Python 优化-数据帧聚合将在聚合过程中使用不同的过滤器:df.loc或not?

Python 优化-数据帧聚合将在聚合过程中使用不同的过滤器:df.loc或not?,python,python-3.x,pandas,dataframe,Python,Python 3.x,Pandas,Dataframe,我期待下面的聚合-理想情况下在一个单一的步骤。聚合列需要使用不同的过滤器进行计算,我想到了两种方法来实现这一点(请参见函数f1和f2)。我认为定义一个索引(如f2)会加快这个过程,但事实恰恰相反——不管数据帧的行数如何,聚合所需的时间大约要长2-3倍 为什么会这样?我认为.loc是推荐的方法。还有,还有第三种(比f1更快的)方法吗?我正在使用Python 3.6.4 import numpy as np import pandas as pd from collections import Or

我期待下面的聚合-理想情况下在一个单一的步骤。聚合列需要使用不同的过滤器进行计算,我想到了两种方法来实现这一点(请参见函数
f1
f2
)。我认为定义一个索引(如
f2
)会加快这个过程,但事实恰恰相反——不管数据帧的行数如何,聚合所需的时间大约要长2-3倍

为什么会这样?我认为
.loc
是推荐的方法。还有,还有第三种(比f1更快的)方法吗?我正在使用Python 3.6.4

import numpy as np
import pandas as pd
from collections import OrderedDict
import time

N = 10**5
df_big = pd.DataFrame({'grp': np.array(list(range(1,11)) * N),
                       'vals': np.random.randint(0,100, 10*N),
                       'var1': np.random.randint(10,30, 10*N)})

def f1(x):
    d = OrderedDict()
    d['vals_sum_1'] = np.sum(x['vals'][x['var1'] > 15])
    d['vals_mean_1'] = np.mean(x['vals'][x['var1'] > 15])
    d['vals_median_1'] = np.median(x['vals'][x['var1'] > 15])
    d['vals_sum_2'] = np.sum(x['vals'][x['var1'] > 20])
    d['vals_mean_2'] = np.mean(x['vals'][x['var1'] > 20])
    d['vals_median_2'] = np.median(x['vals'][x['var1'] > 20])    
    return pd.Series(d)

def f2(x):
    d = OrderedDict()
    idx1 = x.loc[x['var1'] > 15].index
    idx2 = x.loc[x['var1'] > 20].index
    d['vals_sum_1'] = np.sum(x['vals'][idx1])
    d['vals_mean_1'] = np.mean(x['vals'][idx1])
    d['vals_median_1'] = np.median(x['vals'][idx1])
    d['vals_sum_2'] = np.sum(x['vals'][idx2])
    d['vals_mean_2'] = np.mean(x['vals'][idx2])
    d['vals_median_2'] = np.median(x['vals'][idx2])   
    return pd.Series(d)  

start_time = time.time()
df_grp_1 = df_big.groupby('grp').apply(f1).reset_index()
gr1_time = time.time()
df_grp_2 = df_big.groupby('grp').apply(f2).reset_index()
gr2_time = time.time()

print("Using aggf1: %s seconds ---" % (gr1_time - start_time))
print("Using aggf2: %s seconds ---" % (gr2_time - gr1_time))

有许多重复的操作。通过删除重复索引,您可以看到~2倍因子的改善:

def f3(df):

    g1 = df.loc[df['var1'] > 15].groupby('grp')['vals']
    g2 = df.loc[df['var1'] > 20].groupby('grp')['vals']

    res = pd.DataFrame({'grp': df['grp'].unique()})

    for i, j in enumerate([g1, g2], 1):
        res['vals_sum_'+str(i)] = res['grp'].map(j.sum())
        res['vals_mean_'+str(i)] = res['grp'].map(j.mean())
        res['vals_median_'+str(i)] = res['grp'].map(j.median())

    return res

%timeit df_big.groupby('grp').apply(f1).reset_index()  # 349ms
%timeit df_big.groupby('grp').apply(f2).reset_index()  # 433ms
%timeit f3(df_big)                                     # 183ms
我的一步解决方案(虽然比@jpp慢一点)


回答得很好,这很有帮助。我可以问一下,这对
groupby
中的几个栏目会有什么作用,或者我应该发布一个新问题吗?我肯定这个方法可以扩展到更多栏目,但是可以-请作为一个新问题发布,这样我们就不会偏离您原来的问题。
df_big[df_big.var1 > 15]\
   .groupby('grp')\
   .vals.agg(['sum', 'mean', 'median'])\
   .rename(columns =
           {'sum': 'vals_sum_1',
            'mean': 'vals_mean_1',
            'median': 'vals_median_1'})\
   .join(
       df_big[df_big.var1 > 20]\
          .groupby('grp')\
          .vals.agg(['sum', 'mean', 'median'])\
          .rename(columns = 
                  {'sum': 'vals_sum_2',
                   'mean': 'vals_mean_2',
                   'median': 'vals_median_2'})
         ).reset_index()