Полный код моего победившего решения на хакатоне Analytics Vidhya Data Science Hackathon
Хакатон Data Science Hackathon - это решающее поле битвы для начинающих исследователей данных. Цель любого хакатона - позволить своему воображению расширить границы ваших знаний и навыков в этой области.
После двух лет самообучения я решил проверить свои навыки на реальных условиях битвы с другими специалистами по данным. Поэтому я решил принять участие в онлайн-хакатонах. Я решил составить короткий список веб-сайтов и вскоре выбрал Analytics Vidhya, чтобы начать свое путешествие по хакатону.
Мой первоначальный старт был недостаточно хорош. Но мне удалось попасть в топ-50 на одном из первых четырех онлайн-хакатонов.
Одна важная вещь, которую я извлек из этого, заключалась в том, что нельзя участвовать во всех доступных хакатонах.
Важно выбрать конкретный хакатон, на котором вы хотите сосредоточиться, и приложить для этого максимум усилий. Не участвуйте в нескольких хакатонах одновременно, так как каждый хакатон требует определенного времени и усилий.
В августе Analytics Vidhya запустила хакатон Data Supremacy.
Ссылка на хакатон: https://datahack.analyticsvidhya.com/contest/the-data-supremacy/
И, прочитав постановку задачи, я решил поучаствовать и выложиться на полную. Я буду искать решение в разных разделах для облегчения понимания.
Проблема
Хакатон представлял собой задачу бинарной классификации, в которой мы должны предсказать, соответствует ли конкретный студент критериям отбора, основываясь на его историческом прошлом.
Размер набора данных:
Форма поезда: (18359, 14)
Форма теста: (15021, 13)
Цель: двоичная классификация → 0/1
Всего предоставлено функций: 13 функций [столбцы]
Понимание особенностей
Это важный шаг, который почти все пропускают.
Не переходите сразу к написанию кода машинного обучения. Сначала поймите проблему и значение каждой функции. Посмотрите, сможете ли вы найти какую-либо связь с функциями и целевой переменной.
После тщательного изучения всех функций я решил начать с кода.
Библиотеки
Ниже приведены библиотеки, которые я использовал на протяжении всего хакатона.
Три основные библиотеки, которые я использую почти везде.
import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline
Примечание: я включил больше библиотек, чем те, которые я использовал на самом деле, чтобы показать вам все библиотеки, которые я пробовал во время хакатона.
import xgboost as xgb from xgboost.sklearn import XGBClassifier,XGBRegressor import catboost from catboost import CatBoostClassifier from sklearn.preprocessing import LabelEncoder , MinMaxScaler from sklearn.cross_validation import KFold , cross_val_score from sklearn.metrics import accuracy_score , roc_auc_score,confusion_matrix from sklearn.grid_search import GridSearchCV from sklearn import metrics from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier from sklearn.neighbors import KNeighborsRegressor,KNeighborsClassifier from sklearn.svm import SVR from sklearn.linear_model import LogisticRegression,LinearRegression from sklearn.ensemble import ExtraTreesClassifier from sklearn.model_selection import RandomizedSearchCV
Как выглядят данные?
Пришло время прочитать обучающий и тестовый csv.
train_data = pd.read_csv('train_FG6BvLg.csv') test_data = pd.read_csv('test_wovud0B.csv') print("Train Shape : {}\nTest Shape : {}".format(train_data.shape,test_data.shape))
train_data.head()
Пришлось разделить снимок на две картинки, так как на одной картинке его не будет видно.
Столбец Target - это столбец, который будет прогнозироваться в нашем тестовом файле.
Предварительная обработка
Около 75% моего общего времени было посвящено предварительной обработке данных.
Я изучил все столбцы, чтобы подумать обо всех способах их предварительной обработки, и придумал свой окончательный код предварительной обработки.
Примечание. Методы предварительной обработки для каждого столбца различаются и не везде одинаковы.
Во-первых, пора убрать текстовую часть из столбца город.
city_21 → 21
train_city = train_data.city.str.split("_") test_city = test_data.city.str.split("_")
Он будет содержать список с двумя значениями (первое - «город», а второе - присвоенный номер).
i=0 for x in train_city: train_data.loc[i,'city'] = x[1] i=i+1
Вы можете увидеть сделанные изменения. Я сделал то же самое для test_data.
Затем я решил проверить, есть ли в данных отсутствующие значения.
train_data.isnull().sum()
Нам необходимо правильно обработать эти недостающие значения, так как их отбрасывание приведет к потере важной информации.
Прежде чем мы начнем вменение пропущенных значений и их предварительную обработку, мы объединим данные обучения и тестирования. Это поможет внести такие же изменения во весь набор данных.
Перед объединением извлеките целевой столбец из данных обучения, поскольку он отсутствует в данных тестирования.
target = train_data.pop('target') enrollee_id = test_data['enrollee_id'] combined_data = train_data.append(test_data)
Пришло время приступить к дальнейшей предварительной обработке. Я изменил тип данных столбца city со строки на целое число:
combined_data.city= combined_data.city.astype('int')
Я заменил столбец пол на целую категорию:
combined_data.gender.replace({'Male':2,'Female':0,'Other':1},inplace=True)
Я сделал то же самое для еще двух столбцов:
combined_data.enrolled_university.replace({'no_enrollment':1,'Part time course':2,'Full time course':3},inplace=True) combined_data.major_discipline.replace({'No Major':0,'Other':1,'Arts':2,'Humanities':3,'Business Degree':4,'STEM':5},inplace=True)
Столбцы опыт и размер компании содержали строки типа «‹ 10 »,« ›500» и «500–1000». Это не позволило сделать столбец целым.
combined_data.experience.replace({'>20':21,'<1':0},inplace=True)
Чтобы проиллюстрировать, как выглядел размер company_size:
combined_data.company_size.value_counts()
combined_data.company_size.replace({'<10':0,'10/49':1,'50-99':2,'100-500':3,'500-999':4,'1000-4999':5,'5000-9999':6,'10000+':7},inplace=True)
Столбец company_type имел категориальные значения:
combined_data.company_type.value_counts()
Вместо того, чтобы давать случайные числа для замены, я заменил их на возрастающий порядок их аудитории.
combined_data.company_type.replace({'Other':0,'Early Stage Startup':1,'Funded Startup':2,'NGO':3,'Public Sector':4,'Pvt Ltd':5},inplace=True)
Я также сделал несколько замен в оставшихся столбцах.
combined_data.last_new_job.replace({'never':0,'>4':5,'nan':1},inplace=True) combined_data.relevent_experience.replace({'No relevent experience':0,'Has relevent experience':1},inplace=True)
А как насчет пропущенных значений?
Я пробовал различные методы вменения, включая SimpleImputator из библиотеки sklearn. Я даже пробовал вменять им средние значения, но это было не лучше, чем вменять их в 0
combined_data.major_discipline.fillna(0,inplace=True) combined_data.company_type.fillna(0,inplace=True) combined_data.company_size.fillna(0,inplace=True) combined_data.enrolled_university.fillna(0,inplace=True) combined_data['enrolled_university.1'].fillna(0,inplace=True)
Поскольку данные имели разный диапазон значений. Я решил стандартизировать данные, прежде чем перейти к нашей модели.
Я использовал MinMaxScaler, который позволяет мне настраивать минимальное и максимальное значение диапазона.
values = combined_data.values scalar = MinMaxScaler(feature_range=(0,5)) x_scaled = scalar.fit_transform(values) combined_data = pd.DataFrame(x_scaled,columns=combined_data.columns)
Чтобы перейти к нашей модели, нам нужно удалить столбец ID.
combined_data.drop('enrollee_id',axis=1,inplace=True)
Модель
Честно говоря, я перепробовал более 10 алгоритмов, чтобы посмотреть, какой из них работает.
Я начал с RandomForest на CatBoost.
clf = CatBoostClassifier(iterations=200,depth=4,eval_metric='AUC',l2_leaf_reg=9,learning_rate=0.1)
Но XGBoost превзошел все остальные алгоритмы. Поэтому я остановился на нем, чтобы создать функцию модели:
def model_fit(alg, dtrain, target,dtest): xgb_param = alg.get_xgb_params() xgtrain = xgb.DMatrix(dtrain.values, label=target) cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=alg.get_params()['n_estimators'], nfold=5, early_stopping_rounds=50) #alg.fit(dtrain,target,use_best_model=True,eval_set=(x_val,y_val)) alg.fit(dtrain,target) print("Model Report") print("Accuracy is {}".format(alg.score(x_val,y_val))) feat_imp = pd.Series(alg.feature_importances_,dtrain.columns).sort_values(ascending=False) feat_imp.plot(kind='bar', title='Feature Importances') plt.ylabel('Feature Importance Score') y_pred = alg.predict_proba(dtest)[:,1] return y_pred
Приведенный выше фрагмент кода включает подгонку модели и построение графика важности функции в одной функции.
Наконец идет моя модель и ее параметр:
clf = XGBClassifier( learning_rate =0.3, n_estimators=100, max_depth=3, min_child_weight=1000, gamma=0.7, subsample=0.45, colsample_bytree=0.4, objective= 'binary:logistic', nthread=1, scale_pos_weight=1, seed=27, reg_alpha =0.7, random_state=200)
Как вы получили эти параметры?
Я использовал функцию GridSearchCV, которая помогает выбрать лучший параметр из диапазона параметров, которые вы ему вводите.
param_test2 = { 'n_estimators':[150,170,200], 'learning_rate':[0.03,0.05], 'max_depth':[4,10,15,25], 'min_child_weight':[1,2,5,10], 'subsample':[0.5,0.7,1], 'colsample_bylevel':[0.45,0.7,1], 'colsample_bytree':[0.45,0.7,1], 'gamma':[0,0.1,0.5,1] } gsearch2 = GridSearchCV(estimator = XGBClassifier(), param_grid = param_test2, scoring='roc_auc',n_jobs=4,iid=False, cv=5) gsearch2.fit(x_train,y_train) gsearch2.grid_scores_, gsearch2.best_params_, gsearch2.best_score_
GridSearchCV распечатывает лучшие параметры из перестановки переданных гиперпараметров. (Для выставления очков установлено значение «roc_auc»)
После получения соответствующего гиперпараметра пришло время подогнать модель.
y_pred = model_fit(clf,x_train,y_train,test_data)
Как видите, training_hours была самой важной функцией для того, чтобы студент соответствовал критериям отбора, за которым следовали city_development_index и опыт.
Подождите, мы должны оценить нашу модель
Я использовал KFold, чтобы оценить свою модель, чтобы проверить ее эффективность.
k_fold = KFold(len(train_data), n_folds=8, shuffle=True, random_state=0) print(np.mean(cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1)))
KFold предоставит индексы обучения / тестирования для разделения данных на наборы для обучения и тестирования. Он разделит набор данных на k последовательных сверток. Поскольку точность модели и kfold очень похожи, модель работает правильно.
Подчинение
Я загрузил в общей сложности более 20 файлов, чтобы улучшить свой результат и достичь пика.
submission = pd.DataFrame({'enrollee_id': enrollee_id , 'target': y_pred}) submission.to_csv('submission.csv',index=False)
Результат
Вся тяжелая работа окупилась. Я занял 3-е место на хакатоне среди 1000 человек по всему миру. Ниже приведен снимок таблицы лидеров.
Мое имя пользователя: jsiddhesh96
Код можно найти в моем репозитории GitHub: