Pandas — скорость поиска нескольких условий

#python #pandas #performance

#python #pandas #Производительность

Вопрос:

Я работаю с некоторыми историческими данными по бейсболу и пытаюсь получить информацию о матчах (отбивающий / питчер) для предыдущих игр.

Пример данных:

 import pandas as pd

data = {'ID': ['A','A','A','A','A','A','B','B','B','B','B'],
        'Year' : ['2017-05-01', '2017-06-03', '2017-08-02', '2018-05-30', '2018-07-23', '2018-09-14', '2017-06-01', '2017-08-03', '2018-05-15', '2018-07-23', '2017-05-01'],
        'ID2' : [1,2,3,2,2,1,2,2,2,1,1],
       'Score 2': [1,4,5,7,5,5,6,1,4,5,6],
       'Score 3': [1,4,5,7,5,5,6,1,4,5,6], 
       'Score 4': [1,4,5,7,5,5,6,1,4,5,6]}
df = pd.DataFrame(data)

lookup_data = {"First_Person" : ['A', 'B'],
             "Second_Person" : ['1', '2'],
             "Year" : ['2018', '2018']}

lookup_df = pd.DataFrame(lookup_data)
  

У Lookup df есть текущие сопоставления, у df есть исторические данные и текущие сопоставления.

Я хочу найти, например, для Человека А против Человека 2, каковы были результаты любого из их матчей на любую предыдущую дату?

Я могу сделать это с:

 history_list = []
def get_history(row, df, hist_list):
    #we filter the df to matchups containing both players before the previous date and sum all events in their history
    history = df[(df['ID'] == row['First_Person']) amp; (df['ID2'] == row['Second_Person']) amp; (df['Year'] < row['Year'])].sum().iloc[3:]
    #add to a list to keep track of results
    hist_list.append(list(history.values)   [row['Year'] row['First_Person'] row['Second_Person']])
  

а затем выполнить с помощью apply следующим образом:

 lookup_df.apply(get_history, df=df, hist_list = history_list, axis=1)
  

Ожидаемые результаты будут примерно такими:

 1st P  Matchup date 2nd p   Historical scores
A      2018-07-23     2     11 11 11
B      2018-05-15     2     7  7  7
  

Но это довольно медленно — операция фильтрации занимает около 50 мс на поиск.

Есть ли лучший способ, которым я могу подойти к этой проблеме? В настоящее время для просмотра 250 тысяч исторических совпадений потребовалось бы более 3 часов.

Ответ №1:

Вы можете объединить или сопоставить и сгруппировать по,

 lookup_df['Second_Person'] =   lookup_df['Second_Person'].astype(int) 

merged = df.merge(lookup_df, left_on = ['ID', 'ID2'], right_on = ['First_Person', 'Second_Person'], how = 'left').query('Year_x < Year_y').drop(['Year_x', 'First_Person', 'Second_Person', 'Year_y'], axis = 1)

merged.groupby('ID', as_index = False).sum()

    ID  ID2 Score 2 Score 3 Score 4
0   A   1   1       1       1
1   B   4   7       7       7
  

Комментарии:

1. Извините — я понял, что мне нужно уточнить лучше. Мне нужна любая предыдущая дата до текущей даты, а не только по годам. Я обновил свой исходный пост, чтобы показать это.

2. В вашей последней строке df есть дата 0

3. @ctd25, я не понимаю, как ты получил 11 для идентификатора A. Существует только одна строка с идентификаторами A и ID2 1, которая совпадает с lookup_df

4. Ах да, я торопился и все перепутал 🙂 Но я смог протестировать это, и это работает действительно отлично! Я только что использовал . запрос (date_x < date_y). Спасибо!