使用numpy数组与DataFrame屏蔽熊猫DataFrame

时间:2018-08-31 22:48:25

标签: python pandas

我想使用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'])

我认为无论掩码是df的哪个掩码都将从True返回值。但是,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]

2 个答案:

答案 0 :(得分:1)

源代码说明了原因。对于__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数据框的常规布尔索引沿一个轴,即通过df.loc[mask, :]通过行/轴0或通过df.loc[:, mask]通过列/轴1。

请注意,为清楚起见,您可以并且可能应该直接访问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

答案 1 :(得分:1)

写下Truemask_np的行索引:行0,行0,行2,行{{1 }}。在3中选择具有相同索引的行并将其连接。 df就是这样产生的。

这可能是熊猫的错误​​,因为在源代码中假定用于索引的数组是一维的。


查看源代码(熊猫0.23.4),

df[mask_np]

等效于

df[mask_np]

等同于

df._getitem_bool_array(mask_np)

具有以下评估:

indexer = mask_np.nonzero()[0]
df._take(indexer, axis=0)

这个数组的元组表示沿着数组维度的非零元素的索引。在这种情况下,元组中第一个数组的元素(最终在>>> mask_np.nonzero() (array([0, 0, 2, 3]), array([0, 1, 0, 1])) 中使用)是df._takeTrue的'行'索引。

第一个数组用于沿索引{{​​1}}沿索引,因此您将获得mask_df的第take行作为回报。

相关问题