使用 Pandas 的条件语句创建数据框列:基于多个条件

4

我有一个数据框(df):

  col1 col2 col3
0    1    2    3
1    2    3    1
2    3    3    3
3    4    3    2

我想根据以下条件添加一个新列:
 - if   col1 > col2 > col3   ----->  2
 - elif col1 > col2          ----->  1
 - elif col1 < col2 < col3   -----> -2
 - elif col1 < col2          -----> -1
 - else                      ----->  0

它应该变成这样:

  col1 col2 col3   new
0    1    2    3   -2
1    2    3    1   -1
2    3    3    3    0
3    4    3    2    2

我按照unutbu的这篇帖子的方法进行操作,对于大于或小于1的情况运行良好。但在我的情况下,大于1或小于-1的条件返回错误:

conditions = [
       (df['col1'] > df['col2'] > df['col3']), 
       (df['col1'] > df['col2']),
       (df['col1'] < df['col2'] < df['col3']),
       (df['col1'] < df['col2'])]
choices = [2,1,-2,-1]
df['new'] = np.select(conditions, choices, default=0)


Traceback (most recent call last):

  File "<ipython-input-43-768a4c0ecf9f>", line 2, in <module>
    (df['col1'] > df['col2'] > df['col3']),

  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py", line 1478, in __nonzero__
    .format(self.__class__.__name__))

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

我该如何做到这一点?


1
尝试使用 '.eval' 方法创建单个布尔系列,例如 df.eval('col1 > col2 > col3')。这相当于逐个元素地比较 col1 是否大于 col2,col2 是否大于 col3,并在满足条件时分配 True。否则,pandas 会为 df['col1'] > df['col2'] 创建一个布尔系列,然后不知道如何评估条件 boolean series > df['col3'] - jtorca
2个回答

3

修改你的代码为:

conditions = [
       (df['col1'] > df['col2']) &  (df['col2'] > df['col3']), 
       (df['col1'] > df['col2']),
       (df['col1'] < df['col2']) & (df['col2'] < df['col3']),
       (df['col1'] < df['col2'])]
choices = [2,1,-2,-1]
df['new'] = np.select(conditions, choices, default=0)

0
一个选择是使用pyjanitor中的case_when;其内部使用pd.Series.mask
基本思路是将条件和期望值配对;您可以传递所需的任意数量的配对,然后跟随默认值和目标列名:
# pip install pyjanitor
import pandas as pd
import janitor

df.case_when( 
      # condition, value
     'col1>col2>col3', 2,
     'col1>col2', 1,
     'col1<col2<col3', -2,
     'col1<col2', -1,
     0, # default
     column_name = 'new')

   col1  col2  col3  new
0     1     2     3   -2
1     2     3     1   -1
2     3     3     3    0
3     4     3     2    2

上面的代码使用字符串作为条件,这些条件由父数据框上的pd.eval进行评估,需要注意的是,对于小数据集而言,速度可能会慢一些。另外一种更快的选项(根据数据大小)是避免使用pd.eval选项:
df.case_when( 
      # condition, value
     df.col1.gt(df.col2) & df.col2.gt(df.col3), 2,
     df.col1.gt(df.col2), 1,
     df.col1.lt(df.col2) & df.col2.lt(df.col3), -2,
     df.col1.lt(df.col2), -1,
     0, # default
     column_name = 'new')

   col1  col2  col3  new
0     1     2     3   -2
1     2     3     1   -1
2     3     3     3    0
3     4     3     2    2

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