当 np.where 抛出 TypeError 时,为啥 np.vectorize 在这里工作?

Posted

技术标签:

【中文标题】当 np.where 抛出 TypeError 时,为啥 np.vectorize 在这里工作?【英文标题】:why does np.vectorize work here when np.where throws a TypeError?当 np.where 抛出 TypeError 时,为什么 np.vectorize 在这里工作? 【发布时间】:2022-01-20 00:13:28 【问题描述】:

我有一个 pandas DataFrame,其中名为 myenum 的列的值是 0、1 或 2。我正在尝试将 1s 和 2s 转换为字符串并使用 Enum 的 .name 属性来提供帮助。

我认为这是一个关于理解 np.where 与 np.vectorize 的胆量的问题,因为它们与 DataFrame 系列相关。我很好奇为什么尝试使用 np.where 会引发错误,但使用 np.vectorize 可以工作。我想从中学习并更好地了解 DataFrames 中的最佳矢量化实践。

import enum
import numpy as np
import pandas as pd

df = pd.DataFrame() # one column in this df is 'myenum', its values are either 0, 1, or 2
df['myenum'] = [0, 1, 2, 0, 0, 0, 2, 1, 0]


class MyEnum(enum.Enum):
    First = 1
    Second = 2

# this throws a TypeError - why?
df['myenum'] = np.where(
    df['myenum'] > 0,
    MyEnum(df['myenum']).name,
    ''
    )

# whereas this, which seems pretty analagous, works.  what am i missing?
def vectorize_enum_value(x):
    if x > 0:
        return  MyEnum(x).name
    return ''
vect = np.vectorize(vectorize_enum_value)
df['myenum'] = vect(df['myenum'])

【问题讨论】:

MyEnum(df['myenum']).name 永远无法工作。 MyEnum 构造函数不是numpypandas 的一部分,并且不知道传递数组时要做什么。您确实需要vectorizeapply @Tim Roberts 谢谢 - 所以教训是,要使用 np.where,你必须只在 numpy 知道如何做的 where 子句内执行操作?这就说得通了。并且 vectorize 是一种有效的解决方法,可能比 apply 更快(尽管考虑测试?)。谢谢。 基本上,是的。 numpypandas 对象和函数知道如何处理向量和数组,但是您必须使用 apply 和 vectorize 之类的东西来获得“不知道”的函数。 谢谢。也许更具体的课程是“仅在 numpy 知道如何执行的 where 调用 on 数组 内执行操作”。我有资格获得 on the array 因为在查看我的其他一些工作 np.where 用法时,我确实经常引入自己的课程,但在你的帮助下,我意识到我从未通过我的课程数组... np.where 仅与 cond 参数一样好:df['myenum'] > 0。在 Python 中,函数参数首先被计算,然后传递给函数。 where 不是迭代器或“魔术”。我打算用演示写一个完整的答案,但你没有提供有效的数据框。 np.vectorize 不是特别快;这就像一个列表理解。但是pandas.apply 很慢,除非你指定raw 模式。 【参考方案1】:

where 表达式的完整回溯是:

Traceback (most recent call last):
  File "/usr/lib/python3.8/enum.py", line 641, in __new__
    return cls._value2member_map_[value]
TypeError: unhashable type: 'Series'

During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<ipython-input-27-16f5edc71240>", line 3, in <module>
    MyEnum(df['myenum']).name,
  File "/usr/lib/python3.8/enum.py", line 339, in __call__
    return cls.__new__(cls, value)
  File "/usr/lib/python3.8/enum.py", line 648, in __new__
    if member._value_ == value:
  File "/usr/local/lib/python3.8/dist-packages/pandas/core/generic.py", line 1537, in __nonzero__
    raise ValueError(
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

整个系列送给MyEnum制作:

In [30]: MyEnum(df['myenum'])
Traceback (most recent call last):
  File "/usr/lib/python3.8/enum.py", line 641, in __new__
    return cls._value2member_map_[value]
TypeError: unhashable type: 'Series'
...

问题根本不在于where

如果我们提供一个有效的字符串列表,where 可以正常工作:

In [33]: np.where(
    ...:     df['myenum'] > 0,
    ...:     [vectorize_enum_value(x) for x in df['myenum']],
    ...:     ''
    ...:     )
Out[33]: 
array(['', 'First', 'Second', '', '', '', 'Second', 'First', ''],
      dtype='<U6')

第二个参数,列表推导与vectorize基本相同。

where 是一个函数; Python 在传入函数参数之前对其进行评估。因此每个参数都必须有效。 where 不是迭代器,例如 apply 甚至 vectorize

【讨论】:

以上是关于当 np.where 抛出 TypeError 时,为啥 np.vectorize 在这里工作?的主要内容,如果未能解决你的问题,请参考以下文章

Nuxt 抛出错误:未捕获的 TypeError:无法将类作为函数调用

为啥 Dash 在通过 PyCharm 调试时会抛出 TypeError? [关闭]

使用 np.where 在二维数组中查找匹配行

尝试调用方法时,Angular 7 注入服务在刷新后抛出 TypeError

在使用所有可能的预测变量拟合模型时,它会抛出此错误 TypeError: ufunc 'isfinite' not supported

为啥 np.where & np.min 似乎不适用于这个数组?