当前位置: 首页 > 面试题库 >

numpy矢量化弄乱了数据类型(2)

颛孙星海
2023-03-14
问题内容

我出现了不想要的行为np.vectorize,即,它更改了进入原始函数的参数的数据类型。我最初的问题是关于一般情况的,我将使用这个新问题来提出更具体的情况。

(为什么要问第二个问题?为了说明问题,我创建 了一个关于更具体案例 的问题-从具体问题到更一般的问题总是比较容易。而且我 单独
创建了这个问题,因为我认为这是有助于保持一般情况以及对一般情况的答复(应该找到),而不会因为考虑解决任何特定问题而受到“污染”。)

因此,一个具体的例子。我住的地方,星期三是彩票日。因此,让我们从一个pandas带有日期列的数据帧开始,该数据列包含今年所有的星期三:

df = pd.DataFrame({'date': pd.date_range('2020-01-01', freq='7D', periods=53)})

我想看看我可能会玩这些日子中的哪几天。在每个月的开始和结束我都不感到特别幸运,而且有些月我感到特别不幸。因此,我使用此函数来查看日期是否合格:

def qualifies(dt, excluded_months = []):
    #Date qualifies, if...
    #. it's on or after the 5th of the month; and
    #. at least 5 days remain till the end of the month (incl. date itself); and
    #. it's not in one of the months in excluded_months.
    if dt.day < 5:
        return False
    if (dt + pd.tseries.offsets.MonthBegin(1) - dt).days < 5:
        return False
    if dt.month in excluded_months:
        return False
    return True

我希望您意识到这个html" target="_blank">示例仍然有些人为;)但是,它更接近于我想要做的事情。我尝试通过两种方式应用此功能:

df['qualifies1'] = df['date'].apply(lambda x: qualifies(x, [3, 8]))
df['qualifies2'] = np.vectorize(qualifies, excluded=[1])(df['date'], [3, 8])

据我所知,两者都 应该
起作用,并且我更喜欢后者,因为前者很慢并且皱眉。 编辑: 我了解到,第一个也是皱眉。

但是,只有第一个成功,第二个失败,并带有AttributeError: 'numpy.datetime64' object has no attribute 'day'。所以我的问题是, 是否可以np.vectorize在此函数上使用qualifiesdatetime /
timestamp作为参数。

非常感谢!

PS:有兴趣的是df

In [15]: df
Out[15]: 
         date  qualifies1
0  2020-01-01       False
1  2020-01-08        True
2  2020-01-15        True
3  2020-01-22        True
4  2020-01-29       False
5  2020-02-05        True
6  2020-02-12        True
7  2020-02-19        True
8  2020-02-26       False
9  2020-03-04       False
10 2020-03-11       False
11 2020-03-18       False
12 2020-03-25       False
13 2020-04-01       False
14 2020-04-08        True
15 2020-04-15        True
16 2020-04-22        True
17 2020-04-29       False
18 2020-05-06        True
19 2020-05-13        True
20 2020-05-20        True
21 2020-05-27        True
22 2020-06-03       False
23 2020-06-10        True
24 2020-06-17        True
25 2020-06-24        True
26 2020-07-01       False
27 2020-07-08        True
28 2020-07-15        True
29 2020-07-22        True
30 2020-07-29       False
31 2020-08-05       False
32 2020-08-12       False
33 2020-08-19       False
34 2020-08-26       False
35 2020-09-02       False
36 2020-09-09        True
37 2020-09-16        True
38 2020-09-23        True
39 2020-09-30       False
40 2020-10-07        True
41 2020-10-14        True
42 2020-10-21        True
43 2020-10-28       False
44 2020-11-04       False
45 2020-11-11        True
46 2020-11-18        True
47 2020-11-25        True
48 2020-12-02       False
49 2020-12-09        True
50 2020-12-16        True
51 2020-12-23        True
52 2020-12-30       False

问题答案:

如果使用,np.vectorize则最好指定otypes。在这种情况下,错误是由未指定vectorize使用时间的试验计算引起的otypes。另一种方法是将Series作为对象类型数组传递。

np.vectorize有性能免责声明。 np.frompyfunc可能更快,甚至可以理解列表。

测试 向量化

让我们定义一个更简单的函数-一个显示参数类型的函数:

In [31]: def foo(dt, excluded_months=[]): 
    ...:     print(dt,type(dt)) 
    ...:     return True

还有一个较小的数据框:

In [32]: df = pd.DataFrame({'date': pd.date_range('2020-01-01', freq='7D', perio
    ...: ds=5)})                                                                
In [33]: df                                                                     
Out[33]: 
        date
0 2020-01-01
1 2020-01-08
2 2020-01-15
3 2020-01-22
4 2020-01-29

测试vectorize。(vectorizedocs说使用excluded参数会降低性能,所以我正在使用lambdawith所使用的apply):

In [34]: np.vectorize(lambda x:foo(x,[3,8]))(df['date'])                        
2020-01-01T00:00:00.000000000 <class 'numpy.datetime64'>
2020-01-01 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-08 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-15 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-22 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-29 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
Out[34]: array([ True,  True,  True,  True,  True])

第一行是datetime64产生问题的。其他行是原始的熊猫对象。如果指定otypes,该问题将消失:

In [35]: np.vectorize(lambda x:foo(x,[3,8]), otypes=['bool'])(df['date'])       
2020-01-01 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-08 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-15 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-22 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-29 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
Out[35]: array([ True,  True,  True,  True,  True])

适用:

In [36]: df['date'].apply(lambda x: foo(x, [3, 8]))                             
2020-01-01 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-08 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-15 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-22 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-29 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
Out[36]: 
0    True
1    True
2    True
3    True
4    True
Name: date, dtype: bool

datetime64D型是通过在包裹的系列生产的np.array

In [37]: np.array(df['date'])                                                   
Out[37]: 
array(['2020-01-01T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
       '2020-01-15T00:00:00.000000000', '2020-01-22T00:00:00.000000000',
       '2020-01-29T00:00:00.000000000'], dtype='datetime64[ns]')

显然np.vectorize,在执行初始试验计算时会进行这种包装,但在进行主迭代时则不会。指定otypes跳过该试用计算。尽管这是一个比较模糊的情况,但是该试用计算在其他SO中引起了问题。

在过去,当我进行测试时,np.vectorize它比更明确的迭代要慢。它确实有明确的性能免责声明。当函数需要多个输入并需要广播的好处时,这是最有价值的。仅使用一个参数很难证明。

np.frompyfuncunderlies
vectorize,但返回对象dtype。它的速度通常比数组上的显式迭代快2倍,尽管其速度与列表上的迭代速度相似。在创建和使用numpy对象数组时,它似乎最有用。在这种情况下,我没有使它起作用。

向量化代码

np.vectorize代码是在np.lib.function_base.py

如果otypes未指定,则代码执行以下操作:

        args = [asarray(arg) for arg in args]
        inputs = [arg.flat[0] for arg in args]
        outputs = func(*inputs)

它将每个参数(此处只有一个)放入一个数组,并采用第一个元素。然后将其传递给func。如图Out[37]所示,这将是一个datetime64对象。

frompyfunc

要使用frompyfunc,我需要转换的dtype df['date']

In [68]: np.frompyfunc(lambda x:foo(x,[3,8]), 1,1)(df['date'])                  
1577836800000000000 <class 'int'>
1578441600000000000 <class 'int'>
...

没有它,它传递int给函数,并传递给熊猫时间对象:

In [69]: np.frompyfunc(lambda x:foo(x,[3,8]), 1,1)(df['date'].astype(object))   
2020-01-01 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
2020-01-08 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
...

因此,这种使用方式qualifies是:

In [71]: np.frompyfunc(lambda x:qualifies(x,[3,8]),1,1)(df['date'].astype(object))                                                                     
Out[71]: 
0    False
1     True
2     True
3     True
4    False
Name: date, dtype: object

对象类型

对于主迭代,np.vectorize

      ufunc = frompyfunc(_func, len(args), nout)
      # Convert args to object arrays first
        inputs = [array(a, copy=False, subok=True, dtype=object)
                  for a in args]
        outputs = ufunc(*inputs)

这就解释了为什么vectorize可以otypes工作-它frompyfunc与对象dtype输入一起使用。将其与Out[37]

In [74]: np.array(df['date'], dtype=object)                                     
Out[74]: 
array([Timestamp('2020-01-01 00:00:00'), Timestamp('2020-01-08 00:00:00'),
       Timestamp('2020-01-15 00:00:00'), Timestamp('2020-01-22 00:00:00'),
       Timestamp('2020-01-29 00:00:00')], dtype=object)

另一种指定方法otypes是确保将dtype对象传递给vectorize

In [75]: np.vectorize(qualifies, excluded=[1])(df['date'].astype(object), [3, 8])                                                                      
Out[75]: array([False,  True,  True,  True, False])

这似乎是最快的版本:

np.frompyfunc(lambda x: qualifies(x,[3,8]),1,1)(np.array(df['date'],object))

或更好的是,一个简单的Python迭代:

[qualifies(x,[3,8]) for x in df['date']]


 类似资料:
  • 主要内容:数据类型对象,数据类型标识码,定义结构化数据NumPy 作为 Python 的扩展包,它提供了比 Python 更加丰富的数据类型,如表 1 所示: 表1:NumPy数据类型 序号 数据类型 语言描述 1 bool_ 布尔型数据类型(True 或者 False) 2 int_ 默认整数类型,类似于 C 语言中的 long,取值为 int32 或 int64 3 intc 和 C 语言的 int 类型一样,一般是 int32 或 int 64

  • 本小节将详述 Numpy 内置的数据类型,以及如何在创建数组对象时进行灵活指定、如何查看创建好的数组类型、以及如何更改数据类型。 1. 常见数据类型 Numpy 支持的数据类型比 Python 内置的要多很多,而这也是 Numpy 如此灵活和强大的原因之一。 例如对于整数,在 Numpy 中,根据整数的位数不同所需要占据的空间大小不同,又对整数类型进行类细分,常见地可以分为 int8、int16、

  • 向下和向上滚动后滚动回收器视图时遇到问题。这个想法是改变元素的颜色,但是当我向下滚动时,一切都很好,当滚动向上时——不应该着色的元素正在改变颜色。 这是我的适配器:

  • 问题内容: 我使用Python编写代码,我非常喜欢Notepad 。但是,当我使用制表符进行缩进时,在Notepad 中看起来很晚,但是当我运行该程序时,出现了缩进错误,并且当我在Emacs中检查代码时,我发现Notepad ++实际上增加了比制表符更多的空格。它显示在屏幕上。怎么了? 问题答案: 没有通用的制表符大小,因此我始终确保用空格替换制表符(因此您知道所看到的就是在其他任何地方都可以看到

  • 问题内容: 我有一个带有整数值的NumPy数组。矩阵的值的范围是从0到矩阵中的最大元素(换句话说,其中显示的所有数字是从0到最大数据元素)。我需要建立有效的( 有效的手段是快速的完全矢量化解决方案 )来搜索每一行中的元素数量,并根据矩阵值对它们进行编码。 我找不到类似的问题,或者以某种方式帮助解决了这个问题。 所以如果我在输入中有这个: 所需的输出是: 我知道如何解决这个问题,方法是简单地逐一 迭

  • 问题内容: 我有这个非常奇怪的问题。我有一个包含一些德语字母的网站,当它只是不带php的html时,当我将符号更改为UTF-8时,符号将显示为带有编码的属性,它们不会显示,而不是Ö。当我将html放入php并在Wamp上使用Zenset studio以charset = iso-8859-1编码启动时,得到�而不是Ö(我想补充一下,这个Ö是单选按钮的值) 。当它在一个 标签以正确显示。您能告诉