在numpy.cov中处理缺失观察的简洁方法



正如标题所暗示的那样,我想知道在计算 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

最新更新