Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用pandas在单个groupby调用中执行多个操作?_Python_Pandas_Pandas Groupby - Fatal编程技术网

Python 使用pandas在单个groupby调用中执行多个操作?

Python 使用pandas在单个groupby调用中执行多个操作?,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我想在按日期分组后生成一个摘要数据框。我希望有一列显示给定列的实际平均值,以及过滤大于0的实例后该列的平均值。我知道了如何做到这一点(见下文),但这需要执行两个单独的groupby调用,重命名列,然后将它们重新连接在一起。我觉得一个人应该可以在一个电话里完成这一切。我试图使用eval来执行此操作,但不断出现错误,并被告知使用apply,我无法在groupby对象上使用eval 代码可以满足我的需求,但似乎效率不高: # Sample data data = pd.DataFrame(

我想在按日期分组后生成一个摘要数据框。我希望有一列显示给定列的实际平均值,以及过滤大于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

解决方案是针对您的问题的,但您可以使用单个groupby调用来实现这一点。要获得“avg_delay_pos”,只需删除负值(和零值)


细分

其中
用于屏蔽非正值

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]
最后的
。添加前缀(“avg”)
在结果中添加前缀“\u 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

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

>>> data['avg_delay'] = data.pop('delay')
>>> data['avg_delay_pos'] = data.loc[data['avg_delay'].gt(0), 'avg_delay']
>>> data
   day  month  year  avg_delay  avg_delay_pos
0    1      1  2013          0            NaN
1    1      2  2013         -4            NaN
2    1      3  2013         50           50.0
3    1      1  2014        -60            NaN
4    1      2  2014          9            9.0
5    1      3  2014         10           10.0
>>> 
说明:

  • 我首先删除了
    delay
    列,并将其分配给新名称
    avg\u delay
    ,因此我实际上将
    delay
    的名称重命名为
    avg\u delay

  • 然后我创建了一个名为
    avg_delay\u pos
    的新列,它首先使用
    loc
    获取大于零的值,由于索引不会重置,因此它会将大于零的索引设置为
    avg_delay
    的值,而其他索引则不包含任何赋值,也就是说,他们将像您预期的那样
    NaN


可用的样本数据将使这一问题更容易回答。阅读后,你可以编写自己的函数来处理所有的事情,并使用
apply
。可能
combined=data.groupby(['year','month','day'])['delay','pos'].mean().reset_index().rename(columns={'delay':'avg_delay','pos':'avg_delay_pos})就足够了。但如果没有一些数据,我无法确定……添加了示例数据我想我学到的是,这些类型的操作不能在一行中完成。@BenG这是怎么正确的,为什么正确?您得到与groupby解决方案相同答案的唯一原因是,日历日期在示例数据中是唯一的。我认为这是显而易见的。我想我学到的是这些类型的操作不能在一行中完成。@BenG-PS,你可以在一行中做任何你想做的事情。我的第二种方法可以简化为
df.assign(delay_pos=df['delay']].where(df['delay']>0)).groupby(['year','month','day']).mean().add_prefix('avg_').reset_index()
,这是一行。为了清晰起见,我将其扩展为两个。这不是我该说的,但我觉得你已经放弃了你的赏金:(
>>> data['avg_delay'] = data.pop('delay')
>>> data['avg_delay_pos'] = data.loc[data['avg_delay'].gt(0), 'avg_delay']
>>> data
   day  month  year  avg_delay  avg_delay_pos
0    1      1  2013          0            NaN
1    1      2  2013         -4            NaN
2    1      3  2013         50           50.0
3    1      1  2014        -60            NaN
4    1      2  2014          9            9.0
5    1      3  2014         10           10.0
>>>