pandas GroupBy:如何分组依据和聚合数据以仅按计数显示字段的前 3 个值



这是我关于StackOverflow的第一个问题,所以我尽量清晰简洁。非常感谢您的耐心等待。

背景

我有一个包含 17 个属性的训练数据数据集,这些属性包括:origin_station_codeorigin_stationdestination_station_codedestination_stationroute_codestart_timeend_timefleet_numberstation_codestationstation_typeplatformsch_arr_timesch_dep_timeact_arr_timeact_dep_timedate

在这些属性中,我只关心:dateorigin_stationdestination_stationstart_time

此数据集由 61 个单独的 CSV 文件组成,这些文件使用 glob 函数和循环组合在一起形成一个超过一百万行的数据帧。

数据帧的每一行表示火车旅程的各个停靠点。完整路径由多个停靠点组成,以下屏幕截图显示了由 19 个停靠点组成的路径示例,即从糖波到尝试 Pin:此处。

通过连接origin_stationdestination_station属性,创建了一个名为complete_route name的新属性。这可以识别所有路由,其中有 81 个唯一条目。

任务

我的任务是使用 pandas 对数据帧进行子集化,以便数据集显示每个日期最受欢迎的 3 条路由。此子集数据帧应显示datecomplete_route name以及该路由每天发生的次数计数。通过将 nunique 方法应用于start_time属性(日期/时间类型(,可以确定路径发生的唯一次数。

我目前的进度

目前,我的 GroupBy 和聚合代码能够显示每个路由每天运行的次数,如下所示:

df_grouped = df.groupby(
['date', 'complete_route_name']
).agg(
{
'start_time': 'nunique'    # count the number of unique routes by using the 'nunique' of the start_times
}
).reset_index()

但是,我现在想现在使用我现有的代码,以便它每天仅按计数显示前 3 条唯一路由,例如

date           complete_route_name                                   count
2015-08-01     Attempt Pin to Roll Test                              101
Suit Treatment Turnback to Spiders Toothbrush         93       
Concourse Village to Port Morris                      87
2015-08-02     Bridge Bottle to Ants Attempt                         119
North Riverdale to Eastchester                        117
Wakefield to Kingsbridge                              101
......
2015-09-30     Castleton Corners to Dongan Hills                     121
Eltingville to Graniteville                           119
Great Kills to Castleton                              117

任何这方面的帮助将不胜感激!

其他资源

原始数据集和当前状态的工作簿可以在我的 GitHub 上找到托管,如果它有任何用途/兴趣。也可以在此处查看静态工作簿。

非常感谢!

我会从你离开的地方继续

df_agg = df.groupby(['date', 'route_name']).agg({'start_time':'nunique'}).reset_index()

然后我会做以下事情来解决您的要求

df_sorted_by_group = df_agg.groupby(['date']).apply(
lambda x: x.sort_values(['start_time'],ascending = False)
).reset_index(drop = True)

最后一步

df_final = df_sorted_by_group.groupby(['date']).head(3)

示例代码

import pandas as pd
routes = {'route_name': [ 'A to B', 'A to B',  'B to C',   'B to C',   'C to D', 'C to D',  'C to D', 'C to D',  'D to E',
'A to Z', 'A to Z',  'B to Z',   'B to Z',   'C to Z', 'C to Z',  'C to Z', 'C to Z',  'D to Z'],
'date': ['01/01/2015','01/01/2015','01/01/2015','01/01/2015','01/01/2015','01/01/2015','01/01/2015','01/01/2015','01/01/2015',
'02/01/2015','02/01/2015','02/01/2015','02/01/2015','02/01/2015','02/01/2015','02/01/2015','02/01/2015','02/01/2015'],
'start_time': ['A1','A2','A3','A4','A5','A6','A7','A8','A9','A10','A11','A12','A13','A14','A15','A16','A17','A18']
}
df = pd.DataFrame(routes)
df['date'] = pd.to_datetime(df['date'],format ='%d/%m/%Y')
df
route_name  date    start_time
0   A to B  2015-01-01  A1
1   A to B  2015-01-01  A2
2   B to C  2015-01-01  A3
3   B to C  2015-01-01  A4
4   C to D  2015-01-01  A5
5   C to D  2015-01-01  A6
6   C to D  2015-01-01  A7
7   C to D  2015-01-01  A8
8   D to E  2015-01-01  A9
9   A to Z  2015-01-02  A10
10  A to Z  2015-01-02  A11
11  B to Z  2015-01-02  A12
12  B to Z  2015-01-02  A13
13  C to Z  2015-01-02  A14
14  C to Z  2015-01-02  A15
15  C to Z  2015-01-02  A16
16  C to Z  2015-01-02  A17
17  D to Z  2015-01-02  A18

从上面应用脚本后,您将获得以下结果

df_final
date   route_name  start_time
0   2015-01-01  C to D  4
1   2015-01-01  A to B  2
2   2015-01-01  B to C  2
4   2015-01-02  C to Z  4
5   2015-01-02  A to Z  2
6   2015-01-02  B to Z  2
df_sorted_by_group = df_grouped.groupby(['Date']).apply(
lambda x: x.sort_values(['Count'],ascending = False)
).reset_index(drop = True)
df_grouped_top16 = df_sorted_by_group.groupby(['Date']).head(16)

好的,所以从你的工作部分开始,我会把它重写为:

df_grouped = df.groupby(
['date', 'complete_route_name'], as_index=False
)['start_time'].nunique()

接下来,您可以执行以下操作:

df2=df_grouped.groupby("date").rank().le(3)
df_grouped.loc[df2.loc[df2].index]

最新更新