最近在做交易数据的统计分析时,多次用到数据行之间的一些操作,对于其中的细节,简单做了个笔记。
1. shfit函数
shift
函数在策略回测代码中经常出现,计算交易信号,持仓信号以及资金曲线时都有涉及。
这个函数的主要作用是将某列的值上下移动。
默认情况下,shift
函数是向下移动一行,
移动后,新数据列的第一行数据用NaN
(空值)填充,原始数据列的最后一行丢弃。
import pandas as pd
df = pd.DataFrame({
"A": [1, 2, 3, 4, 5, 6],
"B": [2, 3, 4, 2, 4, 5],
"C": [5, 6, 7, 1, 3, 4],
}, dtype=float)
# 默认 shift()
df["C-shift()"] = df["C"].shift()
print(df)
也可以在shift
函数中指定移动的行数,比如下面的代码下移3行。
df["C-shift(3)"] = df["C"].shift(3)
print(df)
指定的行数为负值时,表示向上移动,此时,下面的部分用NaN
填充。
df["C-shift(-3)"] = df["C"].shift(-3)
print(df)
shift
之后一般会在 首部/尾部 产生NaN
空值,根据情况看是否需要进一步处理。
2. 不同行数的列赋值
shift
函数还是比较好理解的,
下面这个操作比shift
稍微复杂一些。
为了简化,创建两个测试数据:
df1 = pd.DataFrame({
"A": [1, 2, 3, 4, 5, 6],
"B": [2, 3, 4, 2, 4, 5],
"C": [5, 6, 7, 1, 3, 4],
})
df2 = pd.DataFrame({
"D": [110, 100],
})
print(df1, df2)
把df2
只有2行,df1
有6行,此时,把df2
的D列赋值给df1
时,pandas
会自动比较df1
和df2
的index
(索引,也就是上图中红色框内部分),只赋值具有相同index
的行。
df1["D"] = df2["D"]
print(df1)
改变df2
的index
,再次赋值看看:
df2 = pd.DataFrame({
"D": [110, 100],
}, index=[4, 7])
df1["D"] = df2["D"]
print(df1)
df2
中index=4
时能和df1
匹配,所以赋值之后,只有index=4
那行赋给了df1
,df2
中index=7
那行没匹配上,就直接丢弃了。
所以,不同行数的两个数据集互相赋值时,比不是从上而下按行赋值,而是根据两个数据的index
来匹配赋值的。
这时,再回头看计算交易信号的代码,temp
虽然经过过滤之后,行数比df
要少,但是过滤之后的每行数据会根据对应的index
准确的赋给df
中相同index
的行。
3. pct_change函数
pct_change
函数用来计算数据百分比变化的。
具体的计算规则是,当前行数据 减去 上一行数据,得出的结果再 除以 上一行数据。
比如:
df = pd.DataFrame({
"A": [1, 2, 3, 4, 5, 6],
"B": [2, 3, 4, 2, 4, 5],
"C": [5, 6, 7, 1, 3, 4],
}, dtype=float)
df["C_percent"] = df["C"].pct_change()
第一行数据因为没有上一行数据,所以是 NaN
,
这和shift
函数一样,处理完之后,别忘了填充第一行的NaN
。
同样,pct_change()
可以传入参数跨越多行。
df["C_percent"] = df["C"].pct_change(3)
向上3行,也就是隔两行计算变化百分比,这里就会产生3个NaN
。
pct_change()
还可以传入负值,传入负值时的计算规则变为:
当前行数据 减去 下一行数据,得出的结果再 除以 下一行数据。
比如:
df["C_percent"] = df["C"].pct_change(-1)
这样,空值NaN
出现最后一行,因为最后一行没有下一行。
4. cumprod函数
cumprod
函数用来计算累积乘积的。
具体的计算规则是,若 当前行 是第一行,则直接用 **当前行数据 **作为 累积乘积结果;
若 当前行 不是第一行,则用 **当前行数据 **乘以 上一行累积乘积结果,得出的结果作为 当前行累积乘积结果。
比如:
df["C_cumprod"] = df["C"].cumprod()
cumprod
函数不能像shift
和pct_change
那样可以传入数值或负数参数,只有默认的逐行累积计算。
5. 总结
在分析交易信息,特别是统计收益和收益率的变化时,上面几个函数能帮助我们极大简化代码,避免写各种复杂的循环。