Python-一百万行表中日期的矢量化差异
我有以下数据帧:Python-一百万行表中日期的矢量化差异,python,pandas,date,numpy,Python,Pandas,Date,Numpy,我有以下数据帧: Date 2018-04-10 21:05:00 2018-04-10 21:05:00 2018-04-10 21:10:00 2018-04-10 21:15:00 2018-04-10 21:35:00 我的目标是计算每次前后20分钟的行数(包括前后时间相同的行)。如下所示: Date nr_20_min_bef nr_2
Date
2018-04-10 21:05:00
2018-04-10 21:05:00
2018-04-10 21:10:00
2018-04-10 21:15:00
2018-04-10 21:35:00
我的目标是计算每次前后20分钟的行数(包括前后时间相同的行)。如下所示:
Date nr_20_min_bef nr_20_min_after
2018-04-10 21:05:00 2 4
2018-04-10 21:05:00 2 4
2018-04-10 21:10:00 3 2
2018-04-10 21:15:00 4 2
2018-04-10 21:35:00 2 1
我曾尝试执行for循环来迭代所有行,问题是整个系列有超过百万行,因此我正在寻找一个更有效的解决方案。我目前的做法是使用以下功能:
import datetime
import pandas
df = pd.DataFrame(pd.to_datetime(['2018-04-10 21:05:00',
'2018-04-10 21:05:00',
'2018-04-10 21:10:00',
'2018-04-10 21:15:00',
'2018-04-10 21:35:00']),columns = ['Date'])
nr_20_min_bef = []
nr_20_min_after = []
for i in range(0, len(df)):
nr_20_min_bef.append(df.Date.between(df.Date[i] -
pd.offsets.DateOffset(minutes=20), df.Date[i], inclusive = True).sum())
nr_20_min_after.append(df.Date.between(df.Date[i], df.Date[i] +
pd.offsets.DateOffset(minutes=20), inclusive = True).sum())
对于这种情况,矢量化的解决方案可能是理想的,但是,我真的不知道如何做到这一点
提前感谢。我认为您可以使用
apply
即使它不是矢量化的方式,也应该比使用for
循环更快,例如:
#first create the timedelta of 20 minutes
dt_20 = pd.Timedelta(minutes=20)
# then apply on the first column
df['nr_20_min_bef'] = df['Date'].apply(lambda x: df['Date'][((x - dt_20) <= df['Date'] )
& (x >=df['Date'])].count())
df['nr_20_min_after'] = df['Date'].apply(lambda x: df['Date'][(x <= df['Date'] )&
((x + dt_20) >= df['Date'])].count())
我想以后再去 好消息是可以将其矢量化。 坏消息是。。。这并不简单 以下是基准测试代码:
现在,
alt
在做什么?也许使用您发布的df
查看一个小示例最简单:
df = pd.DataFrame(pd.to_datetime(['2018-04-10 21:05:00',
'2018-04-10 21:05:00',
'2018-04-10 21:10:00',
'2018-04-10 21:15:00',
'2018-04-10 21:35:00']),columns = ['Date'])
主要思想是使用Series.rolling
执行滚动求和。当
Series有一个DatetimeIndex,Series。滚动
可以接受序列的时间频率
窗口大小。所以我们可以用固定的可变窗口计算滚动和
时间跨度。因此,第一步是使日期成为DatetimeIndex:
df['Date'] = pd.to_datetime(df['Date'])
df['num'] = 1
df = df.set_index('Date')
由于df
具有重复的日期,请按DatetimeIndex值分组并计算重复的数量:
dup_count = df.groupby(level=0)['num'].count()
# Date
# 2018-04-10 21:05:00 2
# 2018-04-10 21:10:00 1
# 2018-04-10 21:15:00 1
# 2018-04-10 21:35:00 1
# Name: num, dtype: int64
现在计算重复计数的滚动和:
result = dup_count.rolling('20T', closed='both').sum()
# Date
# 2018-04-10 21:05:00 2.0
# 2018-04-10 21:10:00 3.0
# 2018-04-10 21:15:00 4.0
# 2018-04-10 21:35:00 2.0
# Name: num, dtype: float64
维奥拉,那是nr\u 20\u min\u bef
。有20分钟长closed='both'
指定每个窗口都包括其左端点和右端点
现在,如果只计算nr\u 20\u min\u之后的就这么简单的话。理论上,我们所需要做的就是颠倒dup\u count
中的行的顺序,然后计算另一个滚动和。不幸的是,Series.rolling
要求DatetimeIndex单调递增:
由于明显的道路被堵塞,我们绕道而行:
max_date = df.index.max()
min_date = df.index.min()
dup_count_reversed = df.groupby((max_date - df.index)[::-1] + min_date)['num'].count()
# Date
# 2018-04-10 21:05:00 1
# 2018-04-10 21:25:00 1
# 2018-04-10 21:30:00 1
# 2018-04-10 21:35:00 2
# Name: num, dtype: int64
这将生成一个新的伪datetime DatetimeIndex,以便按以下方式分组:
In [288]: (max_date - df.index)[::-1] + min_date
Out[288]:
DatetimeIndex(['2018-04-10 21:05:00', '2018-04-10 21:25:00',
'2018-04-10 21:30:00', '2018-04-10 21:35:00',
'2018-04-10 21:35:00'],
dtype='datetime64[ns]', name='Date', freq=None)
这些值可能不在df.index
——但这没关系。我们唯一需要的是,值是单调递增的,并且日期时间之间的差异
当反转时,对应于df.index
中的差异
现在,使用此反向重复计数,我们可以通过采用滚动总和来享受大胜利(在性能方面):
result = dup_count_reversed.rolling('20T', closed='both').sum()
# Date
# 2018-04-10 21:05:00 1.0
# 2018-04-10 21:25:00 2.0
# 2018-04-10 21:30:00 2.0
# 2018-04-10 21:35:00 4.0
# Name: num, dtype: float64
result
具有我们希望的nr\u 20\u min\u后的值
,但顺序相反,
而且索引错误。以下是我们可以纠正的方法:
result = pd.Series(result.values[::-1], dup_count.index)
# Date
# 2018-04-10 21:05:00 4.0
# 2018-04-10 21:10:00 2.0
# 2018-04-10 21:15:00 2.0
# 2018-04-10 21:35:00 1.0
# dtype: float64
这基本上就是alt
发布文本的全部内容,而不是图片。并使用for-loop显示您的代码。谢谢您的建议。还添加了代码。感谢您的回答!如果在其他列中验证了特定条件,您是否知道一种只计算日期的解决方案?那么,如果在其他列中验证了某个特定字符串,那么要计算20分钟前后的日期数?因此,我们不仅要有nr_20_min_bef和nr_20_min_after列,还要有nr_20_min_bef_variablex和nr_20_min_after_variablex列(表示variablex在不到30分钟之前出现在行上的次数)。我不确定我是否完全理解这个新问题。但是如果你发布了一个新的问题和所有的细节(一个像你在这里提供的玩具例子非常感谢),我很乐意看一看。就这样做了。非常感谢你的帮助!给你:我假设这个解决方案可能与这里介绍的非常相似。但是,我并没有真正做到这一点。当应用于两个系列的日期时间值时,是否可以调整此解决方案?我的意思是:我们不计算同一系列中20分钟之前的日期数量,而是计算附加系列中20分钟之前和之后的值(而不是我们在本例中所做的当前系列)。一个简单的解决方案是迭代第一个系列的每个日期,并检查第二个系列前后20分钟的日期数。然而,由于它是一个100万行的表,这太耗时了。提前谢谢!
max_date = df.index.max()
min_date = df.index.min()
dup_count_reversed = df.groupby((max_date - df.index)[::-1] + min_date)['num'].count()
# Date
# 2018-04-10 21:05:00 1
# 2018-04-10 21:25:00 1
# 2018-04-10 21:30:00 1
# 2018-04-10 21:35:00 2
# Name: num, dtype: int64
In [288]: (max_date - df.index)[::-1] + min_date
Out[288]:
DatetimeIndex(['2018-04-10 21:05:00', '2018-04-10 21:25:00',
'2018-04-10 21:30:00', '2018-04-10 21:35:00',
'2018-04-10 21:35:00'],
dtype='datetime64[ns]', name='Date', freq=None)
result = dup_count_reversed.rolling('20T', closed='both').sum()
# Date
# 2018-04-10 21:05:00 1.0
# 2018-04-10 21:25:00 2.0
# 2018-04-10 21:30:00 2.0
# 2018-04-10 21:35:00 4.0
# Name: num, dtype: float64
result = pd.Series(result.values[::-1], dup_count.index)
# Date
# 2018-04-10 21:05:00 4.0
# 2018-04-10 21:10:00 2.0
# 2018-04-10 21:15:00 2.0
# 2018-04-10 21:35:00 1.0
# dtype: float64