导语:一般的数据预处理中常提及到三类处理:去极值、标准化、中性化。我们将向大家讲述这常见的 三种数据处理操作。 一、去极值 在分析上市公司当季净利润同比增长率数据时,我们往往会被其中一些公司的数据干扰,如图中江 西长运,2017 三季度净利润同比增长率高达32836.04% !而实际上大部分公司的当季净利润同比增长 率的数值都远远达到这个值的百分之一。那么数据去极值操作就显得尤为关键,可以剔除掉数据干扰项, 提高数据结论的准确性。 一般去极值的处理方法就是确定该项指标的上下限,然后超过或者低于限值的数据统统即为限值。 其中上下限数值判断标准有三种,分别为 MAD 、 3σ、百分位法。 以沪深300 成分股的pe 值为原始数据,向大家阐述MAD 、 3σ、百分位法。 import numpy as np import pandas as pd import math from statsmodels import regression import statsmodels.api as sm import matplotlib.pyplot as plt date='20180125' stock=get_index_stocks('000300.SH',date) q = query( valuation.symbol, valuation.pe_ttm, valuation.current_market_cap ).filter(valuation.symbol.in_(stock)) data = get_fundamentals(q,date=date) data.columns = [['symbol','pe_ratio','market_cap']] data = data.set_index(data.symbol.values) del data['symbol'] data['1/PE'] = 1/data['pe_ratio'] data.head() pe_ratio market_cap 1/PE ----------------------- Page 165----------------------- 000001.SZ 10.59 2.402355e+11 0.094429 000002.SZ 18.61 3.903084e+11 0.053735 000008.SZ 54.53 1.661121e+10 0.018339 000060.SZ 27.51 2.613508e+10 0.036350 000063.SZ -115.27 1.237605e+11 -0.008675 将1/PE 的数据分布,运用绘图函数展示出来: fig = plt.figure(figsize = (20, 8)) ax = data['1/PE'].plot.kde(label = 'Original_PE') ax.legend() 下图是 20180125 的沪深300 指数成分股 1/PE 的数据分布: 1. MAD 法: MAD 又称为绝对值差中位数法,是一种先需计算所有因子与平均值之间的距离总和来检测离群值的 方法,处理的逻辑: 第一步,找出所有因子的中位数 Xmedian 第二步:得到每个因子与中位数的绝对偏差值 Xi−Xmedian 第三步:得到绝对偏差值的中位数 MAD 第四步:确定参数 n ,从而确定合理的范围为 [Xmedian−nMAD,Xmedian nMAD],并针对超出合理 范围的因子值做如下的调整: ----------------------- Page 166----------------------- MAD 法代码实现: def filter_extreme_MAD(series,n): #MAD: 中位数去极值 median = series.quantile(0.5) new_median = ((series - median).abs()).quantile(0.50) max_range = median + n*new_median min_range = median - n*new_median return np.clip(series,min_range,max_range) 对原始数据进行 MAD 处理后的结果: fig = plt.figure(figsize = (20, 8)) ax = data['1/PE'].plot.kde(label = 'Original_PE') ax = filter_extreme_MAD(data['1/PE'],5).plot.kde(label = 'MAD') ax.legend() 2. 3σ 法 3σ 法又称为标准差法。标准差本身可以体现因子的离散程度,是基于因子的平均值 Xmean 而定的。 在离群值处理过程中,可通过用 Xmean±nσ 来衡量因子与平均值的距离。 标准差法处理的逻辑与MAD 法类似: 第一步:计算出因子的平均值与标准差 第二步:确认参数 n (这里选定 n = 3 ) 第三步:确认因子值的合理范围为 [Xmean−nσ,Xmean nσ],并对因子值作如下的调整: ----------------------- Page 167----------------------- 3σ 代码实现: def filter_extreme_3sigma(series,n=3): #3 sigma mean = series.mean() std = series.std() max_range = mean + n*std min_range = mean - n*std return np.clip(series,min_range,max_range) 对原始数据进行 3σ 处理后的结果: fig = plt.figure(figsize = (20, 8)) ax = data['1/PE'].plot.kde(label = 'Original_PE') ax = filter_extreme_3sigma(data['1/PE']).plot.kde(label = '3sigma') ax.legend() 3. 百分位法: 将因子值进行升序的排序,对排位百分位高于 97.5%或排位百分位低于2.5% 的因子值,进行类似于 MAD 、 3σ 的方法进行调整。 百分位法代码实现: def filter_extreme_percentile(series,min = 0.10,max = 0.90): #百分位法 series = series.sort_values() q = series.quantile([min,max]) return np.clip(series,q.iloc[0],q.iloc[1]) fig = plt.figure(figsize = (20, 8)) ax = data['1/PE'].plot.kde(label = 'Original_PE') ax = filter_extreme_percentile(data['1/PE']).plot.kde(label = 'Percentile') ax.legend() ----------------------- Page 168----------------------- 对原始数据进行百分位法处理后的结果: 二、标准化 继续深入的做股票数据分析,假设我们需买入当季净利润同比增长率较高和股息率较高的股票,如 果单纯的将两个指标相加,然后取最终值较大的那些股票,那么会面临一个非常严重的问题:两个指标 的数值意义不同。上市公司达到股息率10%难于净利润同比增长率10%,一般股息率都小于 5%,而净 利润增长率则远远超过 5%的数值,因此简单的相加,然后选股会淡化股息率指标。 那么这种情况下,数据标准化处理可以解决问题。 标准化在统计学中有一系列含义,一般使用 z-score 的方法。处理后的数据从有量纲转化为无量纲, 使得不同的指标能够进行比较和回归。 z-score 的方法介绍 标准化后的数值 = (原始值-单个指标内所有值的均值)/单个指标内所有值的标准差 z-score 的方法代码实现: def standardize_series(series): #原始值法 std = series.std() mean = series.mean() return (series-mean)/std fig = plt.figure(figsize = (20, 8)) new = filter_extreme_3sigma(data['1/PE']) ax = standardize_series(new).plot.kde(label = 'standard_1') ax.legend() 对原始数据进行 Z-score 法处理后的结果: ----------------------- Page 169----------------------- 局部数据展示: standard_2 = standardize_series(new.rank()) standard_2.head() 000001.SZ 1.458269 000002.SZ 0.847295 000008.SZ -1.135490 000060.SZ 0.028820 000063.SZ -1.677298 Name: 1/PE, dtype: float64 三、中性化 继续深入的做股票数据分析,你可能会发现银行股的市盈率特别的低,而互联网行业 的市盈率就特别的高,如果直接用市盈率指标,无论你做了标准化还是去极值,你只会挑选 出银行股,而不可能挑选出互联网股,那么互联网中市盈率最低的股票和银行股中市盈率最 高的股票,应该如何体现它们的真实意义呢? 这种情况下你就需要进行数据中性化处理。 中性化处理概念:为了在用某一因子时能剔除其他因素的影响,使得选出的股票更加分 散。标准化用于多个不同量级指标之间需要互相比较或者数据需要变得集中,而中性化的目 的在于消除因子中的偏差和不需要的影响。 具体方法:根据大部分的研报对于中性化的处理,主要的方法是利用回归得到一个与风 险因子线性无关的因子,即通过建立线性回归,提取残差作为中性化后的新因子。这样处理 后的中性化因子与风险因子之间的相关性严格为零。 ----------------------- Page 170----------------------- 用 python 实现中性化:对原始数据进行 3σ 处理后的结果,进行中性化处理。 数据获取 import numpy as np import pandas as pd import math from statsmodels import regression import statsmodels.api as sm import matplotlib.pyplot as plt date='20180125' stock=get_index_stocks('000300.SH',date) q = query( valuation.symbol, valuation.pe_ttm, valuation.current_market_cap ).filter(valuation.symbol.in_(stock)) data = get_fundamentals(q,date=date) data.columns = [['symbol','pe_ratio','market_cap']] data = data.set_index(data.symbol.values) del data['symbol'] data['1/PE'] = 1/data['pe_ratio'] data.head() pe_ratio market_cap 1/PE 000001.SZ 10.59 2.402355e+11 0.094429 000002.SZ 18.61 3.903084e+11 0.053735 000008.SZ 54.53 1.661121e+10 0.018339 000060.SZ 27.51 2.613508e+10 0.036350 000063.SZ -115.27 1.237605e+11 -0.008675 3σ 处理处理函数 def filter_extreme_3sigma(series,n=3): #3 sigma mean = series.mean() std = series.std() max_range = mean + n*std min_range = mean - n*std return np.clip(series,min_range,max_range) 行业代码列表 SHENWAN_INDUSTRY_MAP = { 'S11' :'农林牧渔', 'S21' :'采掘', 'S22' :'化工', 'S23' :'钢铁', 'S24' :'有色金属', 'S27' :' 电子', 'S28' :'汽车', 'S33' :'家用电器', 'S34' :'食品饮料', 'S35' :'纺织服装', ----------------------- Page 171----------------------- 'S36' :'轻工制造', 'S37' :'医药生物', 'S41' :'公用事业', 'S42' :'交通运输', 'S43' :'房地产', 'S45' :'商业贸易', 'S46' :'休闲服务', 'S48' :'银行', 'S49' :'非银金融', 'S51' :'综合', 'S61' :'建筑材料', 'S62' :'建筑装饰', 'S63' :' 电气设备', 'S64' :'机械设备', 'S65' :' 国防军工', 'S71' :'计算机', 'S72' :'传媒', 'S73' :'通信' } 行业代码标记 def get_industry_exposure(order_book_ids): df = pd.DataFrame(index=SHENWAN_INDUSTRY_MAP.keys(), columns=order_book_ids) for stk in order_book_ids: try: df[stk][get_symbol_industry(stk).s_industryid1] = 1 except: continue return df.fillna(0)#将NaN 赋为 0 中性化函数 # 需要传入单个因子值和总市值 def neutralization(factor,mkt_cap = False, industry = True): y = factor if type(mkt_cap) == pd.Series: LnMktCap = mkt_cap.apply(lambda x:math.log(x)) if industry: #行业、市值 dummy_industry = get_industry_exposure(factor.index) x = pd.concat([LnMktCap,dummy_industry.T],axis = 1) else: #仅市值 x = LnMktCap elif industry: #仅行业 dummy_industry = get_industry_exposure(factor.index) x = dummy_industry.T result = sm.OLS(y.astype(float),x.astype(float)).fit() return result.resid ----------------------- Page 172----------------------- 函数调用 #使用 3sigma 离群值处理法 no_extreme_PE = filter_extreme_3sigma(data['1/PE']) #行业市值中性 new_PE_all = neutralization(no_extreme_PE,data['market_cap']) #市值中性 new_PE_MC = neutralization(no_extreme_PE,data['market_cap'],industry = False) #行业中性 new_PE_In = neutralization(no_extreme_PE) fig = plt.figure(figsize = (20, 8)) ax = no_extreme_PE.plot.kde(label = 'no_extreme_PE') ax = new_PE_all.plot.kde(label = 'new_PE_all') ax = new_PE_MC.plot.kde(label = 'new_PE_MC') ax = new_PE_In.plot.kde(label = 'new_PE_In') ax.legend() 结果输出:能够看出市值和行业中性化后的PE 分布变得更加均匀,其中行业中性化比市值中性化的效果更 好。 ----------------------- Page 173-----------------------
python行业中性_第五章:量化研究专题(第五篇:数据处理专题:去极值、标准化、中性化 )...
最新推荐文章于 2024-02-01 14:20:09 发布