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

Для этого есть метод, который выбрать на основе процента отсутствующих значений в столбцах функций. Если процент отсутствующего значения меньше 50%, мы можем заменить его средним значением, медианой или модой, относящейся к нашей проблеме. Но если процент отсутствующих значений более значителен, чем 50%, мы можем выбрать любой из алгоритмов машинного обучения, который может хорошо обрабатывать нулевые значения и на основе текущих данных предсказывает отсутствующее значение. Это может быть дорогостоящим в вычислительном отношении, но это отличный подход для заполнения пропущенных значений, в которых отсутствует более 50% значений.

Позвольте мне объяснить, взяв набор данных!

Рассеянный склероз ‹ — это набор данных, который я использовал здесь, нажмите на него, чтобы просмотреть полный набор данных.

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

Я удалил столбцы unnamed: 0, потому что это бесполезно, и давайте быстро посмотрим на количество нулевых значений, присутствующих в столбцах функций.

Как мы видим здесь, функции: Schooling, Initial_Symptom, Intial_EDSS и Final_EDSS имеют нулевые значения. Теперь давайте посчитаем недостающий процент для этих функций.

total_data=len(df)
missing_val=round((df.isnull().sum())/(total_data)*100,2)
missing_df=pd.DataFrame(missing_val[missing_val.values>0],columns=['Missing percent'])
missing_df

Вот как это выглядит, когда приведенный выше код выполняется, и, как мы видим, «Schooling» и «Initial_Symptom» имеют недостающий процент менее 50%. Для «Initial_symptom» мы можем заменить эти значения его режимом. Но для «Обучения» давайте посмотрим на описательную статистику, чтобы понять и проанализировать, какой из них будет лучше заменить их средним или медианным?

df['Schooling'].describe().T
------------------------------
count    272.000000
mean      15.176471
std        4.244175
min        0.000000
25%       12.000000
50%       15.000000
75%       20.000000
max       25.000000
Name: Schooling, dtype: float64

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

Медиана — это мера центральной тенденции, которая не чувствительна к выбросам. Это означает, что менее вероятно, что ваши данные будут искажены. В асимметричном распределении медиана ближе к центру распределения, чем среднее значение. Это означает, что замена отсутствующих значений медианой будет более точной, чем замена их средним значением.

Примечание. Я заменил нулевые значения нулями, причина этого будет объяснена ниже.

df['Schooling']=np.where(df['Schooling']==0,df['Schooling'].median(),df['Schooling'])
df['Initial_Symptom']=np.where(df['Initial_Symptom']==0,df['Initial_Symptom'].mode()[0],df['Initial_Symptom'])

Теперь давайте посмотрим на функции, которые имеют пропущенные значения более 50%.

Для функций «Inital_EDSS» и «Final_EDSS» я собираюсь использовать некоторые алгоритмы машинного обучения для прогнозирования этих отсутствующих значений.

Для этого я использую классификатор AdaBoosting, чтобы предсказать эти значения и заменить их нулевыми значениями. Я расскажу о причине выбора этого алгоритма в конце.

Параллельно, помимо прогнозирования пропущенных значений, я также рассчитываю важность функций для всех функций, которые помогают понять, какая функция больше всего способствовала прогнозированию пропущенных значений для функций «Initial_EDSS» и «Final_EDSS».

Вот шаги по написанию кода для прогнозирования и расчета важности функции.

  1. Определите гиперпараметры для нашего классификатора AdaBoost.
  2. Составьте список столбцов, в которых отсутствуют значения.
  3. Определите количество разбиений, так как мы собираемся выполнить перекрестную проверку.
  4. Сделать объект для перекрестной проверки KFold
  5. Исправьте размер фигуры и оси, чтобы отобразить важность функции
  6. Перебирать столбцы с отсутствующими значениями

— → Извлеките неотсутствующие строки значений в виде набора поездов

— -› Извлеките строки с отсутствующими значениями в качестве тестового набора

— -› Создать переменную x для входных объектов и переменную y для объектов-меток

— -›Повторить разбиение кросс-валидации

  1. Получите наборы поездов и тестов для каждого разделения на основе X и y
  2. Создайте объект для нашего классификатора
  3. Вписываем наши тренировочные данные в классификатор
  4. Прогнозировать классификатор на тестовом наборе и вычислять точность
  5. рассчитать средний балл для каждого сплита и просуммировать их
  6. рассчитать важность функции для каждого разделения и суммировать их
  7. рассчитать прогнозы леса (OOF) для каждого разделения и суммировать их

— -› Заменить прогнозируемые значения OOF отсутствующими значениями

— -› Создайте фрейм данных для хранения важности функций для каждой итерации столбцов с отсутствующими значениями.

—-› Постройте график важности функции

Теперь давайте посмотрим на код

Примечание. Классификатор AdaBoost не может обрабатывать нулевые значения. Во-первых, я заменил эти нулевые значения нулями и извлек строки, не содержащие нулей, в виде набора поездов и строки, содержащие нули, в качестве тестового набора.

params={
    'n_estimators':200,
    'learning_rate':0.1,
    'random_state':42

}

miss_cols=['Initial_EDSS','Final_EDSS']
split=5
cv=KFold(n_splits=split,shuffle=True,random_state=42)
fig,ax=plt.subplots(nrows=2,figsize=(15,10))
for num,col in enumerate(miss_cols):
  train=df[df[col]!=0]
  test=df[df[col]==0].drop(col,axis=1)

  x=train.drop(col,axis=1)
  y=train[col]

  avg_score=0
  feature_importance = [np.zeros(x.shape[1]) for _ in range(split)]
  oof_test = [np.zeros(len(test)) for _ in range(split)]
  print(f'Kfold start')

  for (i,(train_idx,test_idx)) in enumerate(cv.split(x,y)):
    x_train,y_train=x.iloc[train_idx],y.iloc[train_idx]
    x_test,y_test=x.iloc[test_idx],y.iloc[test_idx]

    model=AdaBoostClassifier(DecisionTreeClassifier(max_depth=1),**params)
    model.fit(x_train,y_train)

    pred=model.predict(x_test)
    score=accuracy_score(pred,y_test)

    print(f'Fold accuracy: {score}')

    avg_score+=score/split
    feature_importance[i]+=model.feature_importances_ / split
    oof_test[i]+=model.predict(test)
  print(f'KFold End\n')
  df.loc[df[col]==0,col]=oof_test[-1]
  importance_df=pd.DataFrame({
      'Feature':x.columns,
      'Importance': np.sum(feature_importance,axis=0)
                  })
  importance_df=importance_df.sort_values(by='Importance',ascending=False)
  sns.barplot(data=importance_df,
              x='Importance',
              y='Feature',
              palette='BuPu_r',
              ax=ax[num])
  ax[num].set_title(col)
  ax[0].set_xlabel('')
fig.suptitle('Feature Importance')
-----------------------------------------------------------------
Kfold start
Fold accuracy: 0.84
Fold accuracy: 0.72
Fold accuracy: 0.24
Fold accuracy: 0.16
Fold accuracy: 0.92
KFold End

Kfold start
Fold accuracy: 0.56
Fold accuracy: 0.68
Fold accuracy: 0.88
Fold accuracy: 0.84
Fold accuracy: 0.92
KFold End

Из приведенного выше графика мы можем видеть, что для «Initial_EDSS»: — Final_EDSS, возраст, грудное вскармливание внесли наибольший вклад, а для «Final_EDSS»: — возраст, Initial_EDSS, Initial_Symptom, школьное обучение, грудное вскармливание и инфратенториальная_МРТ являются хорошими предикторами.

Теперь не будет нулевых значений, если мы проверим еще раз.

df.isnull().sum()
-----------------------------
Gender                     0
Age                        0
Schooling                  0
Breastfeeding              0
Varicella                  0
Initial_Symptom            0
Mono_or_Polysymptomatic    0
Oligoclonal_Bands          0
LLSSEP                     0
ULSSEP                     0
VEP                        0
BAEP                       0
Periventricular_MRI        0
Cortical_MRI               0
Infratentorial_MRI         0
Spinal_Cord_MRI            0
Initial_EDSS               0
Final_EDSS                 0
group                      0
dtype: int64

Причина выбора классификатора AdaBoost для заполнения пропущенных значений

Во-первых, Adaboost — это мощный алгоритм машинного обучения, который можно использовать для изучения сложных взаимосвязей между функциями и целевыми переменными. Это делает его хорошим выбором для работы с категориальными данными, которые часто могут иметь сложные отношения.

Во-вторых, Adaboost — это последовательный алгоритм, что означает, что он строит модель, добавляя слабых учеников по одному. Это может помочь справиться с отсутствующими значениями, поскольку позволяет модели учиться на неотсутствующих значениях, а затем использовать эти знания для прогнозирования отсутствующих значений.

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

Однако важно отметить, что Adaboost не всегда лучший выбор для замены нулевых значений. Если данные не очень сложные, то более простой алгоритм, такой как вменение среднего, может быть лучшим выбором. Кроме того, Adaboost может требовать значительных вычислительных ресурсов, поэтому он может быть не лучшим выбором для больших наборов данных.

В конечном счете, лучший способ решить, использовать ли Adaboost для замены нулевых значений, — это поэкспериментировать с различными алгоритмами и посмотреть, какой из них лучше всего подходит для ваших данных.

Я надеюсь, что это поможет вам в некотором роде!

Спасибо!