我需要创建一个评分器,基于三个列表/数组y_true
、y_pred
和sample_value
来计算得分。问题是网格搜索中的评分器会同时计算训练集和验证集的得分,我不知道如何区分它们。我尝试的方法如下(完整示例):
import pandas as pdimport numpy as npfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import GridSearchCVfrom sklearn.metrics import make_scorerdef RF_metric(y_true, y_pred, sample_value): dict_temp = {'y_pred': list(y_pred), 'y_true': list(y_true), 'sample_value': sample_value} df_temp = pd.DataFrame(dict_temp) df_temp['daily_score'] = df_temp[['y_pred', 'y_true', 'sample_value']].apply( lambda row: row[2] if row[0] == row[1] else -row[2], axis=1) df_temp['cum_score'] = df_temp['daily_score'].cumsum() final_score = df_temp['cum_score'].to_list()[-1] return final_scoreparam_dict = {'n_estimators': [100, 150, 200], 'max_depth': [5, 10, 15], }dates = pd.date_range(start='2020-01-01', end='2020-10-01')df = pd.DataFrame({'Date': dates, 'A':np.random.rand(len(dates)), 'B':np.random.rand(len(dates)), 'label':np.random.choice([0,1],len(dates)), 'sample_value':np.random.rand(len(dates))})train_start = pd.to_datetime('2020-01-01')train_end = pd.to_datetime('2020-06-01')val_start = train_endval_end = pd.to_datetime('2020-07-01')df_train = df[(train_start <= df['Date']) & (df['Date'] < train_end)]df_val = df[(val_start <= df['Date']) & (df['Date'] < val_end)]cv_list = [(list(df_train.index), list(df_val.index))]X = df[['A', 'B']].valuesY = df[['label']].values.ravel()clf = RandomForestClassifier()scoring = make_scorer(RF_metric, sample_value = df_val['sample_value'].to_list())gs = GridSearchCV(clf, param_dict, cv=cv_list, scoring=scoring,n_jobs=4)gs.fit(X,Y)
错误是ValueError: arrays must all be same length
回答:
既然升级版本对你有帮助,看来问题出在return_train_score
以前默认是True
,所以你的scoring
确实是传递了训练集,但使用的是验证集的sample_value
。
一个解决方案(例如,如果你仍然想要训练集的得分,或者想切换到k折交叉验证)是不使用便利函数make_scorer
。它只是返回一个签名为(estimator, X, y)
的可调用对象,其中更大的“得分”更好。你可以自己编写这样的可调用对象,这样你就可以访问X
的所有内容(包括sample_value
列!)而不仅仅是估计器的预测结果。