Python — создание столбца, содержащего имя соперника команды, на основе информации в фрейме данных

#python #pandas

Вопрос:

У меня есть фрейм данных (называемый «игры»), который содержит список баскетбольных игр по ходу игры, в котором я записываю серии очков в отдельных играх (идентификатор игры определяет конкретную игру). Фрейм данных сортируется по совпадениям (т. е. по идентификатору игры).

Пример набора данных «игры»:

 GameID TeamID Scoring Streak  0 nbaG1 A 23  1 nbaG1 B 12  2 nbaG1 B 11  3 nbaG1 A 24  4 nbaG1 B 21  5 nbaG2 C 15  6 nbaG2 C 12  7 nbaG2 D 17  8 nbaG2 C 11 9 nbaG2 D 21  10 nbaG3 E 10  11 nbaG3 F 12  12 nbaG3 F 14  

Из этого фрейма данных я хотел бы просто создать столбец, в котором отображается название команды соперника в соответствующем матче. Например, в игре 1 (nbaG1) это команда А против Б. Итак, если команда А забьет, в новой колонке «противники» должно быть написано «В». Однако я понятия не имею, как сканировать имена в каждой игре и возвращать значение команды противника…и я не нашел советов в других потоках.

Желаемый результат для моего набора данных «игры»:

 GameID TeamID Scoring Streak Opponents 0 nbaG1 A 23 B 1 nbaG1 B 12 A 2 nbaG1 B 11 A 3 nbaG1 A 24 B 4 nbaG1 B 21 A 5 nbaG2 C 15 D 6 nbaG2 C 12 D 7 nbaG2 D 17 C 8 nbaG2 C 11 D 9 nbaG2 D 21 C 10 nbaG3 E 10 F 11 nbaG3 F 12 E 12 nbaG3 F 14 E  

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

1. Можете ли вы прислать нам часть своего кода, чтобы мы могли воспроизвести его?

2. @VictorSaraivaRocha скопируйте фрейм данных операции и сделайте df = pd.read_clipboard(sep=r"ss ")

3. Спасибо, Пранав Хосангади! Я этого не знал.

Ответ №1:

Во-первых, сгруппируйте свой фрейм данных по идентификатору игры и вызовите .unique() , чтобы получить две команды, которые играют в игру

 teams = df.groupby("GameID")["TeamID"].unique()  # game_teams : GameID nbaG1 [A, B] nbaG2 [C, D] nbaG3 [E, F]  

Затем используйте это, чтобы просмотреть обе команды в каждой игре и добавить столбец в исходный кадр данных:

 df["Teams"] = teams[df["GameID"]].to_list()  # df:   GameID TeamID Scoring Streak Teams 0 nbaG1 A 23 [A, B] 1 nbaG1 B 12 [A, B] 2 nbaG1 B 11 [A, B] 3 nbaG1 A 24 [A, B] 4 nbaG1 B 21 [A, B] 5 nbaG2 C 15 [C, D] 6 nbaG2 C 12 [C, D] 7 nbaG2 D 17 [C, D] 8 nbaG2 C 11 [C, D] 9 nbaG2 D 21 [C, D] 10 nbaG3 E 10 [E, F] 11 nbaG3 F 12 [E, F] 12 nbaG3 F 14 [E, F]  

Наконец, apply функция для каждой строки, которая берет элемент из Teams того, что не находится в TeamID

 def select_opponent(row):  for team in row["Teams"]:  if team != row["TeamID"]:  return team  return None  df["Opponent"] = df.apply(select_opponent, axis=1)  # df:   GameID TeamID Scoring Streak Teams Opponent 0 nbaG1 A 23 [A, B] B 1 nbaG1 B 12 [A, B] A 2 nbaG1 B 11 [A, B] A 3 nbaG1 A 24 [A, B] B 4 nbaG1 B 21 [A, B] A 5 nbaG2 C 15 [C, D] D 6 nbaG2 C 12 [C, D] D 7 nbaG2 D 17 [C, D] C 8 nbaG2 C 11 [C, D] D 9 nbaG2 D 21 [C, D] C 10 nbaG3 E 10 [E, F] F 11 nbaG3 F 12 [E, F] E 12 nbaG3 F 14 [E, F] E  

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

1. Хотя ваш ответ в точности соответствует ожиданиям ОП, я не согласен с тем, что у вас нечетное количество строк. Что вы об этом думаете?

2. @Corralien Я не уверен, что понимаю. Почему имеет значение нечетное количество строк, если в каждой GameID из них всего две команды? Я думаю, что ваше замешательство связано с тем фактом, что в игре более двух участников (более одного на команду за игру).

3. @Corralien Я не уверен, что представляет собой «серия очков» OP, но если вы замените ее, например, «Игроком, набравшим очки», я думаю, это будет иметь больше смысла: в игре может быть нечетное количество игроков, набравших очки, но это не влияет на то, кем были соперники

4. Да, наверное, вы правы! 1 за ваш ответ.

5. Спасибо, Пранав, за этот код, который работал как надо и всегда возвращает команду противника вместе со списком команд за игру 🙂 Просто для уточнения в столбце «Полосы очков» указано количество неотвеченных очков, набранных соответствующей командой. Так, например, в первом ряду команда А набрала 23 очка подряд, без каких-либо очков команды Б. Так что действительно нечетное количество строк вполне вероятно 🙂

Ответ №2:

Для общего подхода, который также работал бы с более чем двумя командами за игру, вы могли бы использовать наборы: сначала вычислите набор команд для каждой игры, затем получите противников для каждой строки, вычисляя разницу в наборе между набором команд и набором, содержащим только саму команду.

 teams_per_game = games.groupby('GameID')['TeamID'].apply(set)  opponents = [] for i in games.index:  opponents.append((teams_per_game.loc[games.loc[i, 'GameID']]   - {games.loc[i, 'TeamID']}).pop())  games['Opponents'] = opponents  

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

1. Спасибо, Арне, это сработало как заклинание и возвращает именно то, что мне нужно, даже для моего большого набора данных!