我正在尝试逐块对熊猫数据帧进行排序,而无需更改块内的顺序。
数据帧包含论坛帖子、时间戳和话题名称。我已经对数据帧进行了排序,以便属于同一线程的所有帖子都使用 df.sort_values(['thread', 'timestamp'], inplace=True)
按正确的顺序排列。我现在想根据每个块中第一个帖子的时间戳对属于同一线程的数据块进行排序。块内的顺序应保持不变。
我目前拥有的:
post timestamp thread
0 this 2009/10/30 16:51 hello
1 be 2009/11/02 17:11 hello
2 some 2008/07/10 15:23 nice
3 text 2007/04/22 14:11 question
4 this 2007/04/24 11:03 question
5 be 2007/05/03 17:55 question
6 some 2004/09/01 09:32 game
7 text 2010/01/01 03:32 wheather
我想要什么:
post timestamp thread
6 some 2004/09/01 09:32 game
3 text 2007/04/22 14:11 question
4 this 2007/04/24 11:03 question
5 be 2007/05/03 17:55 question
2 some 2008/07/10 15:23 nice
0 this 2009/10/30 16:51 hello
1 be 2009/11/02 17:11 hello
7 text 2010/01/01 03:32 wheather
有没有办法做到这一点?
让我们尝试先groupby
线程,然后获取第一条记录,按时间对这些记录进行排序,然后使用 DataFrameGroupBy 的 groups
属性获取每个组中索引的当前顺序。 最后,使用 pd.concat
和列表推导式按第一条记录的排序顺序重建数据帧。
g = df.groupby('thread')
s = g.head(1).sort_values('timestamp')['thread']
dg = g.groups
pd.concat([df.reindex(dg[i[1]]) for i in s.iteritems()])
输出:
post timestamp thread
6 some 2004-09-01 09:32:00 game
3 text 2007-04-22 14:11:00 question
4 this 2007-04-24 11:03:00 question
5 be 2007-05-03 17:55:00 question
2 some 2008-07-10 15:23:00 nice
0 this 2009-10-30 16:51:00 hello
1 be 2009-11-02 17:11:00 hello
7 text 2010-01-01 03:32:00 wheather
- 首先,获取每个组的第一个"时间戳"并
argsort
它。 - 接下来,使用
groupby
,利用groupby
按键对组进行排序,但不更改组内的顺序这一事实。 - 最后,按排序顺序
concat
生成的组。
idx = df['thread'].map(df.groupby('thread')['timestamp'].first().argsort())
idx
0 3
1 3
2 2
3 1
4 1
5 1
6 0
7 4
Name: thread, dtype: int64
pd.concat([g for _, g in df.groupby(idx)])
post timestamp thread
6 some 2004/09/01 09:32 game
3 text 2007/04/22 14:11 question
4 this 2007/04/24 11:03 question
5 is 2007/05/03 17:55 question
2 some 2008/07/10 15:23 nice
0 this 2009/10/30 16:51 hello
1 is 2009/11/02 17:11 hello
7 text 2010/01/01 03:32 wheather
使用 sort_values
和 drop_duplicates
得到最小值,然后我们使用 Categorical
cate=df.sort_values('timestamp').drop_duplicates('thread')
df.thread=pd.Categorical(df.thread,ordered=True,categories=cate.thread.tolist())
df=df.sort_values('thread')
df
post timestamp thread
6 some 2004-09-01 09:32:00 game
3 text 2007-04-22 14:11:00 question
4 this 2007-04-24 11:03:00 question
5 be 2007-05-03 17:55:00 question
2 some 2008-07-10 15:23:00 nice
0 this 2009-10-30 16:51:00 hello
1 be 2009-11-02 17:11:00 hello
7 text 2010-01-01 03:32:00 wheather
一种方法是创建一个名为"first_ts"的临时列,其中groupby
在"线程"上,transform
获取每个线程的"时间戳"列上的min
(所以第一个日期)。现在,您可以按此列sort_values
并drop
临时列。
# you might need to convert timestamp to datetime
df.timestamp = pd.to_datetime(df.timestamp)
#create the column
df['first_ts'] = df.groupby('thread').timestamp.transform(min)
#sort and drop
df = df.sort_values(['first_ts']).drop('first_ts',axis=1)
你得到如预期的那样
print(df)
post timestamp thread
6 some 2004-09-01 09:32:00 game
3 text 2007-04-22 14:11:00 question
4 this 2007-04-24 11:03:00 question
5 be 2007-05-03 17:55:00 question
2 some 2008-07-10 15:23:00 nice
0 this 2009-10-30 16:51:00 hello
1 be 2009-11-02 17:11:00 hello
7 text 2010-01-01 03:32:00 wheather
或者,如果不想创建列,也可以将reindex
与 groupby
的排序值的索引一起使用,例如:
df = df.reindex(df.groupby('thread').timestamp.transform(min)
.sort_values().index)