Pandas Dataframe groupby 描述 8x ~比单独计算慢

Ran*_*win 16 python describe percentile quantile pandas

以下代码使用两种不同的方法汇总数字数据。

一种方法使用 Dataframe().describe() 并传递一些特定的额外百分位数。

第二种方法是分别计算的摘要统计(平均值,标准,N),它堆叠,计算相同的位数,然后由索引追加两个和排序所以结果是基本相同的第一种方法。

有一些细微的命名差异,我们可以清理后记,因为汇总数据很小,所以速度非常快。

事实证明,在这个例子中,使用 describe 函数大约慢了 8 倍。

我正在寻找原因以及可能会进一步加快速度的任何其他方法的建议(过滤器、组、值)都从 UI 传递到龙卷风服务 - 所以速度很重要,因为用户正在等待结果,并且数据可能比这个例子更大。

    import pandas as pd
    import numpy as np
    from datetime import datetime

    def make_data (n):
        
        ts = datetime.now().timestamp() + abs(np.random.normal(60, 30, n)).cumsum()
        
        df = pd.DataFrame({
            'c1': np.random.choice(list('ABCDEFGH'), n),
            'c2': np.random.choice(list('ABCDEFGH'), n),
            'c3': np.random.choice(list('ABCDEFGH'), n),
            't1': np.random.randint(1, 20, n),
            't2': pd.to_datetime(ts, unit='s'),
            'x1': np.random.randn(n),
            'x2': np.random.randn(n),
            'x3': np.random.randn(n)
            })
        
        return df
    
    def summarize_numeric_1 (df, mask, groups, values, quantiles): 
        
        dfg = df[mask].groupby(groups)[values]
        
        return dfg.describe(percentiles = quantiles).stack()
    
    def summarize_numeric_2 (df, filt, groups, values, quantiles): 
           
        dfg = df[mask].groupby(groups)[values]
    
        dfg_stats = dfg.agg([np.mean, np.std, len]).stack()
        dfg_quantiles = dfg.quantile(all_quantiles)
        
        return dfg_stats.append(dfg_quantiles).sort_index()

    %time df = make_data(1000000)
    
    groups = ['c1', 'c2', 't1']
    mask = df['c3'].eq('H') & df['c1'].eq('A')
    values = ['x1', 'x3']
    base_quantiles = [0, .5, 1] 
    extd_quantiles = [0.25, 0.75, 0.9]
    all_quantiles = base_quantiles + extd_quantiles
    
    %timeit summarize_numeric_1(df, mask, groups, values, extd_quantiles)
    %timeit summarize_numeric_2(df, mask, groups, values, all_quantiles)
Run Code Online (Sandbox Code Playgroud)

我的电脑上的时间是:

使用描述:每个循环 873 ms ± 8.9 ms(平均值 ± 标准差。7 次运行,每次 1 次循环)

使用两步法:每个循环 105 ms ± 490 µs(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

欢迎所有输入!

Sha*_*mis 1

有根据的猜测

我会将其作为答案发布,也许稍后会被删除,因为它更多的是有根据的猜测,而不是实际的答案。而且评论有点太长了。

因此,在阅读您的答案后,我做的第一件事就是在分析器中重新运行您的计时,以仔细研究问题。由于计算本身的时间相当短,因此它被数据生成所掩盖。但总的来说,时间与您所描述的类似。不仅如此,差异甚至更加明显:第一种方法需要
1094 毫秒,而第二种方法需要63 毫秒。这造成了 17 倍的差异。

由于较低的时间相当小,因此我认为它太小而无法信任,并使用 *10 生成的数据样本大小重新运行测试。它将数据生成步骤提高到一分钟,但数字变得很奇怪: 第一种方法为1173 毫秒,而第二种方法为506 毫秒。因数仅比二稍差一点。

我开始怀疑一些事情。为了证实我的怀疑,我再次运行了最后一次测试,将数据大小增加了 10 倍。结果可能会让您感到惊讶:第一种方法为
12258 毫秒,而第二种方法为3646 毫秒。情况已经完全逆转,系数约为 0.3。

在这种情况下,我的猜测是 pandas 计算实际上是具有更好优化/算法的计算。然而,由于它是 pandas,所以它有相当多的额外包袱 - 这是为了方便和稳健而付出的代价。这意味着存在一层“不必要的”(计算方面的)包袱,无论数据集有多大,都需要随身携带。

因此,如果您希望在您的大小的数据集上比 pandas 更快,请以最直接的方式自己编写它们的操作。这将保持他们的优化并放弃为方便而付费的行李。