【问题标题】:Why does python lambda see a series instead of a value?为什么 python lambda 看到的是一个系列而不是一个值?
【发布时间】:2019-11-30 06:58:52
【问题描述】:

我创建了一个 Pandas DataFrame:

df = pd.DataFrame( {'some_number' : [1,2,3,4,5,6]})

那我想添加一个名为 is_even 的列:

df.assign(
    is_even = lambda x : 'YES' if x.some_number % 2 == 0 else 'NO'
)

我收到一个错误:

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

我了解错误告诉我 if 语句后的 x.some_number 是一个系列。这让我很困惑,因为如果我这样做:

df.assign(
    is_even = lambda x : 'YES' if 1==2 else x.some_number
)

它可以工作并生成以下输出:

这表明 x.some_number 实际上不是一个系列,而是一个标量值。

我知道还有其他方法可以完成我想要完成的任务。但我对这种行为很感兴趣。

为什么,当 x.some_number 在 if 子句之后时,它被视为一个系列,而当它在 else 子句中使用时,它被视为一个值?

INSTALLED VERSIONS
------------------
python           : 3.8.0.final.0
python-bits      : 32
OS               : Windows
OS-release       : 10
machine          : AMD64
processor        : Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
byteorder        : little
LOCALE           : English_United States.1252

pandas           : 0.25.3
numpy            : 1.17.4
IPython          : 7.10.0
matplotlib       : 3.1.2

【问题讨论】:

    标签: python python-3.x pandas lambda


    【解决方案1】:

    问题是只有 if 语句,您在第一个示例中将一个系列与一个标量值进行比较。这永远不会奏效。第二个示例有效,因为您有一个标量 if 语句(当然可以)并且您返回一个系列。返回一个系列(或一个标量)正是传递给assign 的函数需要做的事情。

    现在,您真正想做的是逐行比较。为此使用apply

    df['is_even'] = df.some_number.apply(lambda x: 'YES' if x % 2 == 0 else 'NO' )
    

    这里,x 是一个标量,if 语句按预期工作。 或者,您可以结合 assign 和 lambda 函数

    df.assign(
        is_even = lambda x : x.some_number.apply(lambda x: 'YES' if x % 2 == 0 else 'NO')
    )
    

    再次注意第一个示例的不同之处:外部 lambda 确保内部 lambda 只需要处理 if x % 2 == 0 中的标量。外部 lambda 返回一个系列,就像在您的 second 示例中一样。

    【讨论】:

      【解决方案2】:

      你的证明没有成功。 Pandas Dataframe.assign 似乎能够处理系列或标量并将其应用于数据帧。

      In [7]: df.assign(is_even=lambda x: x.some_number[0] )                                                                 
      Out[7]: 
         some_number  is_even
      0            1        1
      1            2        1
      2            3        1
      3            4        1
      4            5        1
      5            6        1
      
      

      如果您阅读the docs carefully,您会看到该参数接受回调或系列,并根据类型应用它。

      列名是关键字。如果这些值是可调用的,则在 DataFrame 上计算它们并分配给新列。可调用对象不能更改输入 DataFrame(尽管 pandas 不会检查它)。如果这些值不可调用(例如,系列、标量或数组),则只需对其进行赋值。

      另外,如果你深入研究一下源代码:

      # >= 3.6 preserve order of kwargs
      if PY36:
      for k, v in kwargs.items():
          data[k] = com.apply_if_callable(v, data)
      

      您可以查看它是否是可调用对象,它将整个数据帧传递给您的可调用对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-02
        • 1970-01-01
        • 2020-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多