【问题标题】:Parallelize pandas apply并行化 pandas 应用
【发布时间】:2017-01-10 03:10:52
【问题描述】:

熊猫新手,我已经想并行化逐行应用操作。到目前为止我找到了Parallelize apply after pandas groupby 但是,这似乎只适用于分组数据帧。

我的用例不同:我有一个假期列表,对于我当前的行/日期,我想查找这一天之前和之后到下一个假期的非天数。

这是我通过 apply 调用的函数:

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 池进行了一些实验 - 但它既不是很好的代码,也没有得到我的计算结果。

【问题讨论】:

  • "python 池" - 线程还是进程?
  • 我使用的是 multiprocessing.Pool(processes= #ofCPU)
  • 因此不能保证多处理可以加快您的代码速度,但是,由于代码不能正常工作,所以很难知道它在那里运行的是什么。您可能想对此提出问题(FWIW,这种方法对我来说似乎是您最好的选择)。
  • 在应用并行化之前,cythonizing 不是一个好的第一步吗?
  • 据我了解的问题是令人尴尬的并行,例如每一行都是独立的,所以应该更适合并行执行。

标签: python pandas parallel-processing apply embarrassingly-parallel


【解决方案1】:

我认为pandarallel 包现在更容易做到这一点。没有深入研究,但应该可以解决问题。

【讨论】:

    【解决方案2】:

    对于并行方法,这是基于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)

    【讨论】:

      【解决方案3】:

      我认为沿着并行尝试的方式可能过于复杂了。我没有在大样本上尝试过这种方法,所以你的里程可能会有所不同,但它应该给你一个想法......

      让我们从一些日期开始...

      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 进行计算,但它应该作为(我希望)一个相对良好的基础。

      【讨论】:

      • 我用您的代码更新了最小示例(请参阅引导程序)。尝试在假期使用“我的 dateimeIndices”时收到超出范围的索引。
      • 评论不用于扩展讨论;这个对话是moved to chat
      猜你喜欢
      • 2014-11-29
      • 1970-01-01
      • 2017-03-14
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 2021-02-10
      相关资源
      最近更新 更多