广播自定义函数
Broadcasting custom function
我想构建一个广播支持的自定义函数。
特别是,我有两个数组,一个是日期,另一个是时间,我想合并这两个数组,如 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.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
如果您想深入研究 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)
combine
来自 x
和 y
的列表版本甚至更快。
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)
我想构建一个广播支持的自定义函数。
特别是,我有两个数组,一个是日期,另一个是时间,我想合并这两个数组,如 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.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
如果您想深入研究 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)
combine
来自 x
和 y
的列表版本甚至更快。
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)