最近在做交易數據的統計分析時,多次用到數據行之間的一些操作,對於其中的細節,簡單做了個筆記。
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. 總結
在分析交易信息,特別是統計收益和收益率的變化時,上面幾個函數能幫助我們極大簡化代碼,避免寫各種複雜的循環。