概要
如果使用,
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]: date0 2020-01-011 2020-01-082 2020-01-153 2020-01-224 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 True1 True2 True3 True4 TrueName: 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 False1 True2 True3 True4 FalseName: 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']]



