正如标题所暗示的那样,我想知道在计算 Python/pandas 中的协方差矩阵时是否有一种简洁的方法来处理丢失的数据。考虑数据帧
df = pd.DataFrame({'var1': [1,2,3, np.nan, 5, np.nan], 'var2': [1, 1.5, 2, 2.5, np.nan, 3.5]})
如果我们简单地做np.cov(df.var1.dropna(), df.var2.dropna())
,我们会得到一个错误,因为第一列和第二列中缺少的值数量不同。我发现解决此问题的两种方法是:
rowind = list(set(df.var1.dropna().index).intersection(set(df.var2.dropna().index)))
和
rowind = (~np.isnan(data.resid1f1)) & (~np.isnan(data.resid1f2))
然后计算np.cov(df.loc[rowind, "var1"], df.loc[rowind, "var2"])
.但是,我想知道是否有一些内置功能可以以不那么冗长的方式执行此操作。
调用dropna
然后cov
:
In [110]:
df.dropna().cov()
Out[110]:
var1 var2
var1 1.0 0.50
var2 0.5 0.25
这匹配np.cov
:
In [111]:
rowind = (~np.isnan(df.var1)) & (~np.isnan(df.var2))
np.cov(df.loc[rowind, "var1"], df.loc[rowind, "var2"])
Out[111]:
array([[ 1. , 0.5 ],
[ 0.5 , 0.25]])
这与给出不同结果的df.cov
不同,文档指出它排除了丢失的数据,但不清楚它如何处理它们:
In [107]:
df.cov()
Out[107]:
var1 var2
var1 2.916667 0.500
var2 0.500000 0.925
好的,只是弄清楚了上面在做什么:
In [115]:
df.fillna(df.mean(axis=1)).cov()
Out[115]:
var1 var2
var1 2.916667 0.500
var2 0.500000 0.925
我做了下面的要点来重现和举例说明这种差异,我希望这在这次讨论中有用:
# =============================================================================
# NUMPY VS PANDAS: DIFFERENT ESTIMATION OF COVARIANCE IN PRESENCE OF NAN VALUES
# =============================================================================
# data with nan values
M = np.random.randn(10,2)
# add missing values
M[0,0] = np.nan
M[1,1] = np.nan
# Covariance matrix calculations
# ==============================
# numpy
# -----
masked_arr = np.ma.array(M, mask=np.isnan(M))
cov_numpy = np.ma.cov(masked_arr, rowvar=0, allow_masked=True, ddof=1).data
# pandas
# ------
cov_pandas = pd.DataFrame(M).cov(min_periods=0).values
下面显示了计算的示例:
# Homemade covariance coefficient calculation
# (what each of them is actually doing)
# =============================================
# select elements to estimate the element 0,1 in the covariance matrix
x = M[:,0]
y = M[:,1]
mask_x = ~np.isnan(x)
mask_y = ~np.isnan(y)
mask_common = mask_x & mask_y
# numpy
# -----
xn = x-np.mean(x[mask_x])
yn = y-np.mean(y[mask_y])
cov_np = sum(a*b for a,b,c in zip(xn,yn, mask_common) if c)/(np.sum(mask_common)-1)
# pandas
# ------
xn = x-np.mean(x[mask_common])
yn = y-np.mean(y[mask_common])
cov_pd = sum(a*b for a,b,c in zip(xn,yn, mask_common) if c)/(np.sum(mask_common)-1)
请注意,主要区别在于如何将均值函数应用于每个变量。
来源: https://gist.github.com/mmngreco/bd86213d9ccd8ddc61683a853ce2fced
编辑:我在熊猫中添加了一个问题:
https://github.com/pandas-dev/pandas/issues/16837