熊猫:使用嵌套for循环进行细胞比较的替代方法

时间:2020-07-01 12:31:04

标签: python pandas

我正在尝试尝试在车站找到火车会议的问题,但是我很难找到一种方法来进行必要的比较而不使用嵌套的for循环(这很慢,我有数十万个数据点。

我的DataFrame行包含以下有用数据:到达时间(日期时间),出发时间(日期时间),唯一的火车ID(字符串),火车位于开始时间和结束时间之间的车站(字符串)和它遇到的火车ID的单元格(字符串,开始时为空)。我想找到所有相遇的行对,这意味着我想要那个实现:

  1. 从第1行到达到出发的时间间隔与第2行到达到出发的时间间隔重叠。
  2. 位于同一站。

此外,没有会议涉及两列以上的火车。

我尝试了以下操作(下面的代码):我在到达和离开时间之外创建了间隔对象。然后,我使用嵌套的for循环将每行间隔与其他行进行比较,如果它们重叠,则检查站是否匹配。如果他们这样做了,我会将每个火车ID存储在对方的火车会议单元中。

df_dsp['interval']  = [func(x,y) for x, y in zip(df_dsp['arrival'], df_dsp['departure'])]

meetings = np.empty([])
for i in range (1,len(df.index)):
    for q in range (1,len(df.index)):
        if (i < q): # Train meetings are symmetric.
            if df.iloc[i, df.columns.get_loc('interval')].overlaps(df.iloc[q, df.columns.get_loc('interval')]):
                if df.iloc[i, df.columns.get_loc('station')] == df.iloc[q, df.columns.get_loc('station')]:
                    df.iloc[i, df.columns.get_loc('train_id_meeting')] = df.iloc[q, df.columns.get_loc('train_id')]
                    df.iloc[q, df.columns.get_loc('train_id_meeting')] = df.iloc[i, df.columns.get_loc('train_id')]

我看过类似的问题,但是很难将它们有效地应用于我的数据集。我的问题是:如何才能更快地执行这些比较?

修改: 我无法给出数据库(有些机密),但是我创建了一个有代表性的数据集。

d = {'arrival': [pd.Timestamp(datetime.datetime(2012, 5, 1, 1)), pd.Timestamp(datetime.datetime(2012, 5, 1, 3)),
                 pd.Timestamp(datetime.datetime(2012, 5, 1, 6)), pd.Timestamp(datetime.datetime(2012, 5, 1, 4))],
     'departure': [pd.Timestamp(datetime.datetime(2012, 5, 1, 3)), pd.Timestamp(datetime.datetime(2012, 5, 1, 5)), 
                   pd.Timestamp(datetime.datetime(2012, 5, 1, 7)), pd.Timestamp(datetime.datetime(2012, 5, 1, 6))],
     'station': ["a", "b", "a", "b"],
     'train_id': [1, 2, 3, 4],
     'meetings': [np.nan, np.nan, np.nan, np.nan]}
df = pd.DataFrame(data=d)

在此样本数据中,第2行和第4行表示在“ b”站集合的火车。如果可以在不使用Interval对象的情况下更快地完成此操作,那么我很乐意使用它。

2 个答案:

答案 0 :(得分:0)

我的头会爆炸。抱歉,我没有足够的分数,我无法发表评论。无论如何,我们可以让您的数据库对其进行测试吗?

第1行是否与第2行(对)匹配,或者第1行与第2行匹配?

您实际上正在执行O(n ^ 2),可以肯定地将其改进,但是必须非常清楚问题所在。

Pandas中最有效的算法是尝试将所有事物理解为一个矩阵,可以与Numpy Arrays(矢量化)进行比较和研究,但我认为并非如此。

“间隔”的数据类型是什么?

答案 1 :(得分:0)

初始化DataFrame。

d = {'arrival': [pd.Timestamp(datetime.datetime(2012, 5, 1, 1)), pd.Timestamp(datetime.datetime(2012, 5, 1, 3)),
                     pd.Timestamp(datetime.datetime(2012, 5, 1, 6)), pd.Timestamp(datetime.datetime(2012, 5, 1, 4))],
         'departure': [pd.Timestamp(datetime.datetime(2012, 5, 1, 3)), pd.Timestamp(datetime.datetime(2012, 5, 1, 5)), 
                       pd.Timestamp(datetime.datetime(2012, 5, 1, 7)), pd.Timestamp(datetime.datetime(2012, 5, 1, 6))],
         'station': ["a", "b", "a", "b"],
         'train_id': [1, 2, 3, 4],
         'meetings': [np.nan, np.nan, np.nan, np.nan]}
    df = pd.DataFrame(data=d)


Out: 

    arrival     departure   station     train_id    meetings
0   2012-05-01 01:00:00     2012-05-01 03:00:00     a   1   NaN
1   2012-05-01 03:00:00     2012-05-01 05:00:00     b   2   NaN
2   2012-05-01 06:00:00     2012-05-01 07:00:00     a   3   NaN
3   2012-05-01 04:00:00     2012-05-01 06:00:00     b   4   NaN

将数据时间转换为时间戳

df["arrival"] = df["arrival"].apply(lambda x: x.timestamp())
df["departure"] = df["departure"].apply(lambda x: x.timestamp())

初始化两个表进行合并。

df
df2 = df

基于“ Station”将两个表合并在一起,因此已经进行了比较。

merge = pd.merge(df, df2, on=['station'])
table = merge[merge["train_id_x"] != merge["train_id_y"]]

arrival_x   departure_x     station     train_id_x  meetings_x  arrival_y   departure_y     train_id_y  meetings_y
1   1.335834e+09    1.335841e+09    a   1   NaN     1.335852e+09    1.335856e+09    3   NaN
2   1.335852e+09    1.335856e+09    a   3   NaN     1.335834e+09    1.335841e+09    1   NaN
5   1.335841e+09    1.335848e+09    b   2   NaN     1.335845e+09    1.335852e+09    4   NaN
6   1.335845e+09    1.335852e+09    b   4   NaN     1.335841e+09    1.335848e+09    2   NaN

现在使用比较向量化算法

table[((table["arrival_x"] > table["arrival_y"]) & (table["arrival_x"] < table["departure_y"]) | (table["arrival_y"] > table["arrival_x"]) & (table["arrival_y"] < table["departure_x"]))]

结果:

arrival_x   departure_x     station     train_id_x  meetings_x  arrival_y   departure_y     train_id_y  meetings_y
5   1.335841e+09    1.335848e+09    b   2   NaN     1.335845e+09    1.335852e+09    4   NaN
6   1.335845e+09    1.335852e+09    b   4   NaN     1.335841e+09    1.335848e+09    2   NaN

免责声明:此算法可以进一步改进。但我希望你能明白。而不是进行循环,请使用速度更快的Pandas和Numpy函数。