#python #pandas #pandas-groupby
#python #pandas #pandas-groupby
Вопрос:
У меня есть a pd.Dataframe
со столбцами R_fighter
— имя первого бойца, B_fighter
— имя второго бойца и Winner
столбец. Данные сортируются в хронологическом порядке, и я хотел бы добавить столбец, где, если бойцы ранее встречались, и R
боец выиграл, чтобы установить значение -1
, если B
боец выиграл — 1
, и 0
в противном случае. Если было гарантировано, что бойцы могут встретиться снова в том же порядке ( R_fighter
снова R_fighter
, B_fighter
снова B_fighter
), тогда можно сделать следующее:
last_winner_col = np.zeros(df_train.shape[0])
for x in df_train.groupby(['R_fighter', 'B_fighter'])['Winner']:
last_winner = 0
for idx, val in zip(x[1].index, x[1].values):
last_winner_col[idx] = last_winner
last_winner = 2 * val - 1
И добавьте результат pd.Series
в набор данных. Однако их роль может измениться в последующей битве. Решение, которое приходит мне на ум, очень длинное и громоздкое. Я был бы признателен, если бы кто-нибудь предложил удобный способ отслеживания предыдущего победителя, чтобы учесть возможность изменения порядка бойцов?
Ответ №1:
Вы можете создать «отсортированную» версию ваших двух комбатантов и использовать ее:
import pandas as pd
a = list("ABCDEFGH1234")
b = list("12341234ABCD")
win = list("ABCD12341234")
df = pd.DataFrame({"R_fighter":a, "B_fighter":b, "Winner":win})
# make a column with fixed order
df["combatants"] = df[['R_fighter', 'B_fighter']].apply(lambda x: sorted(x), axis=1)
# or simply set the result
df["w"] = df[['R_fighter', 'B_fighter', 'Winner']].apply(lambda x: '-1'
if x[2]==x[0]
else ('1' if x[2]==x[1]
else '0'), axis=1 )
print(df)
Вывод:
R_fighter B_fighter Winner combatants w
0 A 1 A [1, A] -1
1 B 2 B [2, B] -1
2 C 3 C [3, C] -1
3 D 4 D [4, D] -1
4 E 1 1 [1, E] 1
5 F 2 2 [2, F] 1
6 G 3 3 [3, G] 1
7 H 4 4 [4, H] 1
8 1 A 1 [1, A] -1
9 2 B 2 [2, B] -1
10 3 C 3 [3, C] -1
11 4 D 4 [4, D] -1
Чтобы определить победителя на основе 'combatants'
(который содержит отсортированные имена), вы можете сделать:
df["w_combatants"] = df[['combatants', 'Winner']].apply(lambda x: '-1'
if x[1]==x[0][0]
else ('1' if x[1]==x[0][1]
else '0'), axis=1 )
чтобы получить
R_fighter B_fighter Winner combatants w w_combatants
0 A 1 A [1, A] -1 1
1 B 2 B [2, B] -1 1
2 C 3 C [3, C] -1 1
3 D 4 D [4, D] -1 1
4 E 1 1 [1, E] 1 -1
5 F 2 2 [2, F] 1 -1
6 G 3 3 [3, G] 1 -1
7 H 4 4 [4, H] 1 -1
8 1 A 1 [1, A] -1 -1
9 2 B 2 [2, B] -1 -1
10 3 C 3 [3, C] -1 -1
11 4 D 4 [4, D] -1 -1
Ответ №2:
На основании ответа @Patrick Artner я предложил следующее решение:
df_train[['fighters']] = df_train[['R_fighter', 'B_fighter']].apply(lambda x :tuple(sorted(x)), axis = 1)
df_train[['fighter_ord_changed']] = df_train[['R_fighter', 'B_fighter']].apply(lambda x : np.argsort(x)[0], axis = 1)
last_winner_col = np.zeros(df_train.shape[0])
for x in df_train.groupby('fighters')['Winner']:
last_winner = 0
for idx, val in zip(x[1].index, x[1].values):
flag = df_train['fighter_ord_changed'][idx]
last_winner_col[idx] = -last_winner if flag else last_winner
last_winner = 2 * (val ^ flag) - 1