Как BEST извлечь информацию из нескольких фреймов данных на основе ряда условий if \ else и соответствующих значений? (Нужно руководство!)) - PullRequest
5 голосов
/ 07 февраля 2020

Итак, у меня есть три Dataframes, X, Y и Events. У df_X есть координаты X, у df_Y есть координаты Y, а у Events_df есть список событий, которые произошли (данные связаны с баскетболом). Вы увидите, как они связаны друг с другом, посмотрев ниже:

df_Event:

Seconds Passed   Event Type         Player
1.0              Passed The Ball    Steve
2.0              Received Pass      Michael
3.0              Touch              Michael
4.0              Passed The Ball    Michael
5.0              Received The Ball  George


df_X:

Seconds Passed  Steve   Michael   George
1.0             11.43   12.33     15.33
2.0             11.45   12.46     13.22  
3.0             10.99   10.33     14.33           
4.0             11.34   10.36     11.22
5.0             12.43   12.22     11.78


df_Y:

....

(The Same As Above Just With Different Numbers)

Я хочу записать шаблоны событий во времени, а затем взять координаты X, Y, которые соответствуют пройденным секундам столбцы через каждый Dataframes. Так, например, если бы я хотел знать, где начинается и заканчивается проход, мне нужна следующая информация.

Мне нужна следующая информация в новом кадре данных с пометкой "Passes_df":

Passing Player   Receiving Player    X Coordinate PP   Y Coordinate PP  X Coordinate RP   Y Coordinate RP
Steve            Michael             11.43             ....             12.46             .....

Я знаю, что мог бы использовать следующее:

Passes_df['Passing Player'] = df_Event['Player'].where(df_Event['Event'] == 'Pass').dropna()
Passes_df['Receiving Player'] = df_Event['Player'].shift(-1).where\
((df_Event['Event'] == 'Pass') & (df_Event['Event'].shift(-1) == 'Received Pass'))

Однако, это кажется слишком длинным? Могу ли я использовать функцию, которая собирает информацию из каждого источника более свободно? Была бы признательна за помощь!

Ответы [ 5 ]

3 голосов
/ 10 февраля 2020

Решение вопроса требует системного подхода c, который значительно бы повлиял на изменение проблемы. Поскольку в заданном вопросе выходной фрейм данных исключил тип события «Прикосновение» и сравнивал только пропуски и получение; поэтому, я принял подход к достижению при таком выводе.

  1. X и Y кадрирует, кадры данных неубедительны. Нам нужно привести их в чистую форму с помощью функции pd.melt.
  2. Событие слияния, X связывает и Y объединяет данные в единый кадр данных с помощью функции pd.merge.
  3. Создание отдельного кадра данных проходов и получения.
  4. Поскольку «Прошедшие секунды» - это уникальный столбец, я предполагаю, что задержка передачи и получения составляет 1 секунду. Поэтому удалите 1 секунду из принимающего фрейма данных.
  5. Слияние передает фрейм данных с получающим фреймом данных.

(PS: Как обычно, я использовал pd вместо pandas)

Шаг 1: собрать данные в удобной форме

tidy_x = pd.melt(df_x, id_vars='Seconds Passed', var_name='Player', value_name='X_Cordinate')
tidy_y = pd.melt(df_y, id_vars='Seconds Passed', var_name='Player', value_name='Y_Cordinate')
tidy_y['Y_Cordinate'] += 10 # Hypothetical number to change numbers from X.

Шаг 2: Объединить событие, X связывает и Y объединяет данные в единый кадр данных

df = pd.merge(df_event, tidy_x)
df = pd.merge(df, tidy_y)

Теперь у вас есть полные данные события с координатами и игроком.

Шаг 3: Создайте отдельный фрейм данных пропусков и приемов.

passes = df['Event Type'].str.startswith('Pass')
df_passes = df[passes].copy()

received = df['Event Type'].str.startswith('Received')
df_received = df[received].copy()
df_received.loc[received, 'Seconds Passed'] -= 1

Наконец: Слияние передает фрейм данных с фреймом получения данных.

pd.merge(df_passes, df_received, on='Seconds Passed', suffixes=('_PP', '_RP'))

Результат / Выход:

enter image description here

3 голосов
/ 09 февраля 2020

Вы можете использовать pandas.pivot(...) для этого:

#assuming it's sorted by Seconds Passed:
df_Event["Event_order"]=df_Event.groupby("Event Type").cumcount()

df_Event["X"]=df_Event.merge(df_X, on="Seconds Passed").apply(lambda x: x[x["Player"]], axis=1)
df_Event["Y"]=df_Event.merge(df_Y, on="Seconds Passed").apply(lambda x: x[x["Player"]], axis=1)

df=df_Event.pivot(index="Event_order", columns="Event Type", values=["Player", "X", "Y"])

#to flatten columns index:
df.columns=map(lambda x: "_".join(x), df.columns)
0 голосов
/ 16 февраля 2020

Если вам нужна информация о том, «как мяч двигался», включая дриблинг, вы можете сделать следующее:

0: я немного упростил ввод:

d_e = {'seconds':[1,2,3,4,5], 'event' : ['passed', 'received', 'touch', 'passed', 'received'], 'player' : ['Steve', 'Michael','Michael','Michael','George']}
d_x = {'seconds':[1,2,3,4,5], 'Steve': [11.43, 11.45, 10.99, 11.34, 12.43], 'Michael':[12.33, 12.46, 10.33, 10.36, 12.22], 'George': [15.33, 13.22, 14.33, 11.22, 11.78]}
d_y = {'seconds':[1,2,3,4,5], 'Steve': [13.43, 13.45, 12.99, 12.34, 12.00], 'Michael':[9.33, 9.46, 10.53, 12.36, 12.72], 'George': [10.33, 10.22, 10.33, 11.72, 12.78]}
df_e = pd.DataFrame(d_e)
df_x = pd.DataFrame(d_x)
df_y = pd.DataFrame(d_y)

1: объединить X и Y для кортежей для координат:

Конечно, вам не нужно использовать кортежи, и вы можете придерживаться решения, подобного заданному @ckedar, соответственно отрегулируйте ключи позже.

df_merged = df_x.merge(df_y, on=['seconds']).set_index('seconds')
df_merged=df_merged.groupby(df_merged.columns.str.split('_').str[0],axis=1).agg(lambda x : tuple(x.tolist()))

Результат:

                 George         Michael           Steve
seconds                                                
1        (15.33, 10.33)   (12.33, 9.33)  (11.43, 13.43)
2        (13.22, 10.22)   (12.46, 9.46)  (11.45, 13.45)
3        (14.33, 10.33)  (10.33, 10.53)  (10.99, 12.99)
4        (11.22, 11.72)  (10.36, 12.36)  (11.34, 12.34)
5        (11.78, 12.78)  (12.22, 12.72)   (12.43, 12.0)

2: Поместить координаты в фрейм данных события:

df_e['coord'] = df_e.apply(lambda x : df_merged.loc[x['seconds']][x['player']]  ,axis=1)

Результат:

   seconds     event   player           coord
0        1    passed    Steve  (11.43, 13.43)
1        2  received  Michael   (12.46, 9.46)
2        3     touch  Michael  (10.33, 10.53)
3        4    passed  Michael  (10.36, 12.36)
4        5  received   George  (11.78, 12.78)

3: Создать новый df с помощью "from" и " to "information:

Здесь вам придется настраивать различные ключи, если вы не используете кортежи в качестве координат, а скорее X и Y.

df_new = pd.DataFrame(columns=['second', 'from', 'to', 'from_coord', 'to_coord'])
df_new[['second', 'from', 'from_coord']] = df_e[['seconds', 'player', 'coord']].iloc[:-1]
df_new[['to', 'to_coord']] = df_e[['player', 'coord']].iloc[1:].reset_index().drop('index',axis=1)
df_new = df_new.set_index('second')

Результат:

           from       to      from_coord        to_coord
second                                                  
1         Steve  Michael  (11.43, 13.43)   (12.46, 9.46)
2       Michael  Michael   (12.46, 9.46)  (10.33, 10.53)
3       Michael  Michael  (10.33, 10.53)  (10.36, 12.36)
4       Michael   George  (10.36, 12.36)  (11.78, 12.78)

4 (необязательно): теперь вы можете получать пасы и дриблинг:

print('Passes:')
print(df_new[df_new['from'] != df_new['to']])
print('Dribbling:')
print(df_new[df_new['from'] == df_new['to']])

Результат:

Passes:
           from       to      from_coord        to_coord
second                                                  
1         Steve  Michael  (11.43, 13.43)   (12.46, 9.46)
4       Michael   George  (10.36, 12.36)  (11.78, 12.78)

Dribbling:
           from       to      from_coord        to_coord
second                                                  
2       Michael  Michael   (12.46, 9.46)  (10.33, 10.53)
3       Michael  Michael  (10.33, 10.53)  (10.36, 12.36)
0 голосов
/ 10 февраля 2020

Предполагая, что

df_X:
   Seconds  Steve  Michael  George
0      1.0  11.43    12.33   15.33
1      2.0  11.45    12.46   13.22
2      3.0  10.99    10.33   14.33
3      4.0  11.34    10.36   11.22
4      5.0  12.43    12.22   11.78

df_e:
   Seconds     Event   Player
0      1.0    Passed    Steve
1      2.0  Received  Michael
2      3.0     Touch  Michael
3      4.0    Passed  Michael
4      5.0  Received   George

и df_Y похожи на df_X.

Сначала отмените стек df_X и df_Y и соедините их с помощью df_E, чтобы получить всю информацию в одном файле df.

df_X = df_X.set_index('Seconds').stack().rename_axis(['Seconds', 'Player']).rename('X')
df_Y = df_Y.set_index('Seconds').stack().rename_axis(['Seconds', 'Player']).rename('Y')
df_e = df_e.set_index(['Seconds', 'Player'])
df_e = df_e.join(df_X).join(df_Y).reset_index(level='Player')

df_e:
          Player     Event      X      Y
Seconds                                 
1.0        Steve    Passed  11.43  11.43
2.0      Michael  Received  12.46  12.46
3.0      Michael     Touch  10.33  10.33
4.0      Michael    Passed  10.36  10.36
5.0       George  Received  11.78  11.78

Теперь выберите только связанные с передачей события, т.е. Passed и Received

df_pe = df_e[df_e.Event.isin(['Passed', 'Received'])]

Присоединитесь к последовательным событиям:

df_pe = df_pe.join(df_pe.shift(-1), rsuffix='_1')

, а затем сохраните только те проходы, которые были ' Получено '

df_passes = df_pe[df_pe.Event_1 == 'Received']

          Player   Event      X      Y Player_1   Event_1    X_1    Y_1
Seconds                                                                
1.0        Steve  Passed  11.43  11.43  Michael  Received  12.46  12.46
4.0      Michael  Passed  10.36  10.36   George  Received  11.78  11.78
0 голосов
/ 09 февраля 2020

Вашей проблеме не хватает описания - вы используете столбец «Событие» и соответствует «Пропустить», когда значения различаются в данных. Операция сдвига, используемая дважды, вероятно, здесь не рекомендуется, но, возможно, ее можно использовать один раз (все еще можно улучшить):

Passes_df = df_Event.copy()

Passes_df['X_Coordinate_PP'] = Passes_df.apply(lambda x: df_X.loc[df_X['Seconds Passed'] == x['Seconds_Passed']][x['Player']], axis=1)

Passes_df['Y_Coordinate_PP'] = Passes_df.apply(lambda x: df_Y.loc[df_Y['Seconds Passed'] == x['Seconds_Passed']][x['Player']], axis=1)

Passes_df['Passing Player'] = Passes_df.apply(lambda x: x['Player'] if x['Event Type'].contains('Pass') else None)

Passes_df['Receiving Player'] = Passes_df.apply(lambda x: x['Player'] if x['Event Type'].contains('Receive') else None)

Passes_df['X_Coordinate_RP'] = Passes_df['X_Coordinate_PP'].shift(-1)
Passes_df['Y_Coordinate_RP'] = Passes_df['Y_Coordinate_PP'].shift(-1)

Passes_df.drop(columns=['Player'], inplace=True)
Passes_df.dropna(inplace=True)

Дайте мне знать, если это поможет!

...