迭代每一行时提高代码效率:Pandas Dataframe

Improve code efficiency when iterating through each row: Pandas Dataframe

下面的代码计算两个数据帧之间的持续时间和距离,如果持续时间和距离小于特定数量,则会将一个值附加到新数据帧。

下面的代码计算量很大,尤其是对于大型数据帧。

Linked_df=pd.DataFrame()
#for each unique date
for unq_date in R_Unique_Dates:
    #print('unq_dat: ',unq_date)
    #obtain dataframe of Mi and Ri of a specific date
    #add a column for index to track orignal index
    M=Mi.loc[(pd.to_datetime(Mi ['EventDate']) == unq_date) ]
    R=Ri.loc[(pd.to_datetime(Ri['EventDate']) == unq_date) ]
    #Check if unique date exist in M
    if ( M.empty==False) :
        for indexR, rowR in R.iterrows():
            #get duration 
            for indexM, rowM in M.iterrows():

                        duration=datetime.combine(date.today(), rowR['EventTime']) - datetime.combine(date.today(), rowM['EventTime'])
                        dayys = duration.days
                        if (duration.days < 0):
                            duration=datetime.combine(date.today(), rowM['EventTime']) - datetime.combine(date.today(), rowR['EventTime'])
                            dayis = duration.days

                        hours, remainder = divmod(duration.seconds, 3600)
                        minutes, seconds = divmod(remainder, 60) 
                        if (hours==0)&(minutes==0)&(seconds<11):
                            range_15m=dist_TwoPoints_LatLong(rowR['lat_t'],rowR['lon_t'],rowM['lat'],rowM['long'])
                            #print(range_15m)
                            if (range_15m <15):
                                #append in new dataframe 
                                rowM['y']=rowR['y']
                                row1 = pd.DataFrame(rowM)
                                row1 = row1.transpose()
                                Linked_df= pd.concat([Linked_df, row1], ignore_index=True)

假设Mi和Ri中的数据如下:

Ri 数据集

lat_t   lon_t   y   speed_t sprung_weight_t duration_capture    EventDate   EventTime
-27.7816    22.9939 4   27.1    442.0   2.819999933242798   2017/11/01  12:09:15
-27.7814    22.9939 3   27.3    447.6   2.8359999656677246  2017/11/01  12:09:18
-27.7812    22.9939 3   25.4    412.2   2.884000062942505   2017/11/01  12:09:21
-27.7809    22.994  3   26.1    413.6   2.9670000076293945  2017/11/01  12:09:23
-27.7807    22.9941 3   25.4    395.0   2.938999891281128   2017/11/01  12:09:26
-27.7805    22.9941 3   21.7    451.9   3.2829999923706055  2017/11/01  12:09:29
-27.7803    22.9942 3   20.2    441.7   3.6730000972747803  2017/11/01  12:09:33
-27.7801    22.9942 4   16.7    443.3   4.25                2017/11/01  12:09:36
-27.7798    22.9942 3   15.4    438.2   4.819000005722046   2017/11/01  12:09:41
-27.7796    22.9942 3   15.4    436.1   5.0309998989105225  2017/11/01  12:09:45
-27.7794    22.9942 4   15.8    451.6   5.232000112533569   2017/11/01  12:09:50
-27.7793    22.9941 3   18.2    439.4   4.513000011444092   2017/11/01  12:09:56
-27.7791    22.9941 3   21.4    413.7   3.8450000286102295  2017/11/01  12:10:00
-27.7788    22.994  3   23.1    430.8   3.485999822616577   2017/11/01  12:10:04

小米数据集

lat        lon      EventDate   EventTime
-27.7786    22.9939 2017/11/01  12:10:07
-27.7784    22.9939 2017/11/01  12:10:10
-27.7782    22.9939 2017/11/02  12:10:14
-27.778     22.9938 2017/11/02  12:10:17
-27.7777    22.9938 2017/11/02  12:10:21

Linked_df

lat_t   lon_t   y   EventDate   EventTime
-27.7786    22.9939 3   2017/11/01  12:10:07
-27.7784    22.9939 3   2017/11/01  12:10:10

如何优化代码?

注意:也对 dask 数据帧解决方案开放。有相同的日期。请注意,数据集比上面的示例更大,并且需要一周多的时间才能完成 运行。最重要的条件是距离需要小于15米,时差10秒以内。也不需要计算持续时间,因为它没有被存储。可能有替代方法来确定持续时间是否小于 10 秒,这可能需要更少的计算时间。

如果你想要速度,请不要使用 iterrows() ,如果你能避免的话。矢量化可以使您的速度提高 50 倍或 100 倍。

这是如何在您的代码中使用矢量化的示例:

for unq_date in R_Unique_Dates:
    M=Mi.loc[(pd.to_datetime(Mi['EventDate']) == unq_date) ]
    R=Ri.loc[(pd.to_datetime(Ri['EventDate']) == unq_date) ]

    M['date'] = pd.to_datetime(date.today() +' '+ M['EventTime'])
    R['date'] = pd.to_datetime(date.today() +' '+ R['EventTime'])

    M['duration'] = M['date'] - R['date']
    M.loc[M.duration < 0, 'duration'] =  R['date'] - M['date']
    ...

这样你就可以避免使用 iterrows()。

鉴于我们没有您正在使用的数据,此代码可能无法开箱即用,但您应该遵循这个想法:同时在整个数据帧中执行操作(矢量化)而不是迭代它(iterrows())。循环对性能不利。 This article 非常擅长解释这个概念。

外循环for unq_date in R_Unique_Dates:可以表示为groupby,但我建议从上面开始。刚开始使用 groupby 时可能会有点混乱。