首页 > 解决方案 > 用 numpy 数组与 DataFrame 屏蔽 pandas DataFrame

问题描述

我想使用 2D 布尔掩码选择性地更改pandas DataFrame. 我注意到我不能(成功)使用numpy数组作为掩码,但我可以使用DataFrame. 然而,更令人沮丧的是,我没有得到这个numpy方法的错误。

例如,

df = pd.DataFrame({'A':[1,2,3,4], 
                   'B':[10,20,30,40]})

mask_np = np.array([[True,True],
                    [False,False],
                    [True,False],
                    [False,True]])

mask_pd = pd.DataFrame(mask_np, columns=['A','B'])

我认为任何一个掩码都会返回掩码所在位置的dfTrue。但相反,df[mask_np]产生

   A   B
0  1  10
0  1  10
2  3  30
3  4  40

这不是我所期望的,我也无法解释。另一方面, df[mask_pd]产生

     A     B
0  1.0  10.0
1  NaN   NaN
2  3.0   NaN
3  NaN  40.0

这是我期望和想要的。

为什么我不能使用numpy面膜?我的互联网搜索结果没有任何相关性。这种差异背后的任何解释将不胜感激!

[pandas版本0.20.3;Python 3.6.3]

标签: pythonpandasnumpydataframe

解决方案


源代码说明了原因。该__getitem__方法[]是语法糖,专门检查通过数据帧的索引:

elif isinstance(key, DataFrame):
    return self._getitem_frame(key)

如果数据帧是布尔类型,则调用的_getitem_frame方法将返回:pd.DataFrame.where

def _getitem_frame(self, key):
    if key.values.size and not is_bool_dtype(key.values):
        raise ValueError('Must pass DataFrame with boolean values only')
    return self.where(key)

NumPy 数组所采用的路线_getitem_array是不同的,而且更加复杂。出于某种原因,该代码旨在以不同方式处理 NumPy / Pandas 输入,而不是确保相同数据类型的一致性。


使用 Pandas 数据框的常规布尔索引通常沿轴应用,即通过行/轴 0df.loc[mask, :]或列/轴 1 通过df.loc[:, mask]

请注意,为了清楚起见,您可以并且可能应该pd.DataFrame.where直接访问:

res = df.where(mask_np)

print(res)

     A     B
0  1.0  10.0
1  NaN   NaN
2  3.0   NaN
3  NaN  40.0

推荐阅读