<jupyter_start><jupyter_text>Подход 1: градиентный бустинг "в лоб"1. Считайте таблицу с признаками из файла features.csv с помощью кода, приведенного выше. Удалите признаки, связанные с итогами матча (они помечены в описании данных как отсутствующие в тестовой выборке).<jupyter_code>columns = ['duration', 'radiant_win', 'tower_status_radiant', 'tower_status_dire', 'barracks_status_radiant', 'barracks_status_dire']
X_train = data.drop(columns = columns, axis=1)<jupyter_output><empty_output><jupyter_text>2. Проверьте выборку на наличие пропусков с помощью функции count(), которая для каждого столбца показывает число заполненных значений. Много ли пропусков в данных? Запишите названия признаков, имеющих пропуски, и попробуйте для любых двух из них дать обоснование, почему их значения могут быть пропущены.<jupyter_code>total = X_train.shape[0]
missing = X_train.count()[X_train.count() < total]
print(missing)<jupyter_output>first_blood_time               77677
first_blood_team               77677
first_blood_player1            77677
first_blood_player2            53243
radiant_bottle_time            81539
radiant_courier_time           96538
radiant_flying_courier_time    69751
radiant_first_ward_time        95394
dire_bottle_time               81087
dire_courier_time              96554
dire_flying_courier_time       71132
dire_first_ward_time           95404
dtype: int64<jupyter_text>Объяснение пропущенных признаков события first blood дано в описании задания:  Если событие "первая кровь" не успело произойти за первые 5 минут, то признаки принимают пропущенное значение.  Также и с остальными признаками если за первые 5 минут не произошло, то пропуск. 3. Замените пропуски на нули с помощью функции fillna(). На самом деле этот способ является предпочтительным для логистической регрессии, поскольку он позволит пропущенному значению не вносить никакого вклада в предсказание. Для деревьев часто лучшим вариантом оказывается замена пропуска на очень большое или очень маленькое значение — в этом случае при построении разбиения вершины можно будет отправить объекты с пропусками в отдельную ветвь дерева. Также есть и другие подходы — например, замена пропуска на среднее значение признака. Мы не требуем этого в задании, но при желании попробуйте разные подходы к обработке пропусков и сравните их между собой.<jupyter_code>X_train = X_train.fillna(0)<jupyter_output><empty_output><jupyter_text>3. Какой столбец содержит целевую переменную? Запишите его название.<jupyter_code>y_train = data['radiant_win']<jupyter_output><empty_output><jupyter_text>4. Забудем, что в выборке есть категориальные признаки, и попробуем обучить градиентный бустинг над деревьями на имеющейся матрице "объекты-признаки". Зафиксируйте генератор разбиений для кросс-валидации по 5 блокам (KFold), не забудьте перемешать при этом выборку (shuffle=True), поскольку данные в таблице отсортированы по времени, и без перемешивания можно столкнуться с нежелательными эффектами при оценивании качества. Оцените качество градиентного бустинга (GradientBoostingClassifier) с помощью данной кросс-валидации, попробуйте при этом разное количество деревьев (как минимум протестируйте следующие значения для количества деревьев: 10, 20, 30). Долго ли настраивались классификаторы? Достигнут ли оптимум на испытанных значениях параметра n_estimators, или же качество, скорее всего, продолжит расти при дальнейшем его увеличении?<jupyter_code>start_time = datetime.datetime.now()
kf = KFold(n_splits=5, shuffle=True)
best_score = 0
best_estimators = 0
for n in [10, 20, 30, 35, 40]:
    clf = GradientBoostingClassifier(n_estimators=n)
    score = np.mean(cross_val_score(clf, X_train, y_train, cv=kf, scoring='roc_auc'))
    print('Time elapsed:', datetime.datetime.now() - start_time, ', Score:', score)
    if(best_score < score):
        best_score = score
        best_estimators = n
print('Time elapsed:', datetime.datetime.now() - start_time, ", Best estimator in [10, 20, 30, 35, 40]:", best_estimators, ", Best score with best estimator:", best_score)<jupyter_output>Time elapsed: 0:00:18.930388 , Score: 0.665238058735573
Time elapsed: 0:00:52.486674 , Score: 0.6826910222891487
Time elapsed: 0:01:44.003091 , Score: 0.6895554285049135
Time elapsed: 0:02:43.463385 , Score: 0.6923482290969678
Time elapsed: 0:03:49.283427 , Score: 0.6935322106977664
Time elapsed: 0:03:49.283427 , Best estimator in [10, 20, 30, 35, 40]: 40 , Best score with best estimator: 0.6935322106977664<jupyter_text>Долго ли настраивались классификаторы?  Относительно долго  Достигнут ли оптимум на испытанных значениях параметра n_estimators, или же качество, скорее всего, продолжит расти при дальнейшем его увеличении?  Как показали тесты при 35, 40 качество улучшается незначительно, но скорость настройки классификатора при этом растет также очень сильно. Из чего следует, что это не оптимальный подход.  Подход 2: логистическая регрессия1. Оцените качество логистической регрессии (sklearn.linear_model.LogisticRegression с L2-регуляризацией) с помощью кросс-валидации по той же схеме, которая использовалась для градиентного бустинга. Подберите при этом лучший параметр регуляризации (C). Какое наилучшее качество у вас получилось? Как оно соотносится с качеством градиентного бустинга? Чем вы можете объяснить эту разницу? Быстрее ли работает логистическая регрессия по сравнению с градиентным бустингом?<jupyter_code>scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)

start_time = datetime.datetime.now()
grid = {'C': np.power(10.0, np.arange(-5, 6))}
clfl = LogisticRegression(solver='lbfgs', penalty='l2')
gs = GridSearchCV(clfl, grid, scoring='roc_auc', cv=kf)
gs.fit(X_train_scaled, y_train)
print('Time elapsed:', datetime.datetime.now() - start_time, gs.best_params_, ', Best score:', gs.best_score_)<jupyter_output>Time elapsed: 0:00:32.491140 {'C': 0.01} , Best score: 0.7163747392752479<jupyter_text>Какое наилучшее качество у вас получилось?  0.7163747392752479  Как оно соотносится с качеством градиентного бустинга?   Логистическая регрессия дает лучше результат для данной задачи, чем градиентный бустинг.  Чем вы можете объяснить эту разницу?  Потому что, в выборке есть разреженные данные, которые плохо подходят для градиентного бустинга.  Быстрее ли работает логистическая регрессия по сравнению с градиентным бустингом?  Да в разы быстрее. 2. Среди признаков в выборке есть категориальные, которые мы использовали как числовые, что вряд ли является хорошей идеей. Категориальных признаков в этой задаче одиннадцать: lobby_type и r1_hero, r2_hero, ..., r5_hero, d1_hero, d2_hero, ..., d5_hero. Уберите их из выборки, и проведите кросс-валидацию для логистической регрессии на новой выборке с подбором лучшего параметра регуляризации. Изменилось ли качество? Чем вы можете это объяснить?<jupyter_code>columns = ['lobby_type', 'r1_hero', 'r2_hero', 'r3_hero', 'r4_hero', 'r5_hero', 'd1_hero', 'd2_hero', 'd3_hero', 'd4_hero', 'd5_hero']
X_train_without_cat = X_train.drop(columns = columns)
X_train_without_cat_scaled = scaler.fit_transform(X_train_without_cat)


start_time = datetime.datetime.now()
gs2 = GridSearchCV(clfl, grid, scoring='roc_auc', cv=kf)
gs2.fit(X_train_without_cat_scaled, y_train)
print('Time elapsed:', datetime.datetime.now() - start_time, gs2.best_params_, ', Best score:', gs2.best_score_)<jupyter_output>Time elapsed: 0:00:29.299666 {'C': 0.01} , Best score: 0.7167155064571546<jupyter_text>Изменилось ли качество?  Качество практически не изменилось.  Чем вы можете это объяснить?  Потому что параметры выбора героя важные признаки, исходя из выбора героев может строиться более выигрышная тактика, либо есть герои, которые обладают способностями особенными и которые помогают выигрывать чаще. 3. На предыдущем шаге мы исключили из выборки признаки rM_hero и dM_hero, которые показывают, какие именно герои играли за каждую команду. Это важные признаки — герои имеют разные характеристики, и некоторые из них выигрывают чаще, чем другие. Выясните из данных, сколько различных идентификаторов героев существует в данной игре (вам может пригодиться фукнция unique или value_counts).<jupyter_code>columns = ['r1_hero', 'r2_hero', 'r3_hero', 'r4_hero', 'r5_hero', 'd1_hero', 'd2_hero', 'd3_hero', 'd4_hero', 'd5_hero']
heroes = X_train[columns]
print(np.unique(heroes).shape[0])<jupyter_output>108<jupyter_text>4. Воспользуемся подходом "мешок слов" для кодирования информации о героях. Пусть всего в игре имеет N различных героев. Сформируем N признаков, при этом i-й будет равен нулю, если i-й герой не участвовал в матче; единице, если i-й герой играл за команду Radiant; минус единице, если i-й герой играл за команду Dire. Ниже вы можете найти код, который выполняет данной преобразование. Добавьте полученные признаки к числовым, которые вы использовали во втором пункте данного этапа.<jupyter_code>#взял максимум, потому что среди выбора героев имеются пропуски
N = max(np.unique(heroes))

X_train_pick = np.zeros((X_train.shape[0], N))

for i, match_id in enumerate(X_train.index):
    for p in range(5):
        X_train_pick[i, X_train.ix[match_id, 'r%d_hero' % (p+1)]-1] = 1
        X_train_pick[i, X_train.ix[match_id, 'd%d_hero' % (p+1)]-1] = -1
        
X_train_bag_words = np.hstack((X_train_without_cat, X_train_pick))
X_train_bag_words_scaled = scaler.fit_transform(X_train_bag_words)<jupyter_output><empty_output><jupyter_text>5. Проведите кросс-валидацию для логистической регрессии на новой выборке с подбором лучшего параметра регуляризации. Какое получилось качество? Улучшилось ли оно? Чем вы можете это объяснить?<jupyter_code>start_time = datetime.datetime.now()
gs3 = GridSearchCV(clfl, grid, scoring='roc_auc', cv=kf)
gs3.fit(X_train_bag_words_scaled, y_train)
print('Time elapsed:', datetime.datetime.now() - start_time, gs3.best_params_, ', Best score:', gs3.best_score_)<jupyter_output>Time elapsed: 0:00:48.668900 {'C': 0.01} , Best score: 0.7517202727075222<jupyter_text>Какое получилось качество?  0.7517202727075222  Улучшилось ли оно? Чем вы можете это объяснить?  Да улучшилось, связано с тем, что привели категориальные признаки к числовым с которыми логистическая регрессия дает результат лучше. 6. Постройте предсказания вероятностей победы команды Radiant для тестовой выборки с помощью лучшей из изученных моделей (лучшей с точки зрения AUC-ROC на кросс-валидации). Убедитесь, что предсказанные вероятности адекватные — находятся на отрезке [0, 1], не совпадают между собой (т.е. что модель не получилась константной).<jupyter_code>data_test = pd.read_csv('features_test.csv', index_col='match_id')
data_test = data_test.fillna(0)

columns = ['lobby_type', 'r1_hero', 'r2_hero', 'r3_hero', 'r4_hero', 'r5_hero', 'd1_hero', 'd2_hero', 'd3_hero', 'd4_hero', 'd5_hero']
X_test = data_test.drop(columns = columns)
heroes_columns = ['r1_hero', 'r2_hero', 'r3_hero', 'r4_hero', 'r5_hero', 'd1_hero', 'd2_hero', 'd3_hero', 'd4_hero', 'd5_hero']
heroes_test = data_test[heroes_columns]

#взял максимум, потому что среди выбора героев могут иметься пропуски
N = max(np.unique(heroes_test))
X_pick_test = np.zeros((data_test.shape[0], N))

for i, match_id in enumerate(data_test.index):
    for p in range(5):
        X_pick_test[i, data_test.ix[match_id, 'r%d_hero' % (p+1)]-1] = 1
        X_pick_test[i, data_test.ix[match_id, 'd%d_hero' % (p+1)]-1] = -1
X_test_bag_words = np.hstack((X_test, X_pick_test))
X_test_bag_words_scaled = scaler.fit_transform(X_test_bag_words)

clf_best = LogisticRegression(solver='lbfgs', penalty='l2', C=0.01)
clf_best.fit(X_train_bag_words_scaled, y_train)
y_pred_test = clf_best.predict_proba(X_test_bag_words_scaled)
print(y_pred_test)<jupyter_output>[[0.17722857 0.82277143]
 [0.24391437 0.75608563]
 [0.81121329 0.18878671]
 ...
 [0.76617082 0.23382918]
 [0.3687855  0.6312145 ]
 [0.57079002 0.42920998]]
{'fraction_non_alphanumeric': 0.0875158696572154, 'fraction_numerical': 0.05213711383834109, 'mean_word_length': 5.958775029446407, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '656647', 'license': 'MIT', 'n_tokens_mistral': 5040, 'n_tokens_neox': 5429, 'n_words': 1186, 'path': 'ML advanced Yandex/Week 7/.ipynb_checkpoints/Exam-checkpoint.ipynb', 'repo_name': 'PupochekRus/Courses', 'size': '11815'}