用pandas只获取每组的第一行和最后一行

27 人关注

我是python的新手。我有一个巨大的 dataframe ,有几百万行和ID,我的数据是这样的。

Time    ID  X   Y
8:00    A   23  100
9:00    B   24  110
10:00   B   25  120
11:00   C   26  130
12:00   C   27  140
13:00   A   28  150
14:00   A   29  160
15:00   D   30  170
16:00   C   31  180
17:00   B   32  190
18:00   A   33  200
19:00   C   34  210
20:00   A   35  220
21:00   B   36  230
22:00   C   37  240
23:00   B   38  250

我想根据ID和时间对数据进行排序。我所寻找的预期结果是这样的"

Time    ID  X   Y
8:00    A   23  100
13:00   A   28  150
14:00   A   29  160
18:00   A   33  200
20:00   A   35  220
9:00    B   24  110
10:00   B   25  120
17:00   B   32  190
21:00   B   36  230
23:00   B   38  250
11:00   C   26  130
12:00   C   27  140
16:00   C   31  180
19:00   C   34  210
22:00   C   37  240
15:00   D   30  170

我想只选取id中的 "第一个和最后一个",其余的都不选。预期的结果是这样的。

Time    ID  X   Y
8:00    A   23  100
20:00   A   35  220
9:00    B   24  110
23:00   B   38  250
11:00   C   26  130
22:00   C   37  240
15:00   D   30  170

如何在pandas中做到这一点? 谢谢你的建议

python
pandas
dataframe
group-by
pandas-groupby
Arief Hidayat
Arief Hidayat
发布于 2018-12-26
3 个回答
cs95
cs95
发布于 2022-07-11
已采纳
0 人赞同

使用 groupby ,找到每组的 head tail ,以及 concat 这两个。

g = df.groupby('ID')
(pd.concat([g.head(1), g.tail(1)])
   .drop_duplicates()
   .sort_values('ID')
   .reset_index(drop=True))
    Time ID   X    Y
0   8:00  A  23  100
1  20:00  A  35  220
2   9:00  B  24  110
3  23:00  B  38  250
4  11:00  C  26  130
5  22:00  C  37  240
6  15:00  D  30  170

如果你能保证每个ID组有至少要有两行,就不需要调用drop_duplicates

g.head(1)
    Time ID   X    Y
0   8:00  A  23  100
1   9:00  B  24  110
3  11:00  C  26  130
7  15:00  D  30  170
g.tail(1)
     Time ID   X    Y
7   15:00  D  30  170
12  20:00  A  35  220
14  22:00  C  37  240
15  23:00  B  38  250
pd.concat([g.head(1), g.tail(1)])
     Time ID   X    Y
0    8:00  A  23  100
1    9:00  B  24  110
3   11:00  C  26  130
7   15:00  D  30  170
7   15:00  D  30  170
12  20:00  A  35  220
14  22:00  C  37  240
15  23:00  B  38  250
    
令人印象深刻。你能不能向我解释一下 pd.concat groupby 中的作用是什么?
cs95
@Arief g.head(1) g.tail(1) 返回两个独立的数据帧;然后我用 pd.concat 把两个数据帧垂直连接起来。 concat groupby 是独立的操作。
非常感谢你的详细解释。如何保存到新的csv?我得到了错误。
cs95
@Arief result.to_csv('file.csv') 。如果答案对你有帮助,记得接受,谢谢 :-)
如何考虑按时间和ID排序? 因为我试过我的数据,对时间数据感到困惑。
johnnybarrels
johnnybarrels
发布于 2022-07-11
0 人赞同

如果你创建了一个小函数,只选择一个DataFrame的第一行和最后一行,你可以将其应用于group-by,像这样。

df.groupby('ID').apply(lambda x: x.iloc[[0, -1]]).reset_index(drop=True)

正如其他人所提到的,如果在事后也能有.drop_duplicates()或类似的功能,以过滤掉 "ID "只有一行的情况下的重复行,可能会更好。

我喜欢你的解决方案,但是公式中有一个错字(df对x),我建议添加reset_index以避免结果中出现重复的索引列:df.groupby('ID').apply(lambda x: x.iloc[[0, -1]]).reset_index(drop=True)。
@bpelhos 谢谢你,原答案已更新!
Akash Kumar
Akash Kumar
发布于 2022-07-11
0 人赞同

你可以通过简单地对 "ID "列进行排序来获得你想要的列。

df_sorted = df.sort_values("ID")

之后,通过搜索空白,制作一个相同列的空数据框。

all = df[df.ID=='']

通过存储所有存在于'ID'列中的唯一值。

uni = list(df.ID.unique())

最后,在你之前创建的那个空数据框中追加第一个和最后一个头和尾。

最终的代码将看起来像这样。

df_sorted = df.sort_values("ID")
all = df[df.ID=='']
uni = list(df.ID.unique())