【问题标题】:Broadcasting custom function广播自定义功能
【发布时间】:2019-09-02 22:48:05
【问题描述】:

我想构建一个广播支持的自定义函数。

特别是,我有两个数组,一个是日期,另一个是时间,我想合并这两个数组,如datetime.datetime.combine

我想要这样的东西(这是我的价值观,但问题更普遍):

x = array([datetime.date(2019, 1, 21), datetime.date(2019, 1, 21),
           datetime.date(2019, 1, 21)])
y = array([datetime.time(0, 0), datetime.time(0, 15), datetime.time(0, 30)]

我想做这样的事情:

datetime.combine(out[:,0], out[:,1])

要获得相同的结果:

np.asarray([datetime.combine(i,j) for i,j in zip(x,y)])

更笼统地说:

假设我有一个函数f(a,b),我有两个numpy 数组x,y。有没有办法申请广播规则并获取f(x,y)

【问题讨论】:

  • 您是否尝试在 numpy 数组中对 python 函数进行矢量化?
  • 另外,我不认为广播意味着你认为它的意思......
  • 回答你的最后一个问题:这取决于f
  • @MadPhysicist 就第一个答案而言,是的,我想避免使用 np.vectorize。更一般的部分是对第一部分的概括:我写错了。在我的示例中,有一个矢量化问题,如果我正确理解了广播的含义,那么在后面的部分中,我假设这两个数组可能具有不同的大小(但有资格进行广播)。
  • 除非您使用 numpy 类型,否则您不会从包含对成熟的 python 对象的引用的 numpy 数组中获得太多好处

标签: python numpy broadcast


【解决方案1】:

如果您想深入了解c 代码,自定义ufuncs 就可以了。但是您的说明性案例适用于 datetime 对象。 np.frompyfunc 对此非常有用。对于对象 dtype 数组,numpy 必须在(接近)Python 级别进行迭代,在每个对象上运行 Python 代码。如果您在对象数组上调用ufunc,它会将任务委托给每个对象的相应方法(如果不存在这样的方法,则会失败)。

让我们构造你的日期数组:

In [20]: from datetime import datetime   

In [35]: alist = [datetime(2019,1,21,0,0), datetime(2019,1,21,0,10),datetime(2020,1,21,0,0)]                                                           
In [36]: x = np.array([a.date() for a in alist])                                
In [37]: y = np.array([a.time() for a in alist])                                
In [38]: x                                                                      
Out[38]: 
array([datetime.date(2019, 1, 21), datetime.date(2019, 1, 21),
       datetime.date(2020, 1, 21)], dtype=object)
In [39]: y                                                                      
Out[39]: 
array([datetime.time(0, 0), datetime.time(0, 10), datetime.time(0, 0)],
      dtype=object)

并使用列表理解进行组合:

In [41]: np.array([datetime.combine(i,j) for i, j in zip(x,y)])                 
Out[41]: 
array([datetime.datetime(2019, 1, 21, 0, 0),
       datetime.datetime(2019, 1, 21, 0, 10),
       datetime.datetime(2020, 1, 21, 0, 0)], dtype=object)

frompyfunc:

In [43]: np.frompyfunc(datetime.combine, 2,1)(x,y)                              
Out[43]: 
array([datetime.datetime(2019, 1, 21, 0, 0),
       datetime.datetime(2019, 1, 21, 0, 10),
       datetime.datetime(2020, 1, 21, 0, 0)], dtype=object)

frompyfunc我们可以申请广播

In [44]: np.frompyfunc(datetime.combine, 2,1)(x,y[:,None])                      
Out[44]: 
array([[datetime.datetime(2019, 1, 21, 0, 0),
        datetime.datetime(2019, 1, 21, 0, 0),
        datetime.datetime(2020, 1, 21, 0, 0)],
       [datetime.datetime(2019, 1, 21, 0, 10),
        datetime.datetime(2019, 1, 21, 0, 10),
        datetime.datetime(2020, 1, 21, 0, 10)],
       [datetime.datetime(2019, 1, 21, 0, 0),
        datetime.datetime(2019, 1, 21, 0, 0),
        datetime.datetime(2020, 1, 21, 0, 0)]], dtype=object)

x 可以用frompyfunc 构造:

In [46]: np.frompyfunc(lambda a: a.date(),1,1)(alist)                           
Out[46]: 
array([datetime.date(2019, 1, 21), datetime.date(2019, 1, 21),
       datetime.date(2020, 1, 21)], dtype=object)

frompyfunc 版本的 combine 更快

In [47]: timeit np.frompyfunc(datetime.combine, 2,1)(x,y)                       
5.39 µs ± 181 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [48]: timeit np.array([datetime.combine(i,j) for i, j in zip(x,y)])          
11.8 µs ± 66.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

虽然 [48] 时间的很大一部分来自数组接口:

In [51]: timeit [datetime.combine(i,j) for i, j in zip(x,y)]                    
3.91 µs ± 41.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

来自xy 列表版本的combine 甚至更快。

In [52]: %%timeit xy=zip(x.tolist(),y.tolist()) 
    ...: [datetime.combine(i,j) for i,j in xy] 
190 ns ± 0.579 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

【讨论】:

    【解决方案2】:

    如果您正在寻找的不仅仅是 numpy.vectorize,您可能需要查看 numpy ufuncs:

    https://docs.scipy.org/doc/numpy-1.16.1/reference/ufuncs.html

    您可以尝试创建自己的自定义 ufunc https://docs.scipy.org/doc/numpy/user/c-info.ufunc-tutorial.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      相关资源
      最近更新 更多