1.CNE6规模因子
对于规模因子,CNE6中给出了一级因子Size,二级因子Size和Mid cap,以及三级因子LNCAP和MIDCAP。其中一级因子由二级因子合成,二级因子由三级因子合成。对于规模因子,二级和三级因子相同。
一级因子 | 二级因子 | 三级因子 |
---|---|---|
Size | Size | LNCAP |
Mid cap | MIDCAP |
2.三级因子LNCAP的实现
三级因子LNCAP指的是流通市值的对数,所以只需要导入流通市值的数据并取对数即可。
# 流通市值
# 提前准备数据stock_circulated_market_value,每行表示一个日期,每列表示一只股票
import pandas as pd
import numpy as np
stock_circulated_market_value = pd.read_excel("stock_circulated_market_value.xlsx") # 读入excel
stock_circulated_market_value = stock_circulated_market_value.to_numpy() # 转化为numpy数组
# 取对数市值
factor = np.log(stock_circulated_market_value[0, :]) # 取出第一行所有列的流通市值并取对数,即对某一天的流通市值取对数
通过以上代码,可以取出一天的对数流通市值作为因子,要计算所有天的,对整个数组取对数即可
3.三级因子MIDCAP的实现
MIDCAP的计算方式为:首先取 LNCAP 因子暴露的立方,然后以加权回归的方式对 LNCAP 因子正交,最后进行去极值和标准化处理。
3.1 加权
有各种加权方式,这里为了简便直接采用每只股票的对数流通市值占总对数流通市值的比来作为权重。
3.2 正交
在金融学和统计学中,正交化(orthogonalization)是一种数学处理方法,用于去除变量之间的线性相关性。正交化的目的是从一个变量中去除与另一个变量的线性关系,使得处理后的变量在统计意义上独立于原来的变量。
(1)为什么叫“正交”?
“正交”这个术语来源于几何学中的正交性(orthogonality),意思是两个向量在空间中相互垂直,没有线性关系。在统计和回归分析中,两个变量如果是“正交的”,意味着它们的协方差为零,统计上不相关。
(2)正交化的步骤
选择自变量(x)和因变量(y):确定你希望从哪个变量中去除另一个变量的线性关系。
- 进行线性回归:使用自变量对因变量进行线性回归,计算出回归系数。
- 计算残差:用因变量减去回归模型预测的值,得到的残差部分即为正交化后的变量,它与自变量在统计上没有线性关系。
(3)具体例子
以 Size 和 Size_cubed 为例:
- 自变量(x):Size(股票流通市值的对数)
- 因变量(y):Size_cubed(Size 的三次方)
- 线性回归:用 Size 预测 Size_cubed。
- 计算残差:残差部分是 Size_cubed 中去除 Size 的线性影响后的部分,这部分即为 Size_cubed 与 Size 线性无关的部分。
(4)为什么进行正交化
正交化的目的是在多因子模型中去除因子之间的共线性(multicollinearity),确保每个因子独立贡献其解释能力。具体到 Size 和 Size_cubed,正交化的目的是为了确保 Size_cubed 中不包含 Size 的线性信息,从而更清晰地捕捉非线性效应。
3.3 去极值和标准化
(1)去极值
由于极值点的存在可能使结果偏离过大,因此在计算当中通常要进行去极值的操作。
分位数指的是,在由小到大的排序内,有百分之多少的数位于该分位数左侧。例如,25%分位数指的是有25%的数位于该数左侧,即小于等于该数。使用
L
=
(
N
+
1
)
×
p
100
L=(N+1)×\frac{p}{100}
L=(N+1)×100p其中
p
p
p 表示分位数。
在确定位置后,使用插值法计算分位数的值。例如,有数列 [7, 15, 36, 39, 40, 41],计算上四分位数,Q1 的位置为 ( 6 + 1 ) × 0.25 = 1.75 (6+1)× 0.25=1.75 (6+1)×0.25=1.75位于第一个和第二个数字之间,则 Q 1 = 7 + ( 15 − 7 ) × ( 1.75 − 1 ) = 13 Q_1=7+(15-7)×(1.75-1)=13 Q1=7+(15−7)×(1.75−1)=13。表示 7 7 7和 15 15 15之间相差 ( 15 − 7 ) (15-7) (15−7),但是四分位数只大于第一个数字 75 75% 75,所以只能偏离 ( 15 − 7 ) × ( 1.75 − 1 ) (15-7)×(1.75-1) (15−7)×(1.75−1)。
算出框定的分位数后,保留中间的值,去掉两端的极值。
# 对于因子factor,先使用分位数框定范围,再去掉范围之外的数
def winsorization(Series, low_quan, up_quan) # 输入序列,以及上下分位数
factor = pd.Series(factor)
lower = factor.quantile(low_quan) # 得到分位数的值
upper = factor.quantile(up_quan)
factor = np.array(np.clip(factor, lower, upper)) # 将数组框定在分位数范围内
(2)标准化
标准化指的是将数据集转化为均值为0,方差为1的状态,公式为
z
=
x
−
μ
σ
z=\frac{x-μ}{σ}
z=σx−μ,具体原理参见概率论,可以证明
E
(
z
)
=
0
,
D
(
z
)
=
1
E(z) = 0, D(z) = 1
E(z)=0,D(z)=1。
from sklearn.preprocessing import StandardScaler
# StandardScaler.fit_transform可以计算传入数据的均值和标准差并对其进行标准化,需要是二维数组
scaler = StandardScaler()
# 对数据进行标准化处理
factor = scaler.fit_transform(factor)
3.4 代码实现
# 取对数市值
size = np.log(stock_circulated_market_value)
size_total = np.nansum(size) # 对对数流通市值进行求和,忽略缺失值
size_weight = size / size_total # 计算权重
# size因子的三次方
size_cubed = size ** 3
# 对每支股票进行循环,分别将size_cubed对size正交
size_not_nan, size_not_nan_index = deal_nan.get_not_nan(size) # 得到没有缺失值的股票,下同
size_cubed_not_nan = deal_nan.get_not_nan(size_cubed)[0]
size_weight = deal_nan.get_not_nan(size_weight)[0]
# 以size_cubed作为因变量,size作为自变量,size的占比作为权重进行加权回归
model = LinearRegression()
model.fit(size_not_nan.reshape(-1, 1), size_cubed_not_nan.flatten(), sample_weight=size_weight.flatten()) # 传入的数据中,y是1维,x必须是2维,因此需要x.reshape(-1, 1),-1表示自动计算维度,只在1维变2维有效
factor1 = size_cubed_not_nan - model.predict(size_not_nan.reshape(-1, 1))
factor = deal_nan.get_back_num(size, size_not_nan_index, factor1)
# 去极值
factor = winsorization(factor, 0.01, 0.99)
# 标准化
scaler = StandardScaler()
factor = scaler.fit_transform(factor)
对于函数get_not_nan
和函数get_back_num
可以在笔者之前的文章中看到,作用分别是取出数组中没有缺失值的列和将处理后的数值塞回和原数组维度相同的数组,存放在了deal_nan
包中。参见 python中缺失值处理——在因子选股中的应用。
4. 一级因子Size
对于一级因子Size,可以通过对二级因子加权的方式得到。这里为了方便,直接采取等权方式。
Size = 0.5 * LNCAP + 0.5 * MIDCAP
LNCAP
和MIDCAP
分别是刚才写的第一和第二个三级因子,由于规模因子中,二级和三级因子相同,所以直接使用三级因子加权,得到最终的一级因子Size。