并行化 pandas 申请
Parallelize pandas apply
pandas 的新手,我已经想并行化逐行应用操作。到目前为止,我发现 Parallelize apply after pandas groupby 但是,这似乎只适用于分组数据帧。
我的用例不同:我有一个假期列表,对于我当前的row/date,我想找到从这一天到下一个假期前后的休息日。
这是我通过应用调用的函数:
def get_nearest_holiday(x, pivot):
nearestHoliday = min(x, key=lambda x: abs(x- pivot))
difference = abs(nearesHoliday - pivot)
return difference / np.timedelta64(1, 'D')
我怎样才能加快速度?
编辑
我对 pythons 池进行了一些试验 - 但它既不是很好的代码,也没有得到我的计算结果。
我认为沿着并行尝试的路线走下去可能会使事情复杂化。我没有在大样本上尝试过这种方法,所以你的里程可能会有所不同,但它应该给你一个想法......
让我们从一些日期开始...
import pandas as pd
dates = pd.to_datetime(['2016-01-03', '2016-09-09', '2016-12-12', '2016-03-03'])
我们将使用来自 pandas.tseries.holiday
的一些假期数据 - 请注意,实际上我们想要一个 DatetimeIndex
...
from pandas.tseries.holiday import USFederalHolidayCalendar
holiday_calendar = USFederalHolidayCalendar()
holidays = holiday_calendar.holidays('2016-01-01')
这给了我们:
DatetimeIndex(['2016-01-01', '2016-01-18', '2016-02-15', '2016-05-30',
'2016-07-04', '2016-09-05', '2016-10-10', '2016-11-11',
'2016-11-24', '2016-12-26',
...
'2030-01-01', '2030-01-21', '2030-02-18', '2030-05-27',
'2030-07-04', '2030-09-02', '2030-10-14', '2030-11-11',
'2030-11-28', '2030-12-25'],
dtype='datetime64[ns]', length=150, freq=None)
现在我们使用 searchsorted
:
找到与原始日期最近的最近假期的索引
indices = holidays.searchsorted(dates)
# array([1, 6, 9, 3])
next_nearest = holidays[indices]
# DatetimeIndex(['2016-01-18', '2016-10-10', '2016-12-26', '2016-05-30'], dtype='datetime64[ns]', freq=None)
然后取两者的差:
next_nearest_diff = pd.to_timedelta(next_nearest.values - dates.values).days
# array([15, 31, 14, 88])
您需要注意索引,以免回绕,对于前一个日期,请使用 indices - 1
进行计算,但它应该作为(我希望)相对良好的基础。
对于并行方法,这是基于 Parallelize apply after pandas groupby:
的答案
from joblib import Parallel, delayed
import multiprocessing
def get_nearest_dateParallel(df):
df['daysBeforeHoliday'] = df.myDates.apply(lambda x: get_nearest_date(holidays.day[holidays.day < x], x))
df['daysAfterHoliday'] = df.myDates.apply(lambda x: get_nearest_date(holidays.day[holidays.day > x], x))
return df
def applyParallel(dfGrouped, func):
retLst = Parallel(n_jobs=multiprocessing.cpu_count())(delayed(func)(group) for name, group in dfGrouped)
return pd.concat(retLst)
print ('parallel version: ')
# 4 min 30 seconds
%time result = applyParallel(datesFrame.groupby(datesFrame.index), get_nearest_dateParallel)
但我更喜欢@NinjaPuppy 的方法,因为它不需要 O(n * number_of_holidays)
我认为 pandarallel 软件包现在可以更轻松地执行此操作。没有深入研究,但应该可以解决问题。
pandas 的新手,我已经想并行化逐行应用操作。到目前为止,我发现 Parallelize apply after pandas groupby 但是,这似乎只适用于分组数据帧。
我的用例不同:我有一个假期列表,对于我当前的row/date,我想找到从这一天到下一个假期前后的休息日。
这是我通过应用调用的函数:
def get_nearest_holiday(x, pivot):
nearestHoliday = min(x, key=lambda x: abs(x- pivot))
difference = abs(nearesHoliday - pivot)
return difference / np.timedelta64(1, 'D')
我怎样才能加快速度?
编辑
我对 pythons 池进行了一些试验 - 但它既不是很好的代码,也没有得到我的计算结果。
我认为沿着并行尝试的路线走下去可能会使事情复杂化。我没有在大样本上尝试过这种方法,所以你的里程可能会有所不同,但它应该给你一个想法......
让我们从一些日期开始...
import pandas as pd
dates = pd.to_datetime(['2016-01-03', '2016-09-09', '2016-12-12', '2016-03-03'])
我们将使用来自 pandas.tseries.holiday
的一些假期数据 - 请注意,实际上我们想要一个 DatetimeIndex
...
from pandas.tseries.holiday import USFederalHolidayCalendar
holiday_calendar = USFederalHolidayCalendar()
holidays = holiday_calendar.holidays('2016-01-01')
这给了我们:
DatetimeIndex(['2016-01-01', '2016-01-18', '2016-02-15', '2016-05-30',
'2016-07-04', '2016-09-05', '2016-10-10', '2016-11-11',
'2016-11-24', '2016-12-26',
...
'2030-01-01', '2030-01-21', '2030-02-18', '2030-05-27',
'2030-07-04', '2030-09-02', '2030-10-14', '2030-11-11',
'2030-11-28', '2030-12-25'],
dtype='datetime64[ns]', length=150, freq=None)
现在我们使用 searchsorted
:
indices = holidays.searchsorted(dates)
# array([1, 6, 9, 3])
next_nearest = holidays[indices]
# DatetimeIndex(['2016-01-18', '2016-10-10', '2016-12-26', '2016-05-30'], dtype='datetime64[ns]', freq=None)
然后取两者的差:
next_nearest_diff = pd.to_timedelta(next_nearest.values - dates.values).days
# array([15, 31, 14, 88])
您需要注意索引,以免回绕,对于前一个日期,请使用 indices - 1
进行计算,但它应该作为(我希望)相对良好的基础。
对于并行方法,这是基于 Parallelize apply after pandas groupby:
的答案from joblib import Parallel, delayed
import multiprocessing
def get_nearest_dateParallel(df):
df['daysBeforeHoliday'] = df.myDates.apply(lambda x: get_nearest_date(holidays.day[holidays.day < x], x))
df['daysAfterHoliday'] = df.myDates.apply(lambda x: get_nearest_date(holidays.day[holidays.day > x], x))
return df
def applyParallel(dfGrouped, func):
retLst = Parallel(n_jobs=multiprocessing.cpu_count())(delayed(func)(group) for name, group in dfGrouped)
return pd.concat(retLst)
print ('parallel version: ')
# 4 min 30 seconds
%time result = applyParallel(datesFrame.groupby(datesFrame.index), get_nearest_dateParallel)
但我更喜欢@NinjaPuppy 的方法,因为它不需要 O(n * number_of_holidays)
我认为 pandarallel 软件包现在可以更轻松地执行此操作。没有深入研究,但应该可以解决问题。