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

Полный код можно найти на моем гитхабе здесь.

Вот формулировка проблемы:

Цель:
Определить уровень дохода, необходимый для выплаты финансовой помощи семьям в Латинской Америке.

Прежде чем приступить к проекту, я сделал некоторые предварительные выводы:

  • Понимать данные через df.head()
  • Поймите словарь данных — есть 143 столбца, которые относятся к арендному статусу человека, статусу и уровню образования, состоянию, состоянию их дома и его содержимому, например. владеет телевизором и т. д.
  • Понимать типы данных; в основном категоричный
  • Определяем модель: случайный лес

Примечание: я не буду вставлять все выходные данные (обратитесь к моей ссылке на github для полного вывода), а только пройдусь по обработке нулевых значений и моим мыслям о точности модели.

Мой подход:

  1. Понимание данных
    Проверка типов данных (число с плавающей запятой, объекты, целое число), количество значений, пустые значения

2. Проверьте распределение целевой переменной y
Здесь я обнаружил, что данные для переменной y искажены влево. Это может указывать на то, что у меня может быть более высокая оценка точности из-за количества точек данных, которые имеет Target 4 по сравнению с остальными.

import matplotlib.pyplot as plt
import seaborn as sns

sns.set_style('darkgrid')

# Create a countplot to visulaise the balance of the data set based on 'Target' variable.
sns.countplot(x = 'Target', data = train, alpha=0.5).set_title('Target variable count plot')

# Show the plot.
plt.show()

2. Обработка нулевых значений
Как мы поняли из нулевых значений, есть 5 столбцов, в которых у нас есть нулевые значения, требующие обработки.

#Find columns with null values for float columns
null_counts = train.select_dtypes('float64').isnull().sum()
null_counts[null_counts > 0]

#Percentage of total counts
total_counts = len(train)
percentage = null_counts / total_counts *100
percentage

#Null Value Treatments
#(2)   v2a1     (6,860) = Monthly rent payment - 71.8%
#(9)   v18q1    (7,342) = Number of all tablets household owns - 76.8%
#(22)  rez_esc  (7,928) = Years behind in school - 82.9%
#(104) meaneduc     (5) = Average years of education for adults (18+) - 0.05%
#(141) SQBmeaned    (5) = Mean^2 years of education of adults (>=18) in the household - 0.05%

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

Обработка нулевого ежемесячного арендного платежа

Первый столбец, который нужно обработать, ежемесячная арендная плата, мой подход состоял бы в том, чтобы заменить его средними значениями его целевой группы (1–4) из-за огромного расхождения в медианных значениях между каждой целевой группой. Я также рассматривал возможность замены его нулевыми значениями, потому что те, у кого нулевые значения, в основном владели и заплатили за свой дом, являются нулевыми (я не включил код в свой github, так как я не использовал этот метод в конце), но решил против этого, поскольку вместо этого рекомендуется заменить его медианным значением — также в том случае, если нам может понадобиться выполнить некоторую регрессию.

Семья, использующая планшеты, не имеет лечения

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

heads = train.loc[train['parentesco1'] == 1].copy() #only locating the household head 
heads.groupby('v18q')['v18q1'].apply(lambda x: x.isnull().sum()) #while on the household head dataframe, 
                                                                #group by owns a tablet - the one with null values
                                                                #and get only the sum of the null values with tablet

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

Отношение к нулю в школе на несколько лет

Это сложный вопрос, потому что значение этого столбца кажется мне двусмысленным. В моем первоначальном коде, не на github, я обнаружил, что люди, которые в основном нулевые, — это люди в возрасте 17 лет и старше, которых можно считать «не посещающими школу». Но это дискредитирует студентов университета, и, возможно, было бы неправильно заменить его на 0. Вместо этого я решил полностью исключить этот столбец, поскольку есть другие столбцы, которые указывают на уровень образования человека, например. начальная/средняя/колледж и т. д.

Для оставшейся нулевой обработки они составляют 0,05% данных, поэтому я мог бы либо удалить их, либо заменить на нуль, поскольку это совершенно незначительно. Я решил не бросать, так как удаление человека может повлиять на остальную часть домохозяйства.

Запуск модели случайного леса

# Import the train_test_split function.
from sklearn.model_selection import train_test_split

# Split the predictor matrix X and the target vector y into training and testing sets with a 80-20 split ratio.
# Set the random seed to '0' to ensure consistent result.

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

#fitting the training data 
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(criterion = 'gini', max_depth = 8,
                             min_samples_split = 10, random_state = 5)

# 'fit' method trains the model using the provided training data.
clf.fit(X_train, y_train)

#prediction 
y_pred = clf.predict(X_test)
y_pred

from sklearn.metrics import classification_report
print(classification_report(y_pred, y_test))

# Import cross_val_predict function to review predicted values on the test dataset.
from sklearn.model_selection import cross_val_predict

# Print and review th predicted values.
pred = cross_val_predict(clf, X_test, y_test)

# Review the test data using CV = 10.
# Perform Random Forest Classifier model (i.e., clf) on test data using cross-validation approach with 10 folds.

scores_test = cross_val_score(clf, X_test, y_test, cv = 10)

# Print average score of test data.
print(np.mean(scores_test))

# Comment:
#  - 77.5% is the mean performance on test data using all folds (CV=10) cross-validation.

Как видите, наша оценка точности составляет 82%, а наша оценка перекрестной проверки — 77,5%, что может указывать на небольшое переоснащение данных. Сначала я запустил GridSearchCV, и максимальная глубина вывода составила 14. Однако это привело к оценке точности 95%, но с оценкой перекрестной проверки 85%, что составляет разительную разницу в 10%, что указывает на то, что модель была переоснащена. Поэтому я уменьшил максимальную глубину до 8 или 10 и обнаружил, что максимальная глубина 8 является самым низким показателем переобучения.

Моя интерпретация результатов:

  • Есть больше возможностей для улучшения Задачи 1 и Задачи 3, и усилия должны быть сосредоточены на этом (вероятно, данных недостаточно для того, чтобы делать точные прогнозы, поскольку данные смещены прямо в сторону Задачи 4)
  • Показатели отзыва для каждой цели высоки, что указывает на то, что люди точно классифицируются в соответствии с их целью (истинно отрицательные результаты, как правило, точны).
  • Однако показатели точности ниже, особенно для целей 1 и 3, что указывает на то, что модель недостаточно конкретна в своих прогнозах для целей 1 и 3 и вместо этого предсказывает слишком много нецелевых случаев 1 и 3 в качестве целей 1 и 3.
  • В целом показатель точности относительно высок и составляет 82%, однако эта модель не подходит для прогнозирования людей с Целями 1 и 3, и, следовательно, этим целям может быть предоставлена ​​неточная финансовая помощь.
  • Случайный лес является подходящей моделью для использования в этом бизнес-кейсе, но из-за точности результатов он может неточно выдавать соответствующие вспомогательные средства для 1 и 3.

Последние мысли

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