Python 如何总结数据框架

Python 如何总结数据框架,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个pandas数据框,其中包含20,xxx条公交车登机数据记录。数据集包含一个cardNumber字段,该字段对于每位乘客都是唯一的。有一个标识登机类型的type字段。有一个routeName列指定登机的路线,最后是一个Date列,确定登机的时间。我在下面提供了一个模拟数据框架 df=pd.DataFrame( {'cardNumber':['999','999','999','999','901','901','888','888'], “类型”:[“行程通行证”、“传输”、“行程通行证

我有一个pandas数据框,其中包含20,xxx条公交车登机数据记录。数据集包含一个
cardNumber
字段,该字段对于每位乘客都是唯一的。有一个标识登机类型的
type
字段。有一个
routeName
列指定登机的路线,最后是一个
Date
列,确定登机的时间。我在下面提供了一个模拟数据框架

df=pd.DataFrame(
{'cardNumber':['999','999','999','999','901','901','888','888'],
“类型”:[“行程通行证”、“传输”、“行程通行证”、“传输”、“存储值”、“传输”、“行程通行证”,
“旅行通行证”],
'路由名称':['1','2','2','1','20','3','4','4'],
“日期”:[“2020-08-01 06:18:56-04:00”,“2020-08-01 06:46:12-04:00”,“2020-08-01 17:13:51-04:00”,
'2020-08-01 17:47:32 -04:00', '2020-08-10 15:23:16 -04:00', '2020-08-10 15:44:45 -04:00',
'2020-08-31 06:54:09 -04:00', '2020-08-31 16:23:41 -04:00']}
)
df['Date']=pd.to_datetime(df['Date'])
我想做的是总结一下转移活动。从路线1到路线2或从路线2到路线1的平均换乘次数。数据集中有十一种不同的路由,可以在它们之间进行传输

我希望输出看起来像(注意,下面的输出不是从上面提供的示例生成的):


以下代码适用于您提供的区块数据。如果它在您的实际数据中不起作用,请让我知道。也许有更好的方法可以做到这一点,但我认为这是一个很好的起点

这里的总体思路是按乘客分组以确定路线。然后,因为你想要每日平均值,你需要按日期分组,然后按目的地分组,以计算每日平均值

# Define a function to get routes' relationship (origin vs destination)
def get_routes(x):
    if 'transfer' not in x.type.tolist(): # if no 'transfer' type in group, leave it as 0 (we'll remove them afterwards)
        return 0
    x = x[x.type == 'transfer'] # select target type
    date = df[df.cardNumber=='999'].Date.dt.strftime('%m/%d/%Y').unique()
    if date.size == 1: # if there is more than one date by passenger, you'll need to change this code
        date = date[0]
    else:
        raise Exception("There are more than one date per passenger, please adapt your code.")
    s_from = x.routeName[x.Date.idxmin()] # get route from the first date
    s_to = x.routeName[x.Date.idxmax()] # get route from the last date
    return date, s_from, s_to

# Define a function to get the routes' daily average
def get_daily_avg(date_group):
    daily_avg = (
        date_group.groupby(['From', 'To'], as_index=False) # group the day by routes
        .apply(lambda route: route.shape[0] / date_group.shape[0]) # divide the total of trips of that route by the total trips of that day
    )
    return daily_avg

# Get route's relationship
routes_series = df.groupby('cardNumber').apply(get_routes) # retrive routes per passenger
routes_series = routes_series[routes_series!=0] # remove groups without the target type

# Create a named dataframe from the series output
routes_df = pd.DataFrame(routes_series.tolist(), columns=['Date', 'From', 'To'])

# Create dataframe, perform filter and calculations
daily_routes_df = (
    routes_df.query('From != To') # remove routes with same destination as the origin
    .groupby('Date').apply(get_daily_avg) # calculate the mean per date
    .rename(columns={None: 'Avg. Daily'}) # set name to previous output
    .drop(['From','To'], axis = 1) # drop out redundant info since there's such info at the index
    .reset_index() # remove MultiIndex to get a tidy dataframe
)

# Visualize results
print(daily_routes_df)
输出:

         Date From To  Avg. Daily
0  08/01/2020    2  1         1.0

这里的平均值是1,因为每组只有一个计数。请注意,只考虑了“转移”类型。没有它或没有改变路线的,将被进一步删除。

如果我答对了问题,您希望从您的事件中获取行程的开始和结束,并且第一个事件与起点(路线名称)相对应然后计算数据集中具有相同起点和终点的票证数量

如果是这样,您可以按如下方式执行此操作

# srot the dataframe so you can use first/last
df_sorted= df.sort_values(['cardNumber', 'Date']).reset_index(drop=True)

# calculate the counts do the counts, but only
# from the defined types
indexer_trip_points= df_sorted['type'].isin(['transfer'])
df_from_to= df_sorted[indexer_trip_points].groupby('cardNumber').agg(
                  start_date=('Date', 'first'),
                  trip_start=('routeName', 'first'), 
                  trip_end=('routeName', 'last'),
)
                      
df_from_to['start_date']= df_from_to['start_date'].dt.date
df_counts= df_from_to.groupby(['trip_start', 'trip_end', 'start_date']).agg(
    count=('trip_start', 'count')
)
df_counts.reset_index(drop=False, inplace=True)
df_counts.groupby(['trip_start', 'trip_end']).agg(
    avg=('count', 'mean')
)
这导致:

                     avg
trip_start trip_end     
2          1           1
3          3           1

正如您所注意到的,最后一个条目具有相同的起点和终点。所以你可能需要过滤掉那些你还没有完整数据的旅行。例如,如果在您的情况下,一条路由永远不能以其开始时的相同routeName结束,您可以通过比较两列来简单地筛选它们。

上述数据的预期输出是什么?您如何知道哪条路由转到了另一条路由?我认为你的数据(至少你提供的数据块)没有这样的信息。@CainãMaxCouto Silva,这是我认为我遇到的问题之一。我认为这些关系必须是被迫的。例如,在卡号999处,您可以看到乘客登上了路线1,然后转乘了路线2。我不知道是否有办法按
cardNumber
分组,然后按
Date
排序。然后将记录直接拉到传输记录之前,以识别传输。@QuangHoang我编辑了帖子以显示所需的输出。
Avg.Daily
来自哪个列?如何定义从路由2到路由1的*传输?我在数据集上运行了此操作,但对于所有“from”和“to”对,平均每日值为1。你知道为什么会发生这种情况吗?还有,有没有办法解释同一个
卡号在一天内进行两次转账?在上面的示例中,您会注意到,
cardNumber 999
在上午进行转账,然后在下午进行第二次转账。“转账”和“旅行证”之间的关系是什么?“旅行证”是多种交易类型中的一种。“转账”是一种交易类型,当乘客首先使用“行车通行证”、“存储值”或其他多种交易类型时,会进行登记。当他们登上行程的第二条巴士时,系统将该交易识别为“转移”。此后,我创建了一个名为
transfer
的属性,该属性要么是“0”表示“非传输”,要么是“1”表示“传输”。此外,在代码
df_routes['n']=1
行中,我可以更改该值,这就是数据帧中返回的值。
                     avg
trip_start trip_end     
2          1           1
3          3           1