Каков самый быстрый способ перебрать список критериев фильтра для пандой DataFrame и выполнить некоторые вычисления? - PullRequest
0 голосов
/ 15 января 2019

Я часто оказываюсь со списком фильтров, которые мне нужно применить к кадру данных 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

1 Ответ

0 голосов
/ 15 января 2019

Попробуйте использовать 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)

Не БОЛЬШАЯ разница, но в данном конкретном примере мы не можем добиться большего успеха ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...