我有两列:
date age
0 2016-01-05 47.0
1 2016-01-05 43.0
2 2016-01-05 28.0
3 2016-01-05 46.0
4 2016-01-04 39.0
我想要的是另一列日期和年龄之间的差异:
date age dob
0 2016-01-05 47.0 1969-01-05
1 2016-01-05 43.0 1973-01-05
2 2016-01-05 28.0 1988-01-05
3 2016-01-05 46.0 1970-01-05
4 2016-01-04 39.0 1977-01-04
看起来很简单,但是简单的 df['date'] - df['age'].astype('timedelta64[Y]')
给出:
0 1969-01-04 14:27:36
1 1973-01-04 13:44:24
2 1988-01-05 05:02:24
3 1970-01-04 20:16:48
4 1977-01-03 13:01:12
为什么要附加时间戳?甚至 pd.to_timedelta(df['age'], unit='Y')
也给出了相同的结果,并附加警告 unit='Y'
已弃用。
此外,df['date'] - pd.DateOffset(years=df['age'])
抛出(可以理解):
TypeError: cannot convert the series to <class 'int'>
我可以在第二个选项中使用 apply
,df['date'] - df['age'].apply(lambda a: pd.DateOffset(years=a))
,以迂回地获得正确的结果,并且(可以理解)PerformanceWarning: Adding/subtracting array of DateOffsets to DatetimeArray not vectorized
。
什么是好的(pythonic 和矢量化)解决方案?
最佳答案
如果您需要为每一行指定不同的非标准偏移量(即月或年),它可以节省时间遍历唯一偏移量而不是行。使用 groupby
完成此操作。
当唯一偏移量的数量 << DataFrame 中的行数时,尤其如此。对于整数年龄和非常长的 DataFrame 的实际值,很可能就是这种情况。
pd.concat([gp.assign(dob = gp.date - pd.offsets.DateOffset(years=age))
for age, gp in df.groupby('age', sort=False)])
date age dob
0 2016-01-05 47.0 1969-01-05
1 2016-01-05 43.0 1973-01-05
2 2016-01-05 28.0 1988-01-05
3 2016-01-05 46.0 1970-01-05
4 2016-01-04 39.0 1977-01-04
一些时间:
import perfplot
import pandas as pd
import numpy as np
def with_groupby(df):
s = pd.concat([gp.date - pd.offsets.DateOffset(years=idx)
for idx, gp in df.groupby('age', sort=False)])
return s
def with_apply(df):
s = df.apply(lambda x: x['date'] - pd.DateOffset(years=int(x['age'])), axis=1)
return s
perfplot.show(
setup=lambda n: pd.DataFrame({'date': np.random.choice(pd.date_range('1980-01-01',
freq='50D', periods=100), n),
'age': np.random.choice(range(100), n)}),
kernels=[lambda df: with_groupby(df),
lambda df: with_apply(df)],
labels=["groupby", "apply"],
n_range=[2 ** k for k in range(1, 20)],
equality_check=lambda x,y: x.sort_index().compare(y.sort_index()).empty,
xlabel='len(df)'
)
关于python - 从 to_timedelta 计算年龄很奇怪,并且 DateOffset 不可扩展到 Series,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58174267/