欢迎访问369期货网 369会员登录 注册

当前位置: 主页 > 期货量化

量化交易实战19 - 因子与决策树和随机森林(二)用决策树去评估因子的重要性

时间:2025-10-14 15:27|来源:369期货网|作者:369期货网|点击:
在前面,我们探讨因子和线性模型的时候,把若干个财务因子直接丢给模型,模型特别努力的算了很久,结果收益不尽人意,那是哪里出了问题呢?有没有可能我们选的因子对股价的压根儿不存在影响?

也就是说,有没有可能因子不重要,是一个无用的因子?
那怎么解决呢?
我们可以借助决策树去评估因子的重要性!!!
因此,西西和大家一起去尝试一下。
温馨提示:仅供理解,思路可以用于实盘,但是不可直接用于实盘。


多找点因子
代码展示:
    # 聚宽研究环境专属from jqdata import *# 1) 股票池:沪深300stocks = get_index_stocks('000300.XSHG')# 2) 构造查询q = query(    valuation.code,    valuation.market_cap,    balance.total_current_assets - balance.total_current_liability,                # 净营运资本    balance.total_liability - balance.cash_equivalents,                            # 净债务    balance.total_liability / balance.equities_parent_company_owners,              # 产权比率    (balance.total_assets - balance.total_current_assets) / balance.total_assets,  # 非流动资产比率    balance.equities_parent_company_owners / balance.total_assets,                 # 股东权益比率    indicator.inc_total_revenue_year_on_year,                                      # 营收增长率    valuation.turnover_ratio,                                                      # 换手率    valuation.pe_ratio,                                                            # PE    valuation.pb_ratio,                                                            # PB    valuation.ps_ratio,                                                            # PS    indicator.roa                                                                  # 总资产收益率).filter(valuation.code.in_(stocks))# 3) 取数df = get_fundamentals(q)# 4) 重命名列df.columns = [    'code', '市值', '净营运资本', '净债务', '产权比率',    '非流动资产比率', '股东权益比率', '营收增长率', '换手率',    'PE', 'PB', 'PS', '总资产收益率']# 5) 查看结果df.head()

    运行结果:

    图片

    好像数据不全,反正运行结果是有的,代码没错。

    获取技术因子:

      import pandas as pdimport datetimefrom jqdata import *# ---------- 1. 基础准备 ----------# 用上一段得到的 df,这里先还原一下索引,保留 code 列df = df.reset_index(drop=True)          # 如果 df 的 index 已经乱了,先重置codes = df['code'].dropna().unique().tolist()# ---------- 2. 日期 ----------today = datetime.date.today()trade_two_days_ago = get_trade_days(end_date=today, count=3)[0]   # 倒数第 3 个交易日start_day = get_trade_days(end_date=trade_two_days_ago, count=10)[0]# ---------- 3. 取行情 ----------price = get_price(codes,                  start_date=start_day,                  end_date=trade_two_days_ago,                  frequency='daily',                  fields=['close', 'volume'],                  skip_paused=False,                  fq='post')close_df = price['close'].T      # 行:股票,列:日期vol_df   = price['volume'].T# ---------- 4. 计算 10 日技术指标 ----------out = pd.DataFrame(index=codes)out['动量线'] = close_df.iloc[:, -1] - close_df.iloc[:, -10]out['成交量'] = vol_df.mean(axis=1)# 简化 OBVdelta = close_df.diff(axis=1)obv   = ((delta > 0) * vol_df - (delta < 0) * vol_df).fillna(0).cumsum(axis=1)out['累计能量线'] = obv.iloc[:, -1] - obv.iloc[:, -10]out['移动平均']   = close_df.iloc[:, -10:].mean(axis=1)out['指数移动平均'] = close_df.apply(lambda s: s.ewm(span=10, adjust=False).mean().iloc[-1], axis=1)out['乖离率']     = (close_df.iloc[:, -1] - out['移动平均']) / out['移动平均'] * 100out['平均差']     = close_df.iloc[:, -1] - out['移动平均']# ---------- 5. 合并回原始表 ----------df = df.set_index('code').join(out).fillna(0).reset_index()# ---------- 6. 检查结果 ----------df.head()

      运行结果:

      图片

      前面还有哈,截图截不全。

      这个结果包含了财务因子和技术因子,技术因子选择的是两天前的数据,用来预测一天前股票价格变动带来的收益,并找到相对重要的因子。

      设定目标并训练模型

      现在我们就来给模型设定目标。我们的思路是:先找到股票的历史收盘价(如50天前)再用前一天的收盘价除以50天前的收盘价并减1,计算出这50天来股票的收益:然后我们找到那些收益水平大于平均水平的股票,标记为1,其余标记为0,作为模型的分类标签。输入代码如下:

        import numpy as npimport datetimefrom jqdata import *# 1) 交易日today = datetime.date.today()trade_1   = get_trade_days(end_date=today, count=2)[0]   # 前 1 个交易日trade_50  = get_trade_days(end_date=today, count=51)[0]  # 前 50 个交易日# 2) 股票列表codes = df['code'].unique().tolist()# 3) 取收盘价:直接返回以股票代码为索引的 Seriesclose1 = get_price(codes,                   end_date=trade_1,                   count=1,                   frequency='daily',                   fq='pre',                   panel=False).set_index('code')['close']close2 = get_price(codes,                   end_date=trade_50,                   count=1,                   frequency='daily',                   fq='pre',                   panel=False).set_index('code')['close']# 4) 对齐到原表df = df.set_index('code')          # 临时把 code 设为索引,便于 joindf['close1'] = close1df['close2'] = close2df['return'] = df['close1'] / df['close2'] - 1df['signal'] = np.where(df['return'] > df['return'].mean(), 1, 0)df = df.reset_index()              # 如需保留 code 列,再 reset_index# 5) 检查结果df.head()

        运行结果:

        图片

        图比较多,其他的可以自己运行看一下,需要关注的是close1、ciose2、retum和signal这几列。它们分别对应的是1天前的收盘价、50 天前的收价、该时间段内的收益,以及收益是否大于平均值。signal这一列是训练模型用的分类标签现在数据集已经准备就绪,我们可以开始训练模型了。输入代码如下:

          # 1. 导入工具from sklearn.model_selection import train_test_splitfrom sklearn.tree import DecisionTreeClassifier# 2. 构造特征 X 和标签 y# 假设 df 中股票代码列叫 'code',其余因子列都保留X = df.drop(['code', 'close1', 'close2', 'return', 'signal'], axis=1)y = df['signal']# 3. 训练 / 验证集划分(80% 训练,20% 验证)X_train, X_test, y_train, y_test = train_test_split(    X, y, test_size=0.2, random_state=1000)# 4. 建模并训练clf = DecisionTreeClassifier(random_state=1000)clf.fit(X_train, y_train)# 5. 评估print('训练集准确率:', clf.score(X_train, y_train))print('验证集准确率:', clf.score(X_test, y_test))

          运行结果:

            训练集准确率: 1.0 验证集准确率: 0.55

            这个验证集的准确率还是一如既往的难看,看来最近两个月的牛市把模型都给搞不会了,硬着头皮写下去吧,行情差失真,市值一直被低估;行情好失真,市值一直被高估,真的没法了。


            哪些因子最重要

            决策树的属性--featureimportances_存储的是模型判断的样本特征的重要程度。为了便于查看,我们把这个属性存储到一个列表中。

            输入代码如下:


              import pandas as pd# 1. 创建权重表factor_weight = pd.DataFrame({    'features': X.columns,    'importance': clf.feature_importances_})# 2. 按重要性降序排列factor_weight = factor_weight.sort_values(    by='importance',    ascending=False).reset_index(drop=True)# 3. 查看结果factor_weight

              运行结果:

              图片

              【结果分析】从表中可以看到,在所有的因子当中,乖离率这个因子的重要性竟然是最高的,达到了0.23左右,超过了其他因子。

              乖离率(BIAS)是衡量股价偏离其移动平均线幅度的技术指标,用来判断价格是否“超买”或“超卖”。
              公式:
                BIAS = (当前收盘价 − N 日移动平均价) ÷ N 日移动平均价 × 100%

              • 正乖离:股价高于均线,数值越大,短线超买越严重,可能回落。

              • 负乖离:股价低于均线,数值越小,短线超卖越明显,可能反弹。

              在决策树结果中,乖离率权重最高(0.237),说明模型认为它对“未来 50 日收益是否超越平均”最具解释力。

              排名第二的是市销率,

              • 市销率(PS) = 股票市值 ÷ 最近四个季度营业收入

              • 也可以写成 股价 ÷ 每股销售额

              • 常用于衡量公司估值水平,尤其适用于尚未盈利或利润波动大的成长型企业。

              哎,就,难道是择时的问题?占比前五的基本都跟基本面相关。

              大家思考一下,下次西西将用这个结论去写一个简单的策略尝试一下。



              编辑推荐

              Copyright © 2024-2025 成都宁时科技有限公司 版权所有

              蜀ICP备2022023994号