【发布时间】:2020-04-22 03:09:38
【问题描述】:
np.vectorize 产生了不想要的行为,也就是说,它改变了进入原始函数的参数的数据类型。我的original question is about the general case,我将使用这个新问题来询问更具体的案例。
(为什么是第二个问题?我创建了这个问题关于更具体的案例以说明问题 - 从具体到更一般总是更容易。而且我'我单独创建了这个问题,因为我认为保留一般情况以及对它的一般答案(应该找到)自己而不是“污染”考虑解决问题是有用的任何特殊问题。)
所以,一个具体的例子。我住的地方,星期三是彩票日。所以,让我们从一个包含今年所有星期三的日期列的 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
我希望你意识到这个例子仍然有些做作;)但它更接近我想要做的事情。我尝试通过两种方式应用此功能:
df['qualifies1'] = df['date'].apply(lambda x: qualifies(x, [3, 8]))
df['qualifies2'] = np.vectorize(qualifies, excluded=[1])(df['date'], [3, 8])
据我所知,两者都应该工作,我更喜欢后者,因为前者很慢而且frowned upon。 编辑:我了解到第一个也是不赞成大声笑的。
但是,只有第一个成功,第二个失败并返回 AttributeError: 'numpy.datetime64' object has no attribute 'day'。所以我的问题是,如果有办法在这个函数qualifies 上使用np.vectorize,它需要一个日期时间/时间戳作为参数。
非常感谢!
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
【问题讨论】:
-
1) Vectorize 也不受欢迎。无论哪种方式,您都在运行 vanilla python 代码并放弃了实际矢量化的所有好处。
-
2) Vectorize 将尝试将第一个参数转换为数组。
np.array(df['date'])和df['date'].values都有dtype='datetime64[ns]' -
@MadPhysicist,看起来指定
otypes=['boo']会阻止这种转换。好像np.array(...)转换仅在执行隐含的otype计算时才适用。当我测试一个只打印dt类型的简单函数时,我也看到了这种行为。 -
@MadPhysicist,在进行
otypes计算时,vectorize使用np.asarray(...).ravel()[0]得到第一个测试值。但是对于主要的loop,它会执行np.array(..., dtype=object)以准备将args 发送到frompyfunc。也许我们应该为此提交issue。 -
@hpaulj。绝对看起来很值得,尽管我想不出更好的解决方案来进行测试运行。也许将类型检查推迟到以后会很有用。