在Dataframe.assign()中使用if / else会导致ValueError:系列的真值

时间:2019-03-28 21:58:21

标签: python pandas dataframe

我已经用支持这种结构的批处理转换语言定义了大量的数据转换:x = iif(condition,a,b)。我想使用数据框重写这些。

我正在使用Dataframe.assign(),但得到ValueError:系列的真值不明确。使用a.empty,a.bool(),a.item(),a.any()或a.all()。

    import pandas as pd
    df = pd.DataFrame(['apple', 'orange', 'granite'], columns=['name'])
    df.assign(taste = lambda x: 'rocky' if (x.name=='granite') else 'yummy')

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-39-e9ad71ccc45b> in <module>()
----> 1 df.assign(taste = lambda x: 'rocky' if (x.name=='granite') else 'yummy')

~\Anaconda3\lib\site-packages\pandas\core\frame.py in assign(self, **kwargs)
   3305         if PY36:
   3306             for k, v in kwargs.items():
-> 3307                 data[k] = com._apply_if_callable(v, data)
   3308         else:
   3309             # <= 3.5: do all calculations first...

~\Anaconda3\lib\site-packages\pandas\core\common.py in _apply_if_callable(maybe_callable, obj, **kwargs)
    403 
    404     if callable(maybe_callable):
--> 405         return maybe_callable(obj, **kwargs)
    406 
    407     return maybe_callable

<ipython-input-39-e9ad71ccc45b> in <lambda>(x)
----> 1 df.assign(taste = lambda x: 'rocky' if (x.name=='granite') else 'yummy')

~\Anaconda3\lib\site-packages\pandas\core\generic.py in __nonzero__(self)
   1571         raise ValueError("The truth value of a {0} is ambiguous. "
   1572                          "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
-> 1573                          .format(self.__class__.__name__))
   1574 
   1575     __bool__ = __nonzero__

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

起初我以为这是由于对assign()中所允许的关键字的限制,但是非常相似的构造适用于apply():

df['name'].apply(lambda x: 'rocky' if (x=='granite') else 'yummy')

0    yummy
1    yummy
2    rocky
Name: name, dtype: object

但是,这不允许我使用if条件,该条件使用数据框中的多个列。有没有一种方法可以让Assign()工作?

2 个答案:

答案 0 :(得分:2)

分配不是您应在条件分配中使用的功能

df['taste']=np.where(df['name'].eq('granite'),'rocky','yummy')
df
Out[513]: 
      name  taste
0    apple  yummy
1   orange  yummy
2  granite  rocky

答案 1 :(得分:2)

调用Series.apply时,lambda接收每个行值(即标量值)。使用assign,lambda接收整个DataFrame。了解这一点意味着您现在可以执行

之类的操作
df.assign(taste=lambda x: np.where(x['name'] == 'granite', 'r', 'y'))

      name taste
0    apple     y
1   orange     y
2  granite     r

或者,

df.assign(taste=np.where(df['name'] == 'granite', 'r', 'y'))
      name taste
0    apple     y
1   orange     y
2  granite     r

或者,更简单地说,是就地分配,

df['taste'] = np.where(df['name'] == 'granite', 'r', 'y')
df

      name taste
0    apple     y
1   orange     y
2  granite     r