Предотвращение утечки данных с помощью синхронизированных данных и перекрестной проверки
Я использую набор данных Коби Брайанта.
Я хочу предсказать shot_made_flag
с участием KnnRegressor
,
Я пытаюсь избежать утечки данных, группируя данные по season
, year
, а также month
,season
уже существующий столбец и year
а также month
столбцы, которые я добавил, вот так:
kobe_data_encoded['year'] = kobe_data_encoded['game_date'].apply(lambda x: int(re.compile('(\d{4})').findall(x)[0]))
kobe_data_encoded['month'] = kobe_data_encoded['game_date'].apply(lambda x: int(re.compile('-(\d+)-').findall(x)[0]))
Вот полный код моего кода предварительной обработки функций:
import re
# drop unnecesarry columns
kobe_data_encoded = kobe_data.drop(columns=['game_event_id', 'game_id', 'lat', 'lon', 'team_id', 'team_name', 'matchup', 'shot_id'])
# use HotEncoding for action_type, combined_shot_type, shot_zone_area, shot_zone_basic, opponent
kobe_data_encoded = pd.get_dummies(kobe_data_encoded, prefix_sep="_", columns=['action_type'])
kobe_data_encoded = pd.get_dummies(kobe_data_encoded, prefix_sep="_", columns=['combined_shot_type'])
kobe_data_encoded = pd.get_dummies(kobe_data_encoded, prefix_sep="_", columns=['shot_zone_area'])
kobe_data_encoded = pd.get_dummies(kobe_data_encoded, prefix_sep="_", columns=['shot_zone_basic'])
kobe_data_encoded = pd.get_dummies(kobe_data_encoded, prefix_sep="_", columns=['opponent'])
# covert season to years
kobe_data_encoded['season'] = kobe_data_encoded['season'].apply(lambda x: int(re.compile('(\d+)-').findall(x)[0]))
# covert shot_type to numeric representation
kobe_data_encoded['shot_type'] = kobe_data_encoded['shot_type'].apply(lambda x: int(re.compile('(\d)PT').findall(x)[0]))
# add year and month using game_date
kobe_data_encoded['year'] = kobe_data_encoded['game_date'].apply(lambda x: int(re.compile('(\d{4})').findall(x)[0]))
kobe_data_encoded['month'] = kobe_data_encoded['game_date'].apply(lambda x: int(re.compile('-(\d+)-').findall(x)[0]))
kobe_data_encoded = kobe_data_encoded.drop(columns=['game_date'])
# covert shot_type to numeric representation
kobe_data_encoded.loc[kobe_data_encoded['shot_zone_range'] == 'Back Court Shot', 'shot_zone_range'] = 4
kobe_data_encoded.loc[kobe_data_encoded['shot_zone_range'] == '24+ ft.', 'shot_zone_range'] = 3
kobe_data_encoded.loc[kobe_data_encoded['shot_zone_range'] == '16-24 ft.', 'shot_zone_range'] = 2
kobe_data_encoded.loc[kobe_data_encoded['shot_zone_range'] == '8-16 ft.', 'shot_zone_range'] = 1
kobe_data_encoded.loc[kobe_data_encoded['shot_zone_range'] == 'Less Than 8 ft.', 'shot_zone_range'] = 0
# transform game_date to date time object
# kobe_data_encoded['game_date'] = pd.to_numeric(kobe_data_encoded['game_date'].str.replace('-',''))
kobe_data_encoded.head()
Затем я масштабировал данные, используя MinMaxScaler
:
# scaling
min_max_scaler = preprocessing.MinMaxScaler()
scaled_features_df = kobe_data_encoded.copy()
column_names = ['loc_x', 'loc_y', 'minutes_remaining', 'period',
'seconds_remaining', 'shot_distance', 'shot_type', 'shot_zone_range']
scaled_features = min_max_scaler.fit_transform(scaled_features_df[column_names])
scaled_features_df[column_names] = scaled_features
И сгруппированы по season
, year
, а также month
как указано выше:
seasons_date = scaled_features_df.groupby(['season', 'year', 'month'])
Мне было поручено использовать KFold
найти лучший K, используя roc_auc
Гол.
Вот моя реализация:
neighbors = [x for x in range(1,50) if x % 2 != 0]
cv_scores = []
for k in neighbors:
print('k: ', k)
knn = KNeighborsClassifier(n_neighbors=k, n_jobs=-1)
scores = []
accumelated_X = pd.DataFrame()
accumelated_y = pd.Series()
for group_name, group in seasons_date:
print(group_name)
group = group.drop(columns=['season', 'year', 'month'])
not_classified_df = group[group['shot_made_flag'].isnull()]
classified_df = group[group['shot_made_flag'].notnull()]
X = classified_df.drop(columns=['shot_made_flag'])
y = classified_df['shot_made_flag']
accumelated_X = pd.concat([accumelated_X, X])
accumelated_y = pd.concat([accumelated_y, y])
cv = StratifiedKFold(n_splits=10, shuffle=True)
scores.append(cross_val_score(knn, accumelated_X, accumelated_y, cv=cv, scoring='roc_auc'))
cv_scores.append(scores.mean())
#graphical view
#misclassification error
MSE = [1-x for x in cv_scores]
#optimal K
optimal_k_index = MSE.index(min(MSE))
optimal_k = neighbors[optimal_k_index]
print(optimal_k)
# plot misclassification error vs k
plt.plot(neighbors, MSE)
plt.xlabel('Number of Neighbors K')
plt.ylabel('Misclassification Error')
plt.show()
Я не уверен, правильно ли я справляюсь с утечкой данных в этой ситуации, потому что, если я накапливаю данные предыдущего сезона, а затем передаю их cross_val_score
Я мог бы точно так же хорошо справиться с утечкой данных, поскольку cv может разбивать данные таким образом, чтобы проверялись данные нового сезона и данные предыдущего сезона, я прав? Если это так, я хотел бы знать, как подойти к этой ситуации, где я хотел бы использовать K-Fold
найти лучшее k
используя эти синхронизированные данные без утечки данных. Это даже разумно использовать K-Fold
разделить данные, а не разделить по дате игры, чтобы избежать утечки данных?
1 ответ
Короче говоря, поскольку вы хотите что-то сделать со звуками, подобными временным сериям, вы не можете использовать стандартную перекрестную проверку в k-кратном размере.
Вы бы использовали некоторые данные из будущего, чтобы предсказать прошлое, что запрещено.
Хороший подход вы можете найти здесь: https://stats.stackexchange.com/questions/14099/using-k-fold-cross-validation-for-time-series-model-selection
fold 1 : training [1], test [2]
fold 2 : training [1 2], test [3]
fold 3 : training [1 2 3], test [4]
fold 4 : training [1 2 3 4], test [5]
fold 5 : training [1 2 3 4 5], test [6]
где числа в хронологическом порядке вашего времени данных