用熊猫在一个groupby调用中执行多项操作?

时间:2019-06-12 15:11:28

标签: python pandas pandas-groupby

我想按日期分组后产生一个摘要数据框。我想要一个列,它按原样显示给定列的平均值,并过滤掉大于0的实例后,显示同一列的平均值。我想出了如何做到这一点(如下),但是它需要这样做两个单独的groupby调用,重命名这些列,然后将它们重新结合在一起。我跌倒了,一个人应该能够一次完成所有操作。我试图使用eval来执行此操作,但一直出现错误,并被告知要使用apply,无法在groupby对象上使用eval

代码可以让我得到我想要的东西,但效率似乎不高:

# Sample data

data = pd.DataFrame(
          {"year" : [2013, 2013, 2013, 2014, 2014, 2014],
           "month" : [1, 2, 3, 1, 2, 3],
           "day": [1, 1, 1, 1, 1, 1],
           "delay": [0, -4, 50, -60, 9, 10]})

subset = (data
          .groupby(['year', 'month', 'day'])['delay']
          .mean()
          .reset_index()
          .rename(columns = {'delay' : 'avg_delay'})
         )

subset_1 = (data[data.delay > 0]
          .groupby(['year', 'month', 'day'])['delay']
          .mean()
          .reset_index()
          .rename(columns = {'delay' : 'avg_delay_pos'})
         )

combined = pd.merge(subset, subset_1, how='left', on=['year', 'month', 'day'])
combined

   year  month  day  avg_delay  avg_delay_pos
0  2013      1    1          0            NaN
1  2013      2    1         -4            NaN
2  2013      3    1         50           50.0
3  2014      1    1        -60            NaN
4  2014      2    1          9            9.0
5  2014      3    1         10           10.0

2 个答案:

答案 0 :(得分:1)

IIUC,您可以使用以下代码:

delay

说明:

  • 我首先删除avg_delay列,并将其分配给新名称delay,所以我实际上将avg_delay的名称重命名为avg_delay_pos

  • 然后,我创建一个名为loc的新列,该列首先使用avg_delay来获取大于零的值,并且由于索引不会重置,因此它将创建索引值大于NaN的值大于零,而其他值将不包含任何赋值,即它们将是您期望的{{1}}。

答案 1 :(得分:0)

该解决方案特定于您的问题,但是您可以使用单个groupby调用来实现。要获取“ avg_delay_pos”,您只需删除负(和零)值即可。

df['delay_pos'] = df['delay'].where(df['delay'] > 0)

(df.filter(like='delay')
   .groupby(pd.to_datetime(df[['year', 'month', 'day']]))
   .mean()
   .add_prefix('avg_'))                                                                                                                                 

            avg_delay  avg_delay_pos
2013-01-01          0            NaN
2013-02-01         -4            NaN
2013-03-01         50           50.0
2014-01-01        -60            NaN
2014-02-01          9            9.0
2014-03-01         10           10.0

故障

where用于屏蔽非正值。

df['delay_pos'] = df['delay'].where(df['delay'] > 0)
# df['delay'].where(df['delay'] > 0)                                                                                                  

0     NaN
1     NaN
2    50.0
3     NaN
4     9.0
5    10.0
Name: delay, dtype: float64

接下来,提取我们要分组的延迟列,

df.filter(like='delay')                                                                                                             

   delay  delay_pos
0      0        NaN
1     -4        NaN
2     50       50.0
3    -60        NaN
4      9        9.0
5     10       10.0

然后在该日期执行groupby

_.groupby(pd.to_datetime(df[['year', 'month', 'day']])).mean()

            delay  delay_pos
2013-01-01      0        NaN
2013-02-01     -4        NaN
2013-03-01     50       50.0
2014-01-01    -60        NaN
2014-02-01      9        9.0
2014-03-01     10       10.0

在使用pd.to_datetime将年/月/日列转换为单个datetime列的情况下,对单个列进行分组比对多个列进行分组更为有效。

pd.to_datetime(df[['year', 'month', 'day']])                                                                                        

0   2013-01-01
1   2013-02-01
2   2013-03-01
3   2014-01-01
4   2014-02-01
5   2014-03-01
dtype: datetime64[ns]

最后的.add_prefix('avg_')向结果添加前缀“ _avg”。


如果您想要单独的年/月/日列,则可以采用另一种方法

df['delay_pos'] = df['delay'].where(df['delay'] > 0)
df.groupby(['year', 'month', 'day']).mean().add_prefix('avg_').reset_index()

   year  month  day  avg_delay  avg_delay_pos
0  2013      1    1          0            NaN
1  2013      2    1         -4            NaN
2  2013      3    1         50           50.0
3  2014      1    1        -60            NaN
4  2014      2    1          9            9.0
5  2014      3    1         10           10.0