3

编辑:

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

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

原问:

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

这对我来说不是最好的输出,因为我接下来需要按其中一个值进行排序,而且通常这种方式我失去了很多 DataFrame 和 Series 功能。

我想取而代之的是一个带有“a”和“b”列的数据框。

例如,假设一个大数据框 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()

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

6073165338_1 (6073165338, 94.5)

我希望输出是一个具有相同索引的数据框,并且两个值作为数据框中的列,这样我就可以轻松地进行分析。

我怎么做?

4

3 回答 3

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

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

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. 它只运行一次 DF 构造函数,在 groupby-apply 操作结束时
  2. 它不返回不必要的整数索引。
于 2013-10-24T08:34:42.587 回答
0

根据已编辑的问题,也许这就是您要寻找的。在应用调用结果中返回一系列被整理到数据框中(猜测这就是您要查找的内容)

返回一个元组

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

在第二个示例中,结果在数据框中

于 2013-10-23T20:04:15.807 回答
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
于 2013-10-24T08:53:39.510 回答