【问题标题】:Use multiple conditions on a column to assign values of new column在列上使用多个条件来分配新列的值
【发布时间】:2019-07-01 12:10:47
【问题描述】:

我正在尝试根据现有列中的字符串为我的数据分配 8 个标签之一。但是,使用我使用的方法会出现此错误:

ValueError:Series 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。

我正在寻找 144 个不同的字符串,我想将它们分配给 8 个标签。

这是我的意思的简化示例。如果 A 是我的数据框中的现有列,我想创建 B 并根据 A 的值分配字符串。

数据框:

   A     B
0  1   low
1  1   low
2  2   mid
3  3   mid
4  5  high
5  4   mid
6  2   mid
7  5  high

我目前使用的代码是这样的:

for index, row in df.iterrows():
    if df['A'] == 1:
        df['Label'] = 'low'
    elif any([df['A'] == 2, df['A'] == 3, df['A'] == 4]):
        df['Label'] = 'mid'
    elif df['A'] == 5:
        df['Label'] = 'high'

我认为是使用 any() 给了我错误。 据我了解,这是因为 pandas 的工作原理,但我不太了解。有没有更简单的方法来做到这一点?

任何帮助或指点将不胜感激:)

【问题讨论】:

  • 好像你从来没有达到“高”状态,这是你想要的吗?
  • l=[df.A.eq(1),df.A.isin([2,3,4]),df.A.eq(5)] 然后df['B']=np.select(l,['low','mid','high']) 会做得更快。不要在这种情况下使用 iterrows
  • 我想我达到了几次。 A 列中有两个 5 的实例。
  • 但根据您的情况,它应该评估为“中”,不是吗?
  • 啊,抱歉 - 这是一个错字。应该是 4。现在更正了。

标签: python python-3.x pandas any


【解决方案1】:

这里不需要itterrows,它是bad practice,被认为很慢。

方法一pd.cut

df['B'] = pd.cut(df['A'], [0,1,4,10], labels=['low', 'mid', 'high'])

   A     B
0  1   low
1  1   low
2  2   mid
3  3   mid
4  5  high
5  4   mid
6  2   mid
7  5  high

方法二np.select

conditions = [
    df['A'] == 1,
    df['A'].isin([2, 3, 4])
]

choices = ['low', 'mid']

df['B'] = np.select(conditions, choices, default='high')

   A     B
0  1   low
1  1   low
2  2   mid
3  3   mid
4  5  high
5  4   mid
6  2   mid
7  5  high

【讨论】:

    【解决方案2】:

    你为什么不简单地创建一个函数并将它应用到列上,这么简单这么pythonic

    def mapper(x):
         if x == 1:
            return 'low'
         elif x for i in [2, 3, 4]):
            return 'mid'
         elif x == 5:
            return 'high'
         else:
            return 'wtf'
    
    df['B'] = df['A'].apply(mapper)
    

    另一种方法是从映射字典创建数据框并进行连接,这更加直观

    或者另一种方式是参考系列的地图功能map function

    理想情况下,我更喜欢从下到上增加复杂性的顺序

    【讨论】:

      【解决方案3】:

      .loc与索引中的条件一起使用,如下:

      import pandas as pd
      from io import StringIO
      
      df = pd.read_csv(StringIO("""
         A
      0  1
      1  1
      2  2
      3  3
      4  5
      5  4
      6  2
      7  5
      """), sep=r"\s+")
      
      df.loc[df["A"] == 1, "B"] = "low"
      df.loc[df["A"].isin((2, 3, 4)), "B"] = "mid"
      df.loc[df["A"] == 5, "B"] = "high"
      
      print(df)
      
      

      输出:

         A     B
      0  1   low
      1  1   low
      2  2   mid
      3  3   mid
      4  5  high
      5  4   mid
      6  2   mid
      7  5  high
      

      【讨论】:

        【解决方案4】:

        cmets 中@anky_91 的回答简单解决了这个问题:

        l=[df.A.eq(1),df.A.isin([2,3,4]),df.A.eq(5)]
        df['B']=np.select(l,['low','mid','high'])
        

        这要快得多,而且效果很好。

        感谢大家的帮助! :)

        【讨论】:

          猜你喜欢
          • 2019-01-17
          • 2018-04-30
          • 2022-10-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-22
          相关资源
          最近更新 更多