想象一下,我有一些熊猫数据框,如下所示:
creationDate
188080 2019-08-01 21:28:39+03:00
188081 2019-08-01 21:33:13+03:00
188082 2019-08-01 21:39:53+03:00
188083 2019-08-01 21:43:24+03:00
188084 2019-08-01 21:48:17+03:00
188085 2019-08-01 21:52:56+03:00
188086 2019-08-01 21:58:27+03:00
188087 2019-08-01 22:10:50+03:00
188088 2019-08-01 22:14:58+03:00
188089 2019-08-01 22:17:43+03:00
我想创建一个名为density
的新列。对于每一行,它表示“在当前单元格creationDate
之后和当前单元格creationDate
+ 1 hour
之前有多少行”
我具有矢量化功能,但是在我的数据集(约1.500.000行)上,它的运行速度不是很快(在笔记本电脑上花费了大约5分钟)。
def get_density(date, distance_in_minute):
start_datetime = date
end_datetime = date + np.timedelta64(distance_in_minute, 'm')
return df.loc[
(df['creationDate'] >= str(start_datetime)) & (df['creationDate'] < str(end_datetime))
].shape[0]
np_get_density = np.vectorize(lambda x: get_density(x, 60))
df['density'] = np_get_density(df['creationDate'])
如何优化此查询?预先感谢!
答案 0 :(得分:1)
这似乎是使用map
的{{1}}方法的不错选择。 multiprocessing.Pool
函数本质上将是辅助函数。
但是,一个辅助函数只能得到一个参数,最好还提供一个对数据帧的引用。因此,在将结果用作辅助函数之前,请使用get_density
向functools.partial
提供distance_in_minute
和数据帧。
在最佳情况下,如果您的CPU具有 N 个内核,这将使其速度快大约 N 倍。因此,如果您有4核CPU,则时间应该从5分钟缩短到大约1.25分钟。
答案 1 :(得分:1)
如何使用 Dask 。它是用于python中并行计算的库,并且比纯python快得多。
一些笔记(很好)-
1)它不支持多义化。
2)应将适当的数据类型分配给列。
from dask import dataframe as dd
from multiprocessing import cpu_count
import pandas as pd
df=df.reset_index()
df.creationDate=pd.DataFrame(df.creationDate)
def get_density(date):
distance_in_minute=60
start_datetime = date
end_datetime = pd.to_datetime(date) + np.timedelta64(distance_in_minute, 'm')
return (df.loc[
(df['creationDate'] >= str(start_datetime)) & (df['creationDate'] < str(end_datetime))
].shape[0])
nCores = cpu_count()
dd=dd.from_pandas(df,npartitions=nCores)
dd['density']=dd.creationDate.apply(get_density,meta=('density', int))
df=dd.compute()
np.vectorize()
比df.apply
更好的解决方案。
您可以尝试以下操作:
df['density']=(df.apply(lambda x: get_density(x.creationDate),axis=1))
答案 2 :(得分:1)
创建带有datetimeIndex
的系列后,您可以一次使用rolling
。因为您想及时向前看,所以您需要先反转索引的顺序,方法是将每个日期和最大值之间的时间增量添加到随机日期,一旦您用{{1}反转了列creationDate的顺序}。这是一种方法:
[::-1]
你会得到
df['density'] = (pd.Series(1, #create a Series with 1 as value but you can use anything
# index need a start date, anyone is fine
index= pd.to_datetime("today") +
# time delta between each rows once reverse and the max
(df.creationDate.max() - df.creationDate[::-1]))
.rolling('20T') # with the given data, I use 20 minutes as interval,
# change it to 1H for 1 hour, or 60T
.count() #count the number of rows within the rolling window
.values[::-1]) #reverse the values to come back to the original order