Повышение эффективности кода при итерации по каждой строке: Pandas Dataframe - PullRequest
0 голосов
/ 29 сентября 2018

Приведенный ниже код вычисляет длительность и расстояние между двумя кадрами данных, и если продолжительность и расстояние меньше определенной суммы, значение добавляется к новому кадру данных.

Приведенный ниже код является вычислительно дорогим, особенно для большого кадра данных.

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 Dataset

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

Набор данных Mi

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

Как оптимизировать код?

Примечание: также открыты для решений для фреймов данных.Есть даты, которые одинаковы.Обратите внимание, что набор данных больше, чем в приведенном выше примере, и его запуск занимает более недели.Наиболее важным условием является то, что расстояние должно быть менее 15 метров, а разница во времени составляет 10 с или менее.Также не требуется вычислять продолжительность, поскольку она не сохраняется.Могут быть альтернативные способы определить, составляет ли продолжительность менее 10 секунд, что может занять меньше вычислительного времени.

1 Ответ

0 голосов
/ 29 сентября 2018

Если вы хотите скорость, не используйте 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 ()).Петли плохо влияют на производительность. Эта статья прекрасно объясняет эту концепцию.

Внешний цикл for unq_date in R_Unique_Dates: можно выразить как групповой, но я бы рекомендовал начать с вышеприведенного.Использование groupby может немного сбивать с толку при запуске.

...