За время своего существования вакцины успешно спасли бесчисленное количество жизней. Они широко признаны во всем мире как эффективное средство борьбы с потенциально опасными для жизни заболеваниями, такими как оспа и полиомиелит.

В 1985–1996 годах проводилось исследование младенцев, родившихся в деревнях Буркина-Фассо. Целью исследования было определить влияние вакцинации на смертность в возрасте до 2 лет. Исследование показало, что смертность в возрасте до 2 лет была ниже у детей, которые были вакцинированы. Ссылку на оригинальное исследование можно найти здесь.

Теперь мы будем использовать данные, собранные в ходе этого исследования, для обучения модели логистической регрессии, которая может предсказать, подвергается ли вакцинированный ребенок риску смерти или нет. Первым шагом в этом процессе является понимание функций в наборе данных. Вы можете найти набор данных, Jupyter Notebook с соответствующим кодом и файл с справочной информацией и дескрипторами функций здесь.

Теперь, когда мы получили общее представление о том, что делает каждая функция в наборе данных, пришло время прочитать данные в нашем блокноте Jupyter и начать их анализ. Вы можете заметить, что имена столбцов в наборе данных довольно неоднозначны. Итак, переименуем их для ясности и удобства.

data = pd.read_excel("Biostatem_OMS.xls")
data.rename(columns={'ZON':'region', 'NUMIND':'id', 'SEXE':'sex', 'DTP1':'dtp_age', 'RG':'rg_age', 'BCG':'bcg_age', 'AGMER':'mother_age', 'AGEND':'end_age', 'END':'end_status', 'MAT':'delivery', 'DISP':'dispensary', 
'MALNU1':'malnutrition', 'DEATH':'death_cause', 'GRDTP1':'dtp_6months', 'GRBCG':'bcg_6months', 'GRRG':'rg_6months', 'FRESH':'birth_season', 'DIAR':'diarrhea', 'FEVE':'fever', 'COU':'cough'}, inplace=True)
print(data.head())

Следующим шагом является обработка нулевых значений и очистка данных. Мы заметили, что в столбцах Доставка и Плохое питание большое количество пустых значений. Поэтому мы решили отказаться от них. Мы также удаляем столбец id, так как он имеет уникальные значения и не влияет на наш анализ. Столбцы dtp_age, rg_age и bcg_age также содержат большое количество нулевых значений. В этом случае мы можем предположить, что нуль в этих столбцах означает, что ребенку не вводили дозу вакцины, и, таким образом, нет записи о возрасте, в котором она была введена. Мы заполняем эти нулевые значения -1, чтобы указать, что вакцина не вводилась. Столбец death_cause имеет нулевые значения, соответствующие детям, оставшимся в живых в конце исследования. Мы заполняем эти пустые значения 0, чтобы указать, что ребенок жив. Столбец end_status имеет три уникальных значения — 1, 2 и 3 — соответствующие «мертвым», «живым» и «эмигрированным». Для целей нашего анализа и прогнозирования статус «эмигрировал» означает то же, что и оставшийся в живых ребенок. Итак, мы переназначаем записи с end_status 2 или 3 как 0, чтобы указать, что ребенок остался жив.

print(data.isnull().sum())

data.drop(columns=['delivery', 'id', 'malnutrition'], inplace=True)

data['bcg_age'] = data['bcg_age'].fillna(-1)
data['dtp_age'] = data['dtp_age'].fillna(-1)
data['rg_age'] = data['rg_age'].fillna(-1)
data['death_cause'] = data['death_cause'].fillna(0)

data['end_status'] = data['end_status'].replace(2, 0)
data['end_status'] = data['end_status'].replace(3, 0)

Теперь, когда у нас есть чистый набор данных, мы можем проверить корреляцию между различными функциями. Следующие столбцы имеют очень низкую корреляцию с выходной переменной end_status и поэтому будут отброшены:

  • регион
  • секс
  • возраст_матери
  • диспансер
  • сезон рождения
corr_matrix = data.corr()
print(corr_matrix)
sns.heatmap(corr_matrix)

data.drop(columns=['region', 'sex', 'mother_age', 'dispensary', 'birth_season'], inplace=True)

Теперь мы можем выполнить проектирование признаков, чтобы получить признаки с более высокой корреляцией и одновременно уменьшить размерность. Столбцы диарея, лихорадка и кашель показывают небольшую положительную корреляцию с end_status. Мы можем объединить эти столбцы в одну характеристику под названием болезнь. Это поможет уменьшить размерность. Ту же идею можно повторить для dtp_6months, rg_6months и bcg_6months. Мы можем получить более высокие значения корреляции, если закодируем dtp_age, rg_age и bcg_age как двоичные, а не числовые переменные. Поэтому мы заменяем все значения -1 на 0 и на 1 в противном случае.

sickness = np.empty(len(data), dtype='int32')
for i in range(len(data)):
    if data.diarrhea[i] or data.fever[i] or data.cough[i]:
        sickness[i] = 1
    else:
        sickness[i] = 0

vaccine_6months = np.zeros(len(data), dtype='int32')
for i in range(len(data)):
    if data.dtp_6months[i] or data.rg_6months[i] or data.bcg_6months[i]:
        vaccine_6months[i] = 1

data.drop(columns=['diarrhea', 'fever', 'cough', 'dtp_6months', 'rg_6months', 'bcg_6months'], inplace=True)
data['sickness'] = sickness
data['vaccine_6months'] = vaccine_6months

data.dtp_age = np.where(data.dtp_age == -1, 0, 1)
data.rg_age = np.where(data.rg_age == -1, 0, 1)
data.bcg_age = np.where(data.bcg_age == -1, 0, 1)

Наконец пришло время построить нашу классификационную модель. Итак, давайте начнем с разделения наших данных на наборы для обучения и тестирования с соотношением 80:20.

X = data.drop(columns=['end_status'])
y = data['end_status']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20)

Теперь мы можем использовать реализацию логистической регрессии, предлагаемую в библиотеке sklearn, для построения нашей модели и проверки ее точности.

from sklearn.linear_model import LogisticRegression
LRModel = LogisticRegression()
LRModel.fit(X_train, y_train)
results = LRModel.predict(X_test)
score = LRModel.score(X_test, y_test)
print(score)