因子合成流程

为了说明量化投资研究服务平台因子合成流程,本文将以等权合成为例,介绍因子合成的流程及使用方法 > 等权合成 – 通过多个因子的排名之和来生成一个新的因子。

1、准备工作

因子合成是指多个因子通过计算或训练的方法生成一个新的因子,新产生的因子可以通过回测产生交易策略,或通过因子分析来研究市场规律。

使用因子合成需要自定义一个继承自Ai_Factor的类,从smartbeta.ai_factor导入。

[ ]:
import pandas as pd
from smartbeta.ai_factor import AiFactor
from data_provider.nestlib.market_info import Frequency
from smartbeta.factor_training_feed import FactorTrainingFeed
from datetime import datetime
from data_provider.datafeed.universe import Universe
from smartbeta.factor_training_feed import (
    FactorTrainingFeed,
    standardization_zscore,
    standardization_mean,
    standardization_std,
    outline_sigma,
    standardization_rank,
)

2、自定义因子标准化方法

自定义标准化方法,该方法将对每一个因子进行调用,将因子转化成为模型所需的形式,如归一化,去极值,zscore等,用户也可以自己定义一个因子标准化方法。

要使用自定义的方法,需要实现一个回调函数并在AiFactor子类中的_x_rules中设置此方法, 见下文说明 这里,我们实现一个简单的归一化方法, 即 value = factor_value / factor_count

回调函数定义如下,需带三个参数,
factor_data: (dataframe)包含所有的因子值
direction: 因子方向, 1为升序,即因子值越小,因子排名越靠前。
params: (dict) 保留项,用于某些自定义的参数。
[5]:
def standardization_normalization(factor_data, direction=1, params={"direction": 1}):
    count = factor_data.groupby("tdate")["factor_value"].count()
    count.name = "count"
    factor_data = factor_data.set_index(["tdate"])
    factor_data["factor_value"] = factor_data["factor_value"] / count
    return factor_data.reset_index()

3、建模

实现自定义合成因子类,x_rules指定因子处理方式,处理后的结果将传送给_build_ai_model进行建模。 该模型对所有传入的因子的排名进行相加,生成新因子

factor_parameters参数说明:

treat_na: 对因子缺失值的处理,默认’drop’。可选’mean’、‘median’、‘drop’、‘keep’、float。’drop’表示drop任何有na的行,’drop14’表示当一行中非na的元素个数小于14时,drop该行.浮点数表示将na填充为该浮点数

subFactors: (list)用于合成新因子的因子集合,每个因子使用dict表示,需包含factor_name, factor_direction, frequency三项。

frequency: 生成的新因子所对应的调仓周期。

生成一个新因子,需要重写其_build_ai_model以及_x_rules方法。如没有标准化需求则可在_x_rules放回空数组。

[6]:
class EqualWeightFactor(AiFactor):
    def __init__(
        self,
        factor_name,
        factorDirection=1,
        tickers="A",
        industry_wise=False,
        factor_parameters={
            "subFactors": [],
            "lagCycleNumber": 0,
            "frequency": "month_end",
            "treat_na": 'drop',
        },
    ):
        # Initialize super class.
        super(EqualWeightFactor, self).__init__(
            factor_name=factor_name,
            factor_direction=factorDirection,
            tickers=tickers,
            industry_wise=industry_wise,
            factor_parameters=factor_parameters,
        )

        self.use_factor_cache = False  # do not cache trainning set

    def _x_rules(self):
        """
            通过自定义x_rules回调,可以实现自定义的因子预处理方式
            返回训练用的标准化规则方式。重写该方法来设置所需的标准化方法。
            这里我们只需将所有的因子,先排名,再归一化。
        """
        return [{"func": standardization_rank}, {"func": standardization_normalization}]

    def _build_ai_model(self, dateTime, training_set):
        """
            返回series组,key为securityId, 值为factor value
        """
        # self.ff._get_training_XY用来获取因子的集合,分为训练集和预测集,在此例中我们不需要使用历史数据进行训练,仅使用预测集,即调仓日当天的因子数据
        # _get_training_XY返回的集合由factor_parameter中的lagCycleNumber参数决定训练集使用多少历史的因子数据
        # [0]第一个元素为training_set的X,所有因子经过转化的结果,也就是当前月份往前1个月+lag_period的因子集合pandas对象
        # [1]第二个元素为trainning_set的Y, 即X对应的结果集,根据设置可以为后一个月的return,也可以是good/bad,根据AIFactor的factor_parameter决定
        # [2]第三个元素为当前月份的因子,用于预测

        # 这里我们因为对因子等权叠加,所以只需要当前月份的因子值排名即可。
        # self.ff对象为一个FactorTrainingFeed对象,详细功能参见FactorTrainingFeed Reference部分
        ret = self.ff._get_training_XY(dateTime, training_set)
        result = ret[2]

        # 最后返回因子排名相加的值,由于在创建对象时,我们使用了standardization_rank的预处理方式,
        # 该处理方式已经将因子值转化成了排名,所以这里只需要简单做Sum运算便可。
        data = result.sum(axis=1).reset_index().set_index("security_code")[0]

        return data

4、合成

使用新的合成因子类计算新因子。

[7]:
subFactors = [
    {
        "factor_name": "MonthlyReturn",
        "factor_direction": 1,
        "frequency": Frequency.MONTH,
    },
    {
        "factor_name": "MonthlyTradeAmount",
        "factor_direction": 1,
        "frequency": Frequency.MONTH,
    },
    {
        "factor_name": "RoeGrowth1",
        "factor_direction": -1,
        "frequency": Frequency.MONTH
    },
]

from_dt = "20170101"
to_dt = "20171023"

ab = EqualWeightFactor(
    factor_name="equal_weight_factors",
    tickers="A",
    factor_parameters={
        "subFactors": subFactors,
        "frequency": "month_end",
        "lagCycleNumber": 0,
        "treat_na": 'drop',
    },
)

ab.del_factor()  # 从数据库清空因子,以便重新录入
%time ab.generate_factor_and_store(from_dt, to_dt, echo=False)
Can not find the factor: equal_weight_factors in sys
2018-08-31 17:22:17,116 - factor_training_feed.py:275 - INFO - 正在计算训练集. lagCycle: 0, frequency: month_end
loading monthlyreturn time cost 2.14s
2018-08-31 17:22:20,093 - factor_training_feed.py:203 - INFO - 是否对当前因子按升序排列: True
loading monthlytradeamount time cost 1.83s
2018-08-31 17:22:23,350 - factor_training_feed.py:203 - INFO - 是否对当前因子按升序排列: True
loading roegrowth1 time cost 1.99s
2018-08-31 17:22:26,678 - factor_training_feed.py:203 - INFO - 是否对当前因子按升序排列: False
2018-08-31 17:22:27,834 - factor_training_feed.py:344 - INFO - 加载行情数据...
2018-08-31 17:22:41,486 - factor_training_feed.py:354 - INFO - 统计收益...
2018-08-31 17:22:41,600 - factor_training_feed.py:403 - INFO - 合并因子至单个dataframe...
CPU times: user 20.1 s, sys: 4.49 s, total: 24.6 s
Wall time: 26.9 s

4.1. 设置行业过滤-非必需

可以通过 set_industry 接口,对行业进行过滤。设置后,因子合成时只会考虑所选行业中的股票。

  • 参数
    • industry: 类型 str, list, 传入单个申万行业分类代码,或分类代码列表
  • 示例
[8]:
ab.set_industry('SW801790')
# 或
ab.set_industry(['SW801790','SW851231'])

5、回测

对生成的因子进行回测, 使用默认设置,全A选股,对冲中证500指数

[9]:
from smartbeta.backtest.factor_backtest import FactorBackTest

uni = Universe()
factors = [{"name": "equal_weight_factors", "direction": 1}]
bt = FactorBackTest(
    "000905.SH", from_dt, to_dt, factors, holding_count=200, freq="month_end"
)  # '000905.SH'

%time bt.run()
bt.analy_plot()
loading dailyreturn time cost 1.76s
加载中: equal_weight_factors
loading equal_weight_factors time cost 0.63s
因子加载完成

100.0%
加载完毕,用时 3.373秒
CPU times: user 5.42 s, sys: 276 ms, total: 5.7 s
Wall time: 7.03 s
_images/因子合成建模_13_6.png

6、AiFactor Reference

[10]:
help(AiFactor)
Help on class AiFactor in module smartbeta.ai_factor:

class AiFactor(smartbeta.factorbase.BaseFactor)
 |  Ai因子基础类,提供基于机器学习合成因子的功能,
 |  用户需要提供自定义的_generate_ai_factor方法,使用训练集提供的内容来进行新因子的训练合成。
 |
 |  Method resolution order:
 |      AiFactor
 |      smartbeta.factorbase.BaseFactor
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, factor_name, factor_direction=1, tickers='A', industry_wise=False, factor_parameters={'subFactors': [], 'frequency': 'month_end', 'lagCycleNumber': 12, 'rolling_frequency': 'default', 'use_ranks_as_x': False, 'use_ranks_as_y': True, 'class_percentile': 10, 'class_remove_neural': True, 'treat_null_factor_as_zero': True})
 |      :param factor_name: 因子名称,要求唯一。
 |      :param factor_direction: 因子值排名的方向,1:升序(值越小排名越前) -1:降序
 |      :param tickers: 股票范围, 支持3种格式: 1. 'A' 2.数组['600000.SH', '600100.SH', ...] 3.指数,表示指数成份['000905.SH']
 |      :param industry_wise: 是否针对行业板块分别训练,将影响_generate_ai_factor中trainning_set的输入。
 |      :param factor_parameters: (dict)用于自定义的合成因子的参数,但必须包含subFactors以及frequency.
 |             subFactors:(list)用于合成新因子的因子集合,每个因子使用dict表示,需包含factor_name, factor_direction, frequency三项。 frequency: 生成的新因子所对应的调仓周期。
 |             lagCycleNumber: (int)窗口周期,subFactors所需的窗口周期数,如果是用于训练模型,则相当于训练集的所需的历史周期数
 |             use_ranks_as_x:(bool)是否将因子值(训练集的X)转化为排名。
 |             use_ranks_as_y:  (bool) 是否将表现(训练集的Y)转化为排名。
 |             class_percentile: (int) 训练集的Y(即表现)的好坏筛选百分比。仅对use_ranks_as_y为True时有效。
 |             class_remove_neural: (int)是否将训练集Y(即表现)的中间位置去除。仅对se_ranks_as_y有效,如class_percentile 为10%时,
 |                                         排名前10%将被标记为good(1), 后10%为bad(-1),中间80%是否去除(0值)。
 |             treat_null_factor_as_zero:是否将因子sub_factors中出现的空值赋为0.
 |
 |  set_industry(self, industry)
 |      设置行业范围
 |
 |      Parameters
 |      ----------
 |      industry: str, list
 |          申万行业id,或行业id列表
 |
 |  set_use_factor_cache(self, use_it)
 |      是否使用缓存,当使用多个因子进行合并的时候,使用缓存将所有用到的标准化后的因子数据进行一次性缓存,即缓存trainning_set对象。
 |      对于_build_ai_model的调参尤其有效,该参数默认开启。
 |      :param use_it: (bool)是否使用缓存
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from smartbeta.factorbase.BaseFactor:
 |
 |  add_factor_definition(self, category=None, create_by='', cn_name='', description='', cal_alg='', storage_method='db', create_time=None)
 |      加入因子定义相关信息
 |      :param category: 因子大类
 |      :param create_by: 创建者
 |      :param description: 描述
 |      :param cal_alg: 计算方法
 |      :param storage_method: 存储方式,目前有实时计算和落入数据库两种
 |      :param create_time: 创建时间,如果为None值,就填充为当前时间
 |      :return:
 |
 |  calculate(self, ticker, from_date, to_date)
 |
 |  clear_factor(self)
 |      对当天的因子进行清洗,主要有:
 |      1. 过滤掉无穷大和无穷小的值
 |      2. 过滤掉nan值
 |      3. 过滤掉未上市的股票(未上市可能已经有财报发布,导致会出现一些值)
 |      4. 过滤掉已经退市的股票
 |      :return: 过滤后的因子值
 |
 |  deal_his_data(self, from_date, to_date)
 |      根据起止时间,处理已有历史数据
 |
 |  del_factor(self, factor_name=None)
 |      将因子数据从数据库中删除
 |
 |  del_factor_definition(self, factor_name=None)
 |      将因子定义从因子定义表中删除
 |
 |  generate_factor_and_store(self, from_date, to_date, save_method=None, echo=False)
 |      计算因子并录入数据库
 |      params:
 |          from_date: (str)起始时间
 |          to_date: (str)结束时间
 |          echo: (bool)是否打印进度条和信息
 |          save_method: 保存方式,当前仅支持覆盖,即此参数不起作用
 |      returns:
 |          (str)执行结果信息
 |
 |  generate_factor_and_store_origin(self, from_date, to_date, save_method=None, echo=False)
 |      计算因子并录入数据库
 |      params:
 |          from_date: (str)起始时间
 |          to_date: (str)结束时间
 |          echo: (bool)是否打印进度条和信息
 |          save_method: 保存方式,
 |              'override'/ None 表示若库中已有这些天的记录,则删除再插入这些天的记录;
 |              'join' 表示更新这些天的记录,对于那天已有股票因子值的记录,则更新
 |              e.g:
 |              原有记录:
 |                      [{'td': 201701011, 'factor_info':
 |                          [
 |                              {'tk': '000001.SZ', 'fv': 0.5},
 |                              {'tk': '000002.SZ', 'fv': 0.9}
 |                          ]
 |                      }]
 |              保存记录:
 |                      [{'td': 201701011, 'factor_info':
 |                          [
 |                              {'tk': '000002.SZ', 'fv': 0.5},
 |                              {'tk': '000003.SZ', 'fv': 0.9}
 |                          ]
 |                      }]
 |              override方式保存,则现有记录:
 |                      [{'td': 201701011, 'factor_info':
 |                          [
 |                              {'tk': '000002.SZ', 'fv': 0.5},
 |                              {'tk': '000003.SZ', 'fv': 0.9}
 |                          ]
 |                      }]
 |              join方式保存,则现有记录:
 |                      [{'td': 201701011, 'factor_info':
 |                          [
 |                              {'tk': '000001.SZ', 'fv': 0.5},
 |                              {'tk': '000002.SZ', 'fv': 0.5},
 |                              {'tk': '000003.SZ', 'fv': 0.9}
 |                          ]
 |                      }]
 |      returns:
 |          (str)执行结果信息
 |
 |  get_factor_df(self)
 |      :return: 获取该因子的所有数据,格式为pd.DataFrame
 |
 |  get_factor_direction(self)
 |      获取因子方向
 |      返回:(1或-1)
 |          1: 因子值升序,因子值越小,得分越高
 |          -1:降序, 因子值越大越好,得分越高
 |
 |  get_factor_name(self)
 |      获取因子唯一名称
 |      返回:(str)因子名
 |
 |  get_factor_param(self)
 |      获取参数
 |      返回:(dict)因子自定义参数
 |
 |  get_factor_value(self, dt)
 |      获取因子值
 |      params:
 |          dt: 'str', 输入需要获取的因子值的日期
 |
 |      return:
 |          (dict)ticker-factor_value键值对
 |
 |  get_first_record_date(self)
 |
 |  get_last_record_date(self)
 |
 |  get_last_record_date_origin(self)
 |
 |  get_trading_days(self)
 |      获取计算因子的交易日历
 |      返回交易日历
 |
 |  has_definition(self)
 |      因子是否有相关的定义
 |      :return:
 |
 |  load(self, begin_day, end_day, ticker=None, factor_name=None, use_cache=False)
 |      从mongo中读取因子数据
 |      :param factor_name: 因子的名称
 |      :param begin_day: 开始日期,int类型YYYYMMDD, 也可以是datetime/str
 |      :param end_day: 结束日期,int类型YYYYMMDD, 也可以是datetime/str
 |      :param ticker: 股票代码。如果没有传入ticker的list,默认取出所有股票的因子值
 |      :param use_cache: 是否使用缓存,default False
 |      :return: 因子数据,pandas.DataFrame类型, 若不存在,返回panddas.DataFrame()
 |
 |  print_test(self, ticker, from_date, to_date)
 |
 |  save(self, save_method='override')
 |      因子数据保存到arctic_factor_data.factor_symbol
 |      Args:
 |          save_method: 保存方式,
 |              'override'/ None 表示若库中已有这些天的记录,则删除再插入这些天的记录;
 |              'join' 表示更新这些天的记录,对于那天已有股票因子值的记录,则更新
 |      Returns:
 |          'ok' if save successfully else raise exception
 |
 |  save_origin(self, save_method='override')
 |      将因子写入mongo数据库,默认数据库collection已经创建好,后续可以优化
 |      Args:
 |          save_method: 保存方式,
 |              'override'/ None 表示若库中已有这些天的记录,则删除再插入这些天的记录;
 |              'join' 表示更新这些天的记录,对于那天已有股票因子值的记录,则更新
 |      Returns:
 |          'ok' if save successfully else raise exception
 |
 |  set_cache_folder(self, folder)
 |
 |  set_factor_name(self, factor_name)
 |
 |  set_factor_value(self, factor_df)
 |      直接set因子值
 |      :param factor_df: 要有三列值:'tdate', 'security_code', 'factor_value'。其中tdate为类似"20170929"类型的string
 |      :return:
 |
 |  set_frequency(self, frequency)
 |
 |  set_should_write_cache(self, write)
 |
 |  set_tickers(self, tickers)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from smartbeta.factorbase.BaseFactor:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

[11]:
help(AiFactor._build_ai_model)
Help on function _build_ai_model in module smartbeta.ai_factor:

_build_ai_model(self, dateTime, training_set)
    通过模型生成因子值,该方法必须被子类重写
    :param dateTime: 需要生成的因子的时间
    :param training_set: 用于训练模型的输入,包含训练所需的训练集和结果集。
    :return 因子Series, index为security_code, 值为因子值
            600100.SH  0.0012
            600101.SH  0.0051
            ...

[12]:
help(AiFactor._x_rules)
Help on function _x_rules in module smartbeta.ai_factor:

_x_rules(self)
    返回训练用的标准化规则方式。重写该方法来设置所需的标准化方法。

7、FactorTrainingFeed Reference

factorTrainingFeed类用于ai_factor内部提供各类因子集合处理的服务。在AiFactor._build_ai_model可以通过self.ff对象获取各类训练集处理的功能。

[13]:
help(FactorTrainingFeed)
Help on class FactorTrainingFeed in module __main__:

class FactorTrainingFeed(builtins.object)
 |  此类用于提供因子的标准化数据处理服务,提供将因子及其表现转化为各类标准化的训练集X和结果集Y的输出。
 |  AiFactor类使用此类作为内部数据集的处理。
 |
 |  Methods defined here:
 |
 |  __init__(self, factor_params, industry=None, use_factor_cache=True)
 |      构造函数
 |      :param factor_params: (list)每个元素为一个dict,包含数据集所要管理的因子信息。
 |                            每个dict需包含factor_name, factor_direction, frequency三项。
 |                            factor_name:(str)因子名称
 |                            factor_direction:(int)因子方向,1位升序,-1为降序
 |                            frequency: (string))对应周期(week_end/month_end/daily)。
 |      :param use_factor_cache: (bool)是否使用缓存因子进行因子读取加速。
 |
 |  calc_training_sets(self, from_date, to_date, lagCycleNumber=12, adjust_frequency='month_end', treat_null_factor_as_zero=True, rolling_frequency='default', include_latest=False, treat_na='drop')
 |      将因子合并成训练所需的X、Y集合
 |      :params tickers: 可以为string'A'表示全A市场,或'000016.SH'表示指数成份
 |      :params lagCycleNumber: 单个ticker应具备的训练集大小,如:使用过去12个月,按月度采样,则该值为12
 |      :params occurred_at: 样本采集频率, [daily/week_start/week_end/month_start/month_end]
 |      :return (x:样本集,y:结果集)
 |
 |  filter_by_tickers(self, tickers, trainning_set_pd=None, inplace=True)
 |      从训练集中筛选股票。
 |      :param tickers: 需要筛选的tickers,可以是指数成分如'000905.SH'或tickers数组['600000.SH', '002100.SZ' ...]
 |      :param trainning_set_pd: (dataframe)需要筛选的trainning_set对象, 如果为none则表示self内部管理的training_set
 |      :param inplace:(bool)是否更新到内部的trainning_set对象
 |
 |  get_training_XY(self, dt)
 |      根据输入日期,拆分训练集,将最近的一个数据样本作为需要预测的数据
 |      :params dt:需要拆分训练集的日期
 |      :returns tuple(train_x, train_y, predict_x, predict_y): 其中predict_y可用于验证,是带未来值
 |
 |  handle_x_standardization_rules(self, factor_data, factor_direction=1)
 |      使用预先设置的x_rules对训练集进行标准化处理。
 |      :param factor_data: (dataframe)因子数据, columns为factor_value、 security_code、tdate。
 |      :param factor_direction: (bool)因子方向,1为升序,-1为降序
 |      :return 处理后的factor_data对象
 |
 |  set_X_process_rules(self, rules)
 |      设置训练集的处理规则
 |      :param rules: (list)每个元素必须为rule方法,系统提供standardization_zscore等标准化方法。
 |
 |  set_rolling_frequency(self, rolling_frequency)
 |      设置训练集的滚动频率,如为日频,则表示生成日级别的训练集数据。
 |      如adjust_frequency为week_end, rolling_frequency为daily则表示按日频滚动训练,
 |      并以周评调仓,结果集以T+5也就是周收益进行计算
 |      :param rolling_frequency: daily, week_end, month_end, default。default表示与adjust_frequency一致
 |
 |  transform_to_percentile(self, training_set, percentile, remove_neutral=True, inplace=True)
 |      将y收益率y排序, 根据百分位数计算优劣并合并至原有Y集合
 |      :params: percentile 百分位数,0~100
 |      :return: 合并后的y集合,包含满足百分位数的值
 |
 |  transform_to_rank(self, training_set, inplace=True)
 |      将y收益率转化为排名
 |      :return: 合并后的y集合,包含收益排名
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

[14]:
help(FactorTrainingFeed.set_X_process_rules)
Help on function set_X_process_rules in module __main__:

set_X_process_rules(self, rules)
    设置训练集的处理规则
    :param rules: (list)每个元素必须为rule方法,系统提供standardization_zscore等标准化方法。

[15]:
help(FactorTrainingFeed.calc_training_sets)
Help on function calc_training_sets in module __main__:

calc_training_sets(self, from_date, to_date, lagCycleNumber=12, adjust_frequency='month_end', treat_null_factor_as_zero=True, rolling_frequency='default', include_latest=False, treat_na='drop')
    将因子合并成训练所需的X、Y集合
    :params tickers: 可以为string'A'表示全A市场,或'000016.SH'表示指数成份
    :params lagCycleNumber: 单个ticker应具备的训练集大小,如:使用过去12个月,按月度采样,则该值为12
    :params occurred_at: 样本采集频率, [daily/week_start/week_end/month_start/month_end]
    :return (x:样本集,y:结果集)

[16]:
help(FactorTrainingFeed.filter_by_tickers)
Help on function filter_by_tickers in module __main__:

filter_by_tickers(self, tickers, trainning_set_pd=None, inplace=True)
    从训练集中筛选股票。
    :param tickers: 需要筛选的tickers,可以是指数成分如'000905.SH'或tickers数组['600000.SH', '002100.SZ' ...]
    :param trainning_set_pd: (dataframe)需要筛选的trainning_set对象, 如果为none则表示self内部管理的training_set
    :param inplace:(bool)是否更新到内部的trainning_set对象

[17]:
help(FactorTrainingFeed.transform_to_percentile)
Help on function transform_to_percentile in module __main__:

transform_to_percentile(self, training_set, percentile, remove_neutral=True, inplace=True)
    将y收益率y排序, 根据百分位数计算优劣并合并至原有Y集合
    :params: percentile 百分位数,0~100
    :return: 合并后的y集合,包含满足百分位数的值

[18]:
help(FactorTrainingFeed.get_training_XY)
Help on function get_training_XY in module __main__:

get_training_XY(self, dt)
    根据输入日期,拆分训练集,将最近的一个数据样本作为需要预测的数据
    :params dt:需要拆分训练集的日期
    :returns tuple(train_x, train_y, predict_x, predict_y): 其中predict_y可用于验证,是带未来值

8、数据集标准化 Reference

数据集的标准化方法用于AI_Factor的_x_rules,用于预处理因子并将其转化成已有的形式,支持用户自定义的处理方式,但是我们也提供以下标准化方法。

[19]:
import smartbeta.factor_training_feed as ftf
[20]:
help(ftf.standardization_mean)
Help on function standardization_mean in module smartbeta.factor_training_feed:

standardization_mean(factor_data, direction=1, params={})
    标准化处理方法-去均值。按factor_data中的tdate分组计算均值。
    return new_factor_value = origin_factor_value - mean
    该方法可在ai_factor._x_rules设定用于标准训练集的处理。

[21]:
help(ftf.standardization_std)
Help on function standardization_std in module smartbeta.factor_training_feed:

standardization_std(factor_data, direction=1, params={})
    标准化处理方法-标准差。按factor_data中的tdate分组计算标准差。
    return new_factor_value = origin_factor_value / std
    该方法可在ai_factor._x_rules设定用于标准训练集的处理。

[22]:
help(ftf.standardization_zscore)
Help on function standardization_zscore in module smartbeta.factor_training_feed:

standardization_zscore(factor_data, direction=1, params={})
    标准化处理方法-标准差。按factor_data中的tdate分组计算zscore。
    return new_factor_value = (origin_factor_value - mean) / std
    该方法可在ai_factor._x_rules设定用于标准训练集的处理。

[23]:
help(ftf.outline_sigma)
Help on function outline_sigma in module smartbeta.factor_training_feed:

outline_sigma(factor_data, direction=1, params={'sigmaThreshold': 3.0})
    标准化处理方法-sigma去极值。将超出阀值的值拉回阀值。
    upThreshold = mean + (sigmaThreshold * sigmaThreshold)
    downThreshold = mean - (sigmaThreshold * sigmaThreshold)
    该方法可在ai_factor._x_rules设定用于标准训练集的处理。

[24]:
help(ftf.standardization_rank_pct)
Help on function standardization_rank_pct in module smartbeta.factor_training_feed:

standardization_rank_pct(factor_data, direction=1, params={})
    标准化处理方法-转户为排名。按factor_data中的tdate分组转化为排名
    该方法可在ai_factor._x_rules设定用于标准训练集的处理。
    : direction: 1为升序(因子值越小,转化为的排名越靠前,其值越小),其余值为降序。

9、附上ada_boost的合成算法

[ ]:
import pandas as pd
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from smartbeta.ai_factor import AiFactor
from smartbeta.factor_training_feed import (
    FactorTrainingFeed,
    standardization_zscore,
    standardization_mean,
    standardization_std,
    outline_sigma,
    standardization_rank,
)


class AdaBoostFactor(AiFactor):
    def __init__(
        self,
        factor_name="adaBoostAlpha",
        factorDirection=1,
        tickers="A",
        industry_wise=False,
        factorParameters={
            "subFactors": [],
            "frequency": "month_end",
            "lagCycleNumber": 12,
            "classifierNumber": 20,
            "dc_depth": 5,
            "use_ranks_as_x": False,
            "use_ranks_as_y": True,
            "class_percentile": 10,
            "class_remove_neural": True,
            "treat_na": 'drop'
        },
    ):
        # Initialize super class.
        super(AdaBoostFactor, self).__init__(
            factor_name=factor_name,
            factor_direction=factorDirection,
            tickers=tickers,
            industry_wise=industry_wise,
            factor_parameters=factorParameters,
        )

    def _x_rules(self):
        """
            返回训练用的标准化规则方式。重写该方法来设置所需的标准化方法。
        """
        if self._factor_param["use_ranks_as_x"] == True:
            return [
                {"func": outline_sigma, "params": {"sigmaThreshold": 3.0}},
                {"func": standardization_zscore},
                {"func": standardization_rank},
            ]
        else:
            return [
                {"func": outline_sigma, "params": {"sigmaThreshold": 3.0}},
                {"func": standardization_zscore},
            ]

    def _build_ai_model(self, dateTime, training_set):
        ret = self.ff._get_training_XY(dateTime, training_set)
        trainX = ret[0]
        trainY = ret[1]
        predictX = ret[2]
        true_predictY = ret[3]

        classifierNumber = self._factor_param["classifierNumber"]
        dt_stump = DecisionTreeClassifier(
            max_depth=self._factor_param["dc_depth"], min_samples_leaf=1
        )
        n_estimators = classifierNumber
        learning_rate = 1
        ada_discrete = AdaBoostClassifier(
            base_estimator=dt_stump,
            learning_rate=learning_rate,
            n_estimators=n_estimators,
            algorithm="SAMME",
        )
        xx = trainX.values
        yy = trainY.values
        tresult = ada_discrete.fit(xx, yy)
        score = ada_discrete.score(xx, yy)

        if predictX.shape[0] == 0:
            return None
        predictY = ada_discrete.predict_proba(predictX.values)

        pX = predictX.reset_index()

        predictionClass = ada_discrete.predict(predictX.values)
        badProba = predictY[:, 0]
        goodProba = predictY[:, 1]
        predictionMatrix = pd.DataFrame(
            {
                "security_code": pX["security_code"],
                "badProba": badProba,
                "goodProba": goodProba,
                "predictionClass": predictionClass,
            }
        )

        data1 = pd.DataFrame(predictionMatrix).sort_values(
            by=["goodProba"], ascending=False
        )
        data = pd.Series(
            dict(zip(list(data1["security_code"]), list(data1["goodProba"])))
        )
        print(
            "datetime: %s, fitting score: %f, training_set: %s, predict_set: %s"
            % (dateTime, score, xx.shape, predictX.shape)
        )
        return data

微信扫码分享本页