【问题标题】:Pandas Date Groupby & Apply - performance improvementPandas Date Groupby & Apply - 性能提升
【发布时间】:2019-09-08 23:37:59
【问题描述】:

我正在做一个半小时的约会 groupby 并申请计算我的数据集的每日统计信息,但它很慢。有没有办法提高以下功能的性能?我读过矢量化,但不确定如何实现它。

我已经使用 apply 和 transform 来获得我想要的输出,但是一整年的数据大约需要 2-3 秒,我希望做得更快,因为我有很多数据。任何人都可以指出正确的方向吗?

import pandas as pd
import numpy as np
import timeit

# dummy data
date_range = pd.date_range('2017-01-01 00:00', '2018-01-01 00:00', freq='30Min')
df = pd.DataFrame(np.random.randint(2, 20, (date_range.shape[0], 2)), index=date_range, columns=['Electricity', 'Natural Gas'])

print(df.head())
print(df.shape)

t1 = timeit.default_timer()
onhour = df.groupby([pd.Grouper(freq='D')]).apply(lambda x: np.count_nonzero(
    x[x > x.quantile(0.05) + x.mean() * .1] >
    x.quantile(0.05) + 0.25 * (x.quantile(0.95)-x.quantile(0.05)),
    axis=0) / 2)

onhour = pd.DataFrame(
    onhour.values.tolist(),
    index=onhour.index,
    columns=df.columns)

print(f"start_time in {timeit.default_timer() - t1}")
print(onhour.head())

t1 = timeit.default_timer()
onhour = df.groupby([pd.Grouper(freq='D')]).transform(lambda x: np.count_nonzero(
    x[x > x.quantile(0.05) + x.mean() * .1] >
    x.quantile(0.05) + 0.25 * (x.quantile(0.95)-x.quantile(0.05)),
    axis=0) / 2).resample('D').mean()

print(f"start_time in {timeit.default_timer() - t1}")
print(onhour.head())

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    您已经在使用 pandas 矢量化优化,因此您无法获得很多时间,但一些技巧可以让您在 1.5 秒内完成。

    1) 使用 agg

    使用agg 代替transformapply 会得到更好的结果,因为you have the same computation for each column (electricity & gas)

    2) 保存分位数计算。

    您计算的是 5% 分位数的 3 倍。我使用了 python function 而不是 lambda,如果你添加一个记忆分位数函数,你仍然可以使用 lambda(它实际上可以帮助紧固,但我敢肯定)。

    def count_something(row):
        qt_df = row.quantile([0.05, 0.95])
        return np.count_nonzero(
            row[row > qt_df.loc[0.05] + row.mean() * .1] > qt_df.loc[0.05] + 0.25 * (qt_df.loc[0.95] - qt_df.loc[0.05]),
            axis=0) / 2
    
    t1 = timeit.default_timer()
    
    onhour = df.groupby([pd.Grouper(freq='D')]).agg(count_something)
    
    print(f"start_time in {timeit.default_timer() - t1}")
    print(onhour.head())
    

    如果您真的想加快计算速度并且您有办法并行化或分发您的计算,我想您可以使用python dask,但我不知道它可以在多大程度上改善您的问题。

    【讨论】:

    • 啊,是的,完美。这总共节省了很多时间。未来可能会有 dask 的空间!使用 lambda 代替函数似乎稍微快一些。
    • 我还尝试查看计算中位数(50% 分位数)是否比平均值快 - 因为它是一个非常好的近似值,没有偏斜的数据。令我惊讶的是,它似乎并没有更快,但我没有进行稳健的测试......
    猜你喜欢
    • 2021-08-12
    • 2020-06-05
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-08-24
    • 2018-04-17
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多