【问题标题】:Using Python 'in' operator to check if Dataframe column values are in list of strings results in ValueError使用 Python 'in' 运算符检查 Dataframe 列值是否在字符串列表中会导致 ValueError
【发布时间】:2021-02-24 15:18:03
【问题描述】:

我有一个类似的数据集:

    Mother ID ChildID    ethnicity
0     1       1          White Other
1     2       2          Indian
2     3       3          Black
3     4       4          Other
4     4       5          Other
5     5       6          Mixed-White and Black

为了简化我的数据集并使其与我正在执行的分类更加相关,我想将种族分为 3 类:

  1. 白人:在此类别中,我将包括“英国白人”和“其他白人”价值观
  2. 南亚:该类别将包括“巴基斯坦”、“印度”、“孟加拉国”
  3. 其他:“其他”、“黑色”、“混合白色和黑色”、“混合白色和南亚”值

所以我希望将上面的数据集转换为:

    Mother ID ChildID    ethnicity
0     1       1          White
1     2       2          South Asian
2     3       3          Other
3     4       4          Other
4     4       5          Other
5     5       6          Other

为此,我运行了以下代码,类似于answer 中提供的代码:


    col         = 'ethnicity'
    conditions  = [ (df[col] in ('White British', 'White Other')),
                   (df[col] in ('Indian', 'Pakistani', 'Bangladeshi')),
                   (df[col] in ('Other', 'Black', 'Mixed-White and Black', 'Mixed-White and South Asian'))]
    choices     = ['White', 'South Asian', 'Other']
        
    df["ethnicity"] = np.select(conditions, choices, default=np.nan)
    

但是在运行它时,我收到以下错误: ValueError:Series 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。

知道为什么我会收到此错误吗?我没有正确处理字符串比较吗?我正在使用类似的技术来操作我的数据集中的其他特征,并且在那里运行良好。

【问题讨论】:

  • 你应该接受我的回答。

标签: python numpy dataframe


【解决方案1】:

我找不到in为什么不起作用,但是isin肯定解决了问题,也许其他人可以告诉为什么in有问题。

conditions  = [ (df[col].isin(('White British', 'White Other'))),
                (df[col].isin(('Indian', 'Pakistani', 'Bangladeshi'))),
                (df[col].isin(('Other', 'Black', 'Mixed-White and Black', 'Mixed-White and South Asian')))]
print(conditions)
choices     = ['White', 'South Asian', 'Other']

df["ethnicity"] = np.select(conditions, choices, default=np.nan)
print(df)

输出

   Mother ID  ChildID    ethnicity
0          1        1        White
1          2        2  South Asian
2          3        3        Other
3          4        4        Other
4          4        5        Other
5          5        6          nan

【讨论】:

【解决方案2】:

使用df[col] in some_tuple,您在some_tuple 中搜索df[col],这显然不是您想要的。你想要的是df[col].isin(some_tuple),它返回一系列与df[col] 相同长度的新布尔值。

那么,为什么还是会出现该错误?在元组中搜索值的函数大致如下:

for v in some_tuple:
    if df[col] == v:
        return True
return False
  • df[col] == v 计算为一系列 result;这里没问题
  • 然后 Python 尝试评估 if result: 并且您收到该错误,因为您在条件子句中有一个系列,这意味着您(隐式)尝试将系列评估为布尔值; pandas 不允许这样做。

对于你的问题,无论如何,我会使用DataFrame.apply。它需要一个将一个值映射到另一个的函数;在您的情况下,将每个种族映射到一个类别的功能。有很多方法可以定义它(见下面的选项)。


import numpy as np
import pandas as pd

d = pd.DataFrame({
    'field': range(6),
    'ethnicity': list('ABCDE') + [np.nan]
})

# Option 1: define a dict {ethnicity: category}
category_of = {
    'A': 'X',
    'B': 'X',
    'C': 'Y',
    'D': 'Y',
    'E': 'Y',
    np.nan: np.nan,
}
result = d.assign(category=d['ethnicity'].apply(category_of.__getitem__))
print(result)

# Option 2: define categories, then "invert" the dict.
categories = {
    'X': ['A', 'B'],
    'Y': ['C', 'D', 'E'],
    np.nan: [np.nan],
}
# If you do this frequently you could define a function invert_mapping(d):
category_of = {eth: cat
               for cat, values in categories.items()
               for eth in values}
result = d.assign(category=d['ethnicity'].apply(category_of.__getitem__))
print(result)

# Option 3: define a function (a little less efficient)
def ethnicity_to_category(ethnicity):
    if ethnicity in {'A', 'B'}:
        return 'X'
    if ethnicity in {'C', 'D', 'E'}:
        return 'Y'
    if pd.isna(ethnicity):
        return np.nan
    raise ValueError('unknown ethnicity: %s' % ethnicity)

result = d.assign(category=d['ethnicity'].apply(ethnicity_to_category))
print(result)

【讨论】:

  • 我理解您所说的将系列评估为布尔值。但是为什么这个评估对我数据集中的其他特征有效。在此处查看此答案:stackoverflow.com/questions/39109045/…
  • 另外,您的代码中如何处理 NaN?在上面的代码中,我通过在 np.select 中传递 default=np.nan 来处理它们。
  • @sums22 你没有做同样的事情。如果您使用“in”,您正在调用一个元组方法,这将导致我在上面编写的代码:在代码中的某处会有一个if,它将有一个系列作为条件(series == value 的结果) .在该答案中,您使用在 Series 中定义的 ">" 等运算符,并将返回另一个 Series。没有if series: 参与。
  • @sums22 处理 NaN 就像写 category_of[np.nan] = np.nan 一样简单。请记住,apply 只需要一个将值映射到另一个值的函数。我的代码只是示例。您可以通过多种方式定义该函数。我会扩展我的答案。
  • @sums22 所以,回顾一下,series in tuple 不是您想要的操作:您不想知道该系列是否在元组内,您需要另一个系列来告诉您元素是否series 在元组中;这就是series.isin(tuple) 所做的。
猜你喜欢
  • 2021-12-06
  • 2013-08-01
  • 2019-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-30
相关资源
最近更新 更多