从多个返回值groupby-apply操作输出DataFrame而不是Series

时间:2013-10-23 15:51:52

标签: python pandas

编辑:

我需要apply函数,它从几个复杂的计算中返回几个值。我可以在元组中返回这些值,因此groupby-apply操作的结果将是一个以组名作为索引而元组作为值的系列。我希望它能返回一个DataFrame,所以我可以保留所有pandas的功能和灵活性。

通常,groupby-apply操作的结果将是一个系列在应用返回1值的情况下。在应用返回2个或更多值的情况下,我希望结果是一个数据帧。所以我的问题是如何做到这一点。有关更多详细信息和示例,请参阅原始版本

原文问:

我有一个包含许多列和组的数据框。我试图通过groupby-apply机制进行分组操作,并且每个组只检索2个值。目前,我为每个组返回一个元组(例如return (a,b)),因此Im得到的结果是一个系列,其中组名称作为索引,tupels作为值。

这对我来说不是最好的输出,因为我接下来需要按照其中一个值进行排序,并且通常这种方式会丢失大部分DataFrame和Series功能。

我想要取回的是一个带有列' a'的数据框架。和' b'。

例如,假设a有一个大的数据帧df看起来像这样:

Out[123]:
         ID1            ID2     score
0    6073165338_1    6073165338  100
1    6073165338_1    6073165338  89
2    6073165338_1    6073165338  87
3    6073165338_1    6073165338  65
4    6073165338_1    6073165338  62

我想按ID1对其进行分组,并为每个组返回ID2(对于每个ID1组都是相同的) 和前3个参赛作品的平均分。我可以这样做:

def calc(grp):
    return grp.ID2.iloc[0],grp.score[:2].mean()

df.groupby('ID1').apply(calc)的结果应该是ID1组作为索引的系列,以及带有2个元素作为值的元组:

6073165338_1(6073165338,94.5)

我希望输出是一个具有相同索引的数据帧,两个值作为数据框中的列,因此我可以轻松地保持分析。

我该怎么做?

3 个答案:

答案 0 :(得分:1)

好的,我有两个解决方案。第一个可能更好,我仍然感谢专家的评论。第一个选项是让应用函数返回一个元组,然后将元组序列转换为DataFrame:

s = x.groupby('ID1').apply(calc)
DataFrame(s.tolist(),index = s.index,columns = ['ID2','top3avg'])

这导致:

Out[156]:
                     ID2    top3avg
ID1     
6073165338_1     6073165338  94.5

第二个是使用返回的元组上的dataframe构造函数返回数据帧:

def calc(grp):
    return DataFrame([(grp.ID2.iloc[0],grp.score[:2].mean())],columns=['ID2','top3avg'])

x.groupby('ID1').apply(calc)的结果现在是一个数据框:

                         ID2    top3avg
ID1         
6073165338_1    0    6073165338  94.5

第一个选项似乎更好:

  1. 它只在groupby-apply操作结束时运行DF构造函数一次
  2. 它不返回不必要的整数索引。

答案 1 :(得分:0)

根据编辑过的问题,也许这就是你要找的东西。在apply调用结果中返回一个系列被整理成一个数据框(猜测这就是你要找的东西)

返回元组

In [721]: x.groupby('ID1').apply(lambda df: (df['ID2'].irow(0), df['score'].irow(0)))
Out[721]:
ID1
6073165338_1    (6073165338, 100)
dtype: object

返回一个系列

In [720]: x.groupby('ID1').apply(lambda df: pd.Series({'c1':df['ID2'].irow(0), 'c2':df['score'].irow(0)}))
Out[720]:
                  c1   c2
ID1
6073165338_1  6073165338  100

在第二个示例中,结果位于数据帧

答案 2 :(得分:0)

首先,看起来你的例子平均超过2个元素,而不是3 - (100 + 89 + 87)/ 3 = 92,(100 + 89)/ 2 = 94.5。

至于你的例子,我认为可以通过在数据帧上获得简单的mean()来完成,其中每个组只剩下前3行。例如,像这样:

df.groupby('ID1').head(3).groupby('ID1').mean()

示例:

>>> df = pd.DataFrame({"ID1":['6073165338_1']*5 + [11111] * 6, "ID2":[6073165338 ]*5 + [22222] * 6, "score":[100,89,87,65,62] + [1, 2, 3, 4, 5, 6]})
>>> df
             ID1         ID2  score
0   6073165338_1  6073165338    100
1   6073165338_1  6073165338     89
2   6073165338_1  6073165338     87
3   6073165338_1  6073165338     65
4   6073165338_1  6073165338     62
5          11111       22222      1
6          11111       22222      2
7          11111       22222      3
8          11111       22222      4
9          11111       22222      5
10         11111       22222      6

>>> df.groupby('ID1').head(3).groupby('ID1').mean()
                     ID2  score
ID1                            
11111              22222      2
6073165338_1  6073165338     92