Pandas - 检查每行是否存在多列中的某个值

4

I have the following Pandas dataframe:

Index  Name  ID1  ID2  ID3
    1  A     Y    Y    Y
    2  B     Y    Y        
    3  B     Y              
    4  C               Y

我希望添加一个名为'Multiple'的新列,用于指示ID1、ID2和ID3列中有超过一个值为Y的行。

Index  Name  ID1  ID2  ID3 Multiple
    1  A     Y    Y    Y   Y
    2  B     Y    Y        Y
    3  B     Y             N
    4  C               Y   N

通常我会使用np.wherenp.select,例如:

df['multiple'] = np.where(<More than 1 of ID1, ID2 or ID3 have a Y in>), 'Y', 'N')

但是我无法想出如何编写条件语句。可能会有越来越多的ID列,所以我不能将每个组合作为单独的条件进行覆盖 (例如:(ID1 = Y and ID3 = Y) or (ID2 = Y and ID3 = Y))。我认为我可能需要计算指定列中的Y值总数?

在Pandas之外,我会考虑使用列表,在其中附加每个列的值(如果为Y),然后查看列表是否具有大于1的长度。

但我不知道如何在np.wherenp.selectdf.loc的限制下完成它。有什么建议吗?


2
np.where(df.filter(like='ID').eq('Y').sum(1).gt(1), 'Y', 'N') - user3483203
尝试:df.apply(lambda x: x.eq('Y')).sum(1).gt(1) - Quang Hoang
1
@QuangHoang 这在这里根本行不通。 - user3483203
我现在要去检查一下.eq、.sum和.gt——这些我之前没用过的东西! - MrDave
user3483203 - 你的建议可行,因此是被接受答案的一个替代方案。 - MrDave
2个回答

4
使用numpy按行求和以获得Y的出现次数即可:
df['multi'] = ['Y' if x > 1 else 'N' for x in np.sum(df.values == 'Y', 1)]

输出:

      Name ID1   ID2   ID3 multi
Index                           
1        A   Y     Y     Y     Y
2        B   Y     Y  None     Y
3        B   Y  None  None     N
4        C   Y  None  None     N

在代码中哪里限制了列ID1、ID2和ID3,而排除了Name? - MrDave
不需要的话,我可以像评论中建议的那样使用过滤器。所以 np.sum(df.filter(like='ID').values == 'Y',1) 或者如果你明确想排除 Name 的话,可以使用 np.sum(df.drop('Name', axis = 1).values == 'Y',1) - Yuca
如果有一个名称列,其值只是“Y”,那该怎么办? - butterflyknife
@butterflyknife,这是我评论中“drop”版本所提到的问题。 - Yuca

3
我会这样做:
获取您想要检查的列的列表。
    cols = [x for x in testdf.columns if "id" in x]

如果需要,您可以在DataFrame上使用filter方法,但我认为明确选择列的列表更清晰,并且您完全可以灵活地更改条件。

之后,只需:

    testdf["multiple"] = (testdf[cols]=="Y").any(axis="columns")

说明:

  • testdf[cols] 返回由您在第一行中选择的列组成的 DataFrame。
  • testdf[cols]=="Y" 返回填充 True 或 False 根据条件 "==Y" 的 DataFrame。
  • ().any(axis="columns") 跨越该 DataFrame 的列,并且对于每一行,如果行中任何项目为 True,则返回 True,否则返回 False。

如果您真的想要,可以将 True 更改为 "Y",将 False 更改为 "N"。


我可能错了,但这似乎是测试任何列值是否为“Y”,而不是是否有多个列值为“Y”? - MrDave
尽管如此,我喜欢最初获取列列表 - 这非常易读。 - MrDave
@MrDave 您是正确的 - 我误读了问题。 - butterflyknife

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接