Pandas合并On<运算符

5

我有一个包含从A到B/C的航班时间和从B/C到Z的航班的df

schedule

我希望能够找到从A到Z的可能一站式路线。这些路线需要在B/C停留。
简单的合并就可以解决问题。
routes = pd.merge(df , df , left_on = 'Destination' , right_on = 'Origin')

Routes

然而,我的日程表 df 有来自 A -> B/C/D/.../Y 的成千上万次航班以及来自 B/C/D/.../Y->Z 的成千上万次航班。将此表与自身合并会导致一个包含数十亿行的 routes 表。我可以通过筛选转机时间小于 24 小时的路线来过滤到一个小的 df。

routes = routes[routes['Time_y'] - routes['Time_x'] < 24]

首先计算所有可能的路线,然后过滤出停留时间小于24小时的路线是计算上不可行的。有没有一种同时执行pd.merge并满足停留时间小于24小时条件的方法呢?伪代码如下:
routes = pd.merge(df , df , left_on = 'Destination' , right_on = 'Origin' , right['Time'] - left['Time'] < 24)

这是示例数据:

df = pd.DataFrame({'Origin': {1: 'A', 6: 'A', 11: 'A', 16: 'A', 21: 'B', 26: 'B', 31: 'C', 36: 'C'}, 'Destination': {1: 'B', 6: 'B', 11: 'C', 16: 'C', 21: 'Z', 26: 'Z', 31: 'Z', 36: 'Z'}, 'Dept_Time': {1: pd.Timestamp('2019-03-30 17:31:00'), 6: pd.Timestamp('2019-05-16 17:32:00'), 11: pd.Timestamp('2019-04-01 08:30:00'), 16: pd.Timestamp('2019-06-09 08:20:00'), 21: pd.Timestamp('2019-07-26 08:31:00'), 26: pd.Timestamp('2019-03-31 06:16:00'), 31: pd.Timestamp('2019-07-03 23:52:00'), 36: pd.Timestamp('2019-03-27 17:31:00')}, 'Arrv_Time': {1: pd.Timestamp('2019-03-30 23:23:00'), 6: pd.Timestamp('2019-05-16 23:22:00'), 11: pd.Timestamp('2019-04-01 14:22:00'), 16: pd.Timestamp('2019-06-09 14:18:00'), 21: pd.Timestamp('2019-07-26 14:23:00'), 26: pd.Timestamp('2019-06-18 05:00:00'), 31: pd.Timestamp('2019-07-04 05:36:00'), 36: pd.Timestamp('2019-03-27 23:23:00')}})

据我所知,没有这样的操作。您可以将表格分成N个部分,将每个部分与每个部分合并,然后过滤和合并结果。这将需要N^2次合并,但是通过精心选择的N,可能在计算上可行。 - DYZ
@DYZ 谢谢。我怀疑这会保留内存,但会减慢整体运行时间。我想要改进的是运行时间。我会测试并报告结果。 - Jack
不认为有办法在pandas的合并中添加这样的条件,但是这里的最佳答案可能会有所帮助:https://dev59.com/RmAg5IYBdhLWcg3whrMV - kudeh
1
@JoergVanAken 谢谢 - 好主意。df涵盖了300天。我能想到的一个问题是这将创建24-48小时的中转时间... 让leg_1 = df[df['time'] == '2019-01-01'] 和 leg_2 = df[df['time'] == '2019-01-02']。pd.merge(leg_1 , leg_2) 将创建一个行程,其中航班1在2019-01-01早些时候离开,航班2在2019-01-02晚些时候离开,这使得中转时间为24-48小时。 - Jack
你们的日期时间类型是什么?它包含 HH:MM:SS 吗?请直接在问题中发布示例数据。 - Parfait
显示剩余2条评论
1个回答

0

考虑计算未来(提前1天)的日期,并将其添加到与起点/终点合并的数据中:

from datetime import timedelta
...

df['Future_Time'] = df['Flight_Time'] + timedelta(days=1)

merged_df = pd.merge(df, df, 
                     left_on = ['Destination', 'Future_Time'],
                     right_on = ['Origin', 'Flight_Time'],
                     suffixes=['_o','_d'])

假设您的航班时间有影响合并连接的时间组件,请将日期规范化为计算未来日期之前的午夜,并进行合并:
df['Normalized_Time'] = df['Flight_Time'].dt.normalize()
df['Future_Time'] = df['Normalized_Time'] + timedelta(days=1)

merged_df = pd.merge(df, df, 
                     left_on = ['Destination', 'Future_Time'],
                     right_on = ['Origin', 'Normalized_Time'],
                     suffixes=['_o','_d'])

以上可能会导致24-48小时的配对问题。但从那里开始,您可以根据较小的数据集过滤出24小时范围内的内容:

merged_df[merge_df['Flight_Time_d'] <= merge_df['Flight_Time_o'] + timedelta(days=1)]

或者全部一起:

merged_df = (pd.merge(df, df, 
                      left_on = ['Destination', 'Future_Time'],
                      right_on = ['Origin', 'Normalized_Time'],
                      suffixes=['_o','_d'])
               .query("Flight_Time_d <= Flight_Time_o + timedelta(days=1)")
            )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接