0%

【Python】Pandas之dataframe与series的协方差计算

目的

什么是协方差

协方差(Covariance)在概率论和统计学中用于衡量两个变量的总体误差。而方差是协方差的一种特殊情况,即当两个变量是相同的情况。 协方差表示的是两个变量的总体的误差,这与只表示一个变量误差的方差不同。 如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值,另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值。 如果两个变量的变化趋势相反,即其中一个大于自身的期望值,另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。
\(Cov(X,Y) = E[(X-E(X))(Y-E(Y))]\)

协方差的性质

  1. \(Cov(X,Y)=Cov(Y,X)\)
  2. \(Cov(aX,bY)=abCov(X,Y)\),(a,b是常数)
  3. \(Cov(X_1+X_2,Y)=Cov(X_1,Y)+Cov(X_2,Y)\)
  4. \(Cov(X+a,Y+b)=Cov(X,Y)\)

协方差的计算

可以使用pandas,numpy来计算两个变量的协方差,下面举例分别说明

获取数据

分别取顺丰控股(002352.SZ)沪深300指数(000300.SH)自2018年12月28日至2019年12月31日的数据,这里是为了计算每日涨跌幅,故多取了2018年最后一个交易日的数据

1
2
3
4
5
6
7
8
9
10
import pandas as pd
import numpy as np
import QUANTAXIS as QA
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

stock = QA.QA_fetch_stock_day_adv('002352','2018-12-28','2019-12-31')
index = QA.QA_fetch_index_day_adv('000300','2018-12-28','2019-12-31')
display(stock.data)
display(index.data)
open high low close volume amount
date code
2018-12-28 002352 32.75 33.02 32.50 32.75 55314.0 181019008.0
2019-01-02 002352 32.50 32.71 32.21 32.71 16457.0 53470292.0
2019-01-03 002352 32.63 32.88 32.23 32.73 22575.0 73397384.0
2019-01-04 002352 32.59 32.99 32.11 32.95 36217.0 118465936.0
2019-01-07 002352 32.88 32.91 32.62 32.80 31058.0 101845472.0
... ... ... ... ... ... ... ...
2019-12-25 002352 38.39 38.45 37.73 37.90 70724.0 268576480.0
2019-12-26 002352 38.00 38.38 37.52 37.75 72621.0 274198528.0
2019-12-27 002352 37.75 38.03 37.38 37.51 97280.0 367301696.0
2019-12-30 002352 37.52 37.87 37.00 37.70 106665.0 399623008.0
2019-12-31 002352 37.80 37.85 37.00 37.19 78659.0 292803712.0

245 rows × 6 columns

open close high low vol amount up_count down_count date_stamp volume
date code
2018-12-28 000300 2994.80 3010.65 3024.35 2984.82 710537.0 7.814531e+10 200 81 1.545926e+09 710537.0
2019-01-02 000300 3017.07 2969.54 3018.78 2958.49 686630.0 7.610557e+10 70 216 1.546358e+09 686630.0
2019-01-03 000300 2963.02 2964.84 3000.44 2953.26 708671.0 7.666480e+10 145 142 1.546445e+09 708671.0
2019-01-04 000300 2940.19 3035.87 3036.81 2935.83 1033189.0 1.071410e+11 286 12 1.546531e+09 1033189.0
2019-01-07 000300 3055.15 3054.30 3061.75 3035.91 1011643.0 1.057039e+11 217 73 1.546790e+09 1011643.0
... ... ... ... ... ... ... ... ... ... ... ...
2019-12-25 000300 3988.66 3990.87 4000.56 3976.36 949388.0 1.318965e+11 117 168 1.577203e+09 949388.0
2019-12-26 000300 3993.67 4025.99 4025.99 3993.54 1088606.0 1.408150e+11 236 53 1.577290e+09 1088606.0
2019-12-27 000300 4029.25 4022.03 4066.80 4019.72 1509264.0 1.950904e+11 116 173 1.577376e+09 1509264.0
2019-12-30 000300 4015.52 4081.63 4083.69 4001.50 1559714.0 2.168147e+11 241 53 1.577635e+09 1559714.0
2019-12-31 000300 4077.75 4096.58 4098.14 4069.01 1232642.0 1.731193e+11 189 95 1.577722e+09 1232642.0

245 rows × 10 columns

每日涨跌幅的计算公式为:\(\frac{当日收盘价-前日收盘价}{前日收盘价}\)
可以有两种方式计算

  • 直接计算
1
2
3
returns_stock = (stock.data['close']-stock.data['close'].shift(1))/stock.data['close'].shift(1)
returns_index = (index.data['close']-index.data['close'].shift(1))/index.data['close'].shift(1)
display(returns_stock,returns_index)
date        code  
2018-12-28  002352         NaN
2019-01-02  002352   -0.001221
2019-01-03  002352    0.000611
2019-01-04  002352    0.006722
2019-01-07  002352   -0.004552
                        ...   
2019-12-25  002352   -0.012764
2019-12-26  002352   -0.003958
2019-12-27  002352   -0.006358
2019-12-30  002352    0.005065
2019-12-31  002352   -0.013528
Name: close, Length: 245, dtype: float64



date        code  
2018-12-28  000300         NaN
2019-01-02  000300   -0.013655
2019-01-03  000300   -0.001583
2019-01-04  000300    0.023957
2019-01-07  000300    0.006071
                        ...   
2019-12-25  000300   -0.000523
2019-12-26  000300    0.008800
2019-12-27  000300   -0.000984
2019-12-30  000300    0.014818
2019-12-31  000300    0.003663
Name: close, Length: 245, dtype: float64
  • 使用pct_change()计算
1
2
3
returns_stock = stock.data.close.pct_change()
returns_index = index.data.close.pct_change()
display(returns_stock,returns_index)
date        code  
2018-12-28  002352         NaN
2019-01-02  002352   -0.001221
2019-01-03  002352    0.000611
2019-01-04  002352    0.006722
2019-01-07  002352   -0.004552
                        ...   
2019-12-25  002352   -0.012764
2019-12-26  002352   -0.003958
2019-12-27  002352   -0.006358
2019-12-30  002352    0.005065
2019-12-31  002352   -0.013528
Name: close, Length: 245, dtype: float64



date        code  
2018-12-28  000300         NaN
2019-01-02  000300   -0.013655
2019-01-03  000300   -0.001583
2019-01-04  000300    0.023957
2019-01-07  000300    0.006071
                        ...   
2019-12-25  000300   -0.000523
2019-12-26  000300    0.008800
2019-12-27  000300   -0.000984
2019-12-30  000300    0.014818
2019-12-31  000300    0.003663
Name: close, Length: 245, dtype: float64

使用numpy计算协方差

1
2
covr_matrix = np.cov(returns_stock, returns_index)
print(covr_matrix)
[[nan nan]
 [nan nan]]

使用numpy计算协方差时,不会自动排除NaN的数据,所以需要手动清洗数据。

1
2
covr_matrix = np.cov(returns_stock[1:], returns_index[1:])
print(covr_matrix)
[[3.19837928e-04 9.71284226e-05]
 [9.71284226e-05 1.56416934e-04]]
1
2
covr = covr_matrix[0][1]
print(covr)
9.712842264272448e-05

使用pandas计算协方差

因为取出的数据是多含多重索引的series数据,在使用pandas.series.cov()进行协方差计算时,如果索引不一致,会出现计算结果为nan的情况

1
2
covr = returns_stock.cov(returns_index)
print(covr)
nan

需要先去除多重索引,办法有多种,如使用droplevel(),unstack()等,以下分别举例说明。

  • 使用droplevel()来完成
1
2
covr = returns_stock.droplevel(1).cov(returns_index.droplevel(1))
print(covr)
9.712842264272448e-05
  • 使用unstack()来完成
1
2
3
4
5
df = pd.concat([returns_stock.unstack(), returns_index.unstack()],axis=1)
display(df)
df.cov()
covr = df.cov().loc['002352','000300']
print(covr)
code 002352 000300
date
2018-12-28 NaN NaN
2019-01-02 -0.001221 -0.013655
2019-01-03 0.000611 -0.001583
2019-01-04 0.006722 0.023957
2019-01-07 -0.004552 0.006071
... ... ...
2019-12-25 -0.012764 -0.000523
2019-12-26 -0.003958 0.008800
2019-12-27 -0.006358 -0.000984
2019-12-30 0.005065 0.014818
2019-12-31 -0.013528 0.003663

245 rows × 2 columns

code 002352 000300
code
002352 0.000320 0.000097
000300 0.000097 0.000156
9.71284226427245e-05

使用pandas.dataframe.cov()panadas.series.cov()时,会自动排除NaN的数据,这一点与用numpy来计算是有区别的。