【问题标题】:What is the fastest way to loop over a list of filter criteria for a pandas DataFrame and do some calculations?循环遍历 pandas DataFrame 的过滤条件列表并进行一些计算的最快方法是什么?
【发布时间】:2019-06-09 18:52:38
【问题描述】:

我经常发现自己有一个需要应用于 pandas 数据框的过滤器列表。我应用每个过滤器并进行一些计算,但这通常会导致代码变慢。我想优化性能。我创建了一个慢速解决方案的示例,它在日期范围列表上过滤数据框并计算与我的日期范围匹配的行的列的总和,然后将此值分配给与日期范围开始匹配的日期:

import numpy as np
import pandas as pd
import datetime


def generateTestDataFrame(N=50, windowSizeInDays=5):
    dd = {"AsOfDate" : [],
            "WindowEndDate" : [],
            "X" : []}

    d = datetime.date.today()

    for i in range(N):

        dd["AsOfDate"].append(d)
        dd["WindowEndDate"].append(d + datetime.timedelta(days=windowSizeInDays))
        dd["X"].append(float(i))

        d = d + datetime.timedelta(days=1)

    newDf = pd.DataFrame(dd)
    return newDf

def run():
    numRows = 50
    windowSizeInDays = 5

    print "NumRows: %s" % (numRows)
    print "WindowSizeInDays: %s" % (windowSizeInDays)

    df = generateTestDataFrame(numRows, windowSizeInDays)

    newAggColumnName = "SumOverNdays"
    df[newAggColumnName] = np.nan  # Initialize the column to nan

    for i in range(df.shape[0]):
        row_i = df.iloc[i]
        startDate = row_i["AsOfDate"]
        endDate = row_i["WindowEndDate"]
        sumAggOverNdays = df.loc[ (df["AsOfDate"] >= startDate) & (df["AsOfDate"] < endDate) ]["X"].sum()
        df.loc[df["AsOfDate"] == startDate, newAggColumnName] = sumAggOverNdays  

    print df.head(10)

if __name__ == "__main__":
    run()

这会产生以下输出:

NumRows: 50
WindowSizeInDays: 5
     AsOfDate WindowEndDate    X  SumOverNdays
0  2019-01-15    2019-01-20  0.0          10.0
1  2019-01-16    2019-01-21  1.0          15.0
2  2019-01-17    2019-01-22  2.0          20.0
3  2019-01-18    2019-01-23  3.0          25.0
4  2019-01-19    2019-01-24  4.0          30.0
5  2019-01-20    2019-01-25  5.0          35.0
6  2019-01-21    2019-01-26  6.0          40.0
7  2019-01-22    2019-01-27  7.0          45.0
8  2019-01-23    2019-01-28  8.0          50.0
9  2019-01-24    2019-01-29  9.0          55.0

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    尝试使用 pandas.DataFrame.apply() 进行计算。

    文档:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html

    使用您的代码:

    %%timeit
    run()
    205 ms ± 33.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    适应:

    %%timeit
    windowSizeInDays = 5
    rows = 50
    df_ = pd.DataFrame(index=range(rows),columns=['AsOfDate','WindowEndDate','X','SumOverNdays'])
    asofdate = [datetime.date.today() + datetime.timedelta(days=i) for i in range(rows)]
    windowenddate = [i + datetime.timedelta(days=windowSizeInDays) for i in asofdate]
    
    df_['AsOfDate'] = asofdate
    df_['WindowEndDate'] = windowenddate
    df_['X'] = np.arange(float(df_.shape[0]))
    df_['SumOverNdays'] = df_.apply(lambda x: df_.loc[ (df_["AsOfDate"] >= x['AsOfDate']) & (df_["AsOfDate"] < x['WindowEndDate']) ]["X"].sum(), axis=1)
    df_
    112 ms ± 3.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    没有差异,但在这个特定的例子中,我们不能做得比这更好......

    【讨论】:

    • 这只是一个 Python 级别的循环。对于干净的数据,就像这里一样,它通常不会比等效的列表理解快,并且不应该用作优化性能的手段。
    • 是的,我使用了“应用”,但我想知道如何使用它来解决我上面发布的代码?我仍然需要创建过滤数据框来应用我想要的计算。我认为它正在创建副本或其他东西,这就是为什么它很慢。
    • 知道了,我使用 apply 快速编写了代码...我将编辑我的帖子。
    猜你喜欢
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2023-03-24
    • 2023-03-29
    • 2011-07-17
    相关资源
    最近更新 更多