大家一直说过拟合,给大家看一下常见的过拟合,
表示就是训练集非常好,而测试集非常差:
这是集成树分类的代码:
import lightgbm as lgb
import numpy as np
from sklearn.metrics import accuracy_score, f1_score
def learning_rate_power(current_round):
base_learning_rate = 0.19000424246380565
min_learning_rate = 0.0001
lr = base_learning_rate * np.power(0.995, current_round)
return max(lr, min_learning_rate)
def train(df_train, df_val, feature_cols, label_col='label'):
lgb_clf = lgb.LGBMClassifier(n_jobs=4,
objective='multiclass',
random_state=100)
opt_params = {'n_estimators': 500,
'boosting_type': 'gbdt',
'objective': 'multiclass',
'num_leaves': 2452,
'min_child_samples': 212,
}
lgb_clf.set_params(**opt_params)
train = df_train[feature_cols] # train = (train - train.mean())/train.std() val = df_val[feature_cols] # val = (val - val.mean())/val.std() fit_params = { # 'early_stopping_rounds': 400, 'eval_metric': 'multiclass', 'eval_set': [(train, df_train[label_col]), (val, df_val[label_col])], # 'verbose': 20, # 'verbosity':-1, 'callbacks': [lgb.reset_parameter(learning_rate=learning_rate_power)]} lgb_clf.fit(train, df_train[label_col], **fit_params) pred_train = lgb_clf.predict(train) print('Training accuracy: ', accuracy_score(df_train[label_col], pred_train)) print('F1 accuracy : ', f1_score(df_val[label_col], lgb_clf.predict(val), average='micro')) print('Validation accuracy: ', accuracy_score(df_val[label_col], lgb_clf.predict(val)))
看下数据表现:
在训练集上,预测的准确率可以达到99%,而测试集上,不足10%。
上面是label为10类的结果,如果改为label预测3类:
那么预测准确性提升至33%,也就是和“瞎猜”差不多。
这样的探索是有意义——我们来一步步优化到可用,找到有用的因子。如果那么容易,那岂不是人人都可以学会?那岂不是很多就失效了?
按惯例,明天统一更新代码,新加入的同学可以看看老的系统工程。
持续给大家写代码的,交付最前沿AI量化技术和策略的星球:
吾日三省吾身
坚持的意义与价值。
坚持100天,你能感觉到自己养成了一个习惯。
后续是基于惯性,或者基于系统,自己想做的事情,并不需要坚持。
所谓“长期主义”,即是如此。
日更公众号443天,收获了一些肯定,认识了不少好朋友。
最初的最初,就是希望把一个兴趣爱好,一个成果跟大家分享。
不要想太多,先做它1000天看看。
当然,目前看,1000天肯定不是终点,还会有新的1000天。
早上读斯多葛学派的书,希望找到内心的平静与安宁。
——把你所拥有的,当成你所所求的。
其实,无论是谁,都已经拥有很多东西。比如年轻,健康的身体。
——蔡磊在《相信》里说的一个细节:“他透过医院的玻璃窗,看到外面流浪汉,拥有矫健的步伐和绵延的生命,不免心里羡慕。”——这位身价过亿,曾经杀伐决断,雷厉风行的高管,身体在不可控的情况下迅速衰退。
功名利禄尘与土。不见武陵豪杰墓,无花无酒锄作田。
如何让人生过得充实而有意义,人生之远大目标应该是什么?
我们下载29个A股主要行业指数。
下面是etf与指数的对应关系:
etfs_indexes = {
'159870.SZ':'000813.CSI',
'512400.SH':'000819.SH',
'515220.SH':'399998.SZ',
'515210.SH': '930606.CSI',
'516950.SH': '930608.CSI',
'562800.SH': '930632.CSI',
'515170.SH': '000815.CSI',
'512690.SH': '399987.SZ',
'159996.SZ': '930697.CSI',
'159865.SZ': '930707.CSI',
'159766.SZ': '930633.CSI',
'515950.SH': '931140.CSI',
'159992.SZ': '931152.CSI',
'159839.SZ': '399441.SZ',
'512170.SH': '399989.SZ',
'159883.SZ': 'h30217.CSI',
'512980.SH': '399971.CSI', '159869.SZ': '930901.CSI', '515050.SH': '931079.CSI', '515000.SH': '931087.CSI', '515880.SH': '931160.CSI', '512480.SH': 'h30184.CSI', '515230.SH': 'h30202.CSI', '512670.SH': '399973.SZ', '515790.SH': '931151.CSI', '159757.SZ': '980032.CNI', '516110.SH': 'h30015.CSI', '512800.SH': '399986.SZ', '512200.SH': '931775.CSI',
使用指数数据的好处在于,可回测周期比较长。
数据我已经帮大家下载好,并完成格式统一化:
准备因子集——由于机器学习需要的因子比较多,不像传统量化,可能就几条规则几个因子,我们直接手写就好了。
from abc import abstractmethod class AlphaBase: # 返回因子集的fields, names @abstractmethod def get_factors(self): pass def get_field_by_name(self, name): fields, names = self.get_factors() for f,n in zip(fields, names): if n == name: return f def get_labels(self): return ["label(shift(close, -1)/close - 1,0)"], ['label'] def get_ic_labels(self): days = [1, 5, 10, 20] fields = ['shift(close, -{})/close - 1'.format(d) for d in days] names = ['return_{}'.format(d) for d in days] return fields, names def get_all_fields_names(self, b_ic=False): fields, names = self.get_factors() if not b_ic: label_fields, label_names = self.get_labels() else: label_fields, label_names = self.get_ic_labels() fields.extend(label_fields) names.extend(label_names) return fields, names class AlphaLit: def get_all_features_names(self): fields,names = self.get_fields_names() label_field, label_name = self.get_label() all_fields = fields.copy() all_fields.append(label_field) all_names = names.copy() all_names.append(label_name) return all_fields, all_names def get_fields_names(self): fields = [] names = [] windows = [2, 5, 10, 20] fields += ['close/shift(close,%d) - 1' % d for d in windows] names += ['roc_%d' % d for d in windows] fields += ['avg(volume,1)/avg(volume,5)'] names += ['avg_amount_1_avg_amount_5'] fields += ['avg(volume,5)/avg(volume,20)'] names += ['avg_amount_5_avg_amount_20'] fields += ['rank(avg(volume,1))/rank(avg(volume,5))'] names += ['rank_avg_amount_1_avg_amount_5'] fields += ['avg(volume,5)/avg(volume,20)'] names += ['rank_avg_amount_5_avg_amount_20'] windows = [2, 5, 10] fields += ['rank(roc_%d)' % d for d in windows] names += ['rank_roc_%d' % d for d in windows] fields += ['rank(roc_2)/rank(roc_5)'] names += ['rank_roc_2_rank_roc_5'] fields += ['rank(roc_5)/rank(roc_10)'] names += ['rank_roc_5_rank_roc_10'] return fields, names def get_label(self): return "shift(close, -10)/close - 1,0)", 'label'
dataloader支持截面函数:
df_all.set_index([df_all.index,'symbol'],inplace=True) for rank_field, rank_name in rank_exprs: #支持截面rank,逻辑加在这里 se = calc_expr(df_all, rank_field) se.name = rank_name df_all[rank_name] = se #df_all['symbol'] = df_all.index. #df_all = df_all.set_index(df_all.index.l) # todo groupby('date').rank(pct=True) df_all = df_all.loc[self.start_date: self.end_date] return df_all
支持截面函数rank(时间序列排序是ts_rank):
def rank(se: pd.Series): ret = se.groupby(level=1).rank(pct=True) return ret
吾日三省吾身
今早悟到几句话,与大家分享。
作为普通人,进攻才是最好的防守。
守正很重要,出奇更重要。
普通人就是没有特别的家世,没有耀眼的资源加持,光着脚或者刚穿上鞋。一味地守正,患得患失,抵御风险能力有限。
守正,注意风险底限,不碰触法律,以及不做带来不可逆风险的决策。建立系统,做时间的朋友。
但还不够多,这个时代,最焦虑的就是中产。
经济形势风吹草动都带来影响。
中考分流,行业裁员,房价波动。。。
刚装上的鞋子怕掉了。
出奇——是反脆弱,是杠铃配置。追热点,高赔率的投资,顶级的人脉圈。
可遇而不可求,但这些才是人生安全感的来源。
——游泳的时候,如何不掉下去?——往前游就是了。
时间会解释一切,因为长期来看,我们都会死,历史长河不过沧海一粟。
——人生没有意义,人生只是一场体验。
有些人小心翼翼一辈子,却没有真正活过。
在守正的基础上,大胆去尝试,去折腾。
生命在于体验,允许一切发生,体验而已。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103551
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!