按第一个值对组进行排序而不更改组顺序

时间:2019-01-12 01:27:52

标签: python pandas dataframe group-by pandas-groupby

我正在尝试按块对熊猫数据框进行排序,而不更改块内的顺序。

数据框包含论坛帖子,时间戳和主题名称。我已经对数据框进行了排序,以便使用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

有没有办法做到这一点?

4 个答案:

答案 0 :(得分:4)

  1. 首先,获取每个组的第一个“时间戳”,并argsort
  2. 接下来,使用groupby,利用groupby按键对组进行排序,但不更改组内顺序的事实。
  3. 最后,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

答案 1 :(得分:4)

让我们尝试首先使用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

答案 2 :(得分:4)

使用sort_valuesdrop_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

答案 3 :(得分:3)

一种方法是创建一个临时列,例如名为“ 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

或者如果您不想创建该列,也可以将reindexgroupby的排序值索引一起使用,例如:

df = df.reindex(df.groupby('thread').timestamp.transform(min)
                  .sort_values().index)