【问题标题】:Find half of each group with Pandas GroupBy用 Pandas GroupBy 找出每组的一半
【发布时间】:2017-11-30 23:56:11
【问题描述】:

我需要使用groupby 选择数据框的一半,其中每个组的大小是未知的,并且可能因组而异。例如:

       index  summary  participant_id
0     130599     17.0              13
1     130601     18.0              13
2     130603     16.0              13
3     130605     15.0              13
4     130607     15.0              13
5     130609     16.0              13
6     130611     17.0              13
7     130613     15.0              13
8     130615     17.0              13
9     130617     17.0              13
10     86789     12.0              14
11     86791      8.0              14
12     86793     21.0              14
13     86795     19.0              14
14     86797     20.0              14
15     86799      9.0              14
16     86801     10.0              14
20    107370      1.0              15
21    107372      2.0              15
22    107374      2.0              15
23    107376      4.0              15
24    107378      4.0              15
25    107380      7.0              15
26    107382      6.0              15
27    107597      NaN              15
28    107384     14.0              15

groupyby('participant_id') 的组大小分别为 10、7、9,participant_id 13、14、15。我只需要每组的前一半(或地板(N/2))。

根据我对 Pandas groupby 的(非常有限的)经验,应该是这样的:

df.groupby('participant_id')[['summary','participant_id']].apply(lambda x: x[:k_i])

其中k_i 是每个组大小的一半。有没有找到k_i的简单解决方案?

【问题讨论】:

  • 当你说“取每组的前半部分”时:你关心数据是如何排序的吗?即,您是先按index 还是summary 排序,然后取每组的前半部分?
  • @BradSolomon,您可以忽略index,“第一”是指(例如,如果每组中有 10 行)每组只取前 5 行。有帮助吗?
  • df.groupby('participant_id').apply(lambda x: x[:len(x)//2]) 怎么样?

标签: python pandas pandas-groupby split-apply-combine


【解决方案1】:

IIUC,您可以在 lambda 内使用大小为 //2 的索引切片:

df.groupby('participant_id').apply(lambda x: x.iloc[:x.participant_id.size//2])

输出:

                    index  summary  participant_id
participant_id                                    
13             0   130599     17.0              13
               1   130601     18.0              13
               2   130603     16.0              13
               3   130605     15.0              13
               4   130607     15.0              13
14             10   86789     12.0              14
               11   86791      8.0              14
               12   86793     21.0              14
15             20  107370      1.0              15
               21  107372      2.0              15
               22  107374      2.0              15
               23  107376      4.0              15

【讨论】:

  • 不错的答案,您可能还想考虑在.groupby() 中设置as_index=False
  • @BradSolomon,谢谢!我正在学习 Pandas,你们的解决方案非常好!
  • @ArnoldKlein 或者您可以添加 .reset_index(level=0, drop=True)
  • 只是一个明显的旁注,同样可以使用用 int 包装的乘法来编写,如下所示:df.groupby('participant_id').apply(lambda x: x.iloc[:int(x.participant_id.size*0.5)]),在我的情况下,我还希望至少为 1,所以需要小心并使用类似:df.groupby('participant_id').apply(lambda x: x.iloc[:max(int(x.participant_id.size*0.5),1)])
【解决方案2】:

您可以通过participant_id 进行分组,并使用transform 方法检查其索引是否在前半部分。这将创建一个布尔系列。然后使用此布尔系列过滤掉您的原始数据框。

criteria = df.groupby('participant_id')['participant_id']\
             .transform(lambda x:  np.arange(len(x)) < int(len(x) / 2))
df[criteria]

     index  summary  participant_id
0   130599     17.0              13
1   130601     18.0              13
2   130603     16.0              13
3   130605     15.0              13
4   130607     15.0              13
10   86789     12.0              14
11   86791      8.0              14
12   86793     21.0              14
20  107370      1.0              15
21  107372      2.0              15
22  107374      2.0              15
23  107376      4.0              15

【讨论】:

  • 谢谢,很好的答案,但上一个似乎更简单。
猜你喜欢
  • 1970-01-01
  • 2021-12-19
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多