Панды - расчет коэффициента выигрыша;сгруппировать по двум столбцам и посчитать - PullRequest
2 голосов
/ 20 сентября 2019

У меня есть фрейм данных со следующими столбцами:

| winner |  loser  | tournament |
+--------+---------+------------+
| John   | Steve   |      A     |
+--------+---------+------------+
| Steve  | John    |      B     |
+--------+---------+------------+
| John   | Michael |      A     |
+--------+---------+------------+
| Steve  | John    |      A     |
+--------+---------+------------+

Я хочу рассчитать исторический выигрыш% победителя и проигравшего для данного турнира.введите и поместите его в свой собственный столбец.


Пример заполнения таблицы выше приведен ниже.Игры будут называться (победитель, проигравший, тип).

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


1) Для первой игры (Джон, Стив, а).Нет предыдущих игр типа A. Поэтому мы заполняем 0s.

2) Для второй игры (Steve, John, B).Нет предыдущих игр типа B. Поэтому мы заполняем нулями.

3) Для третьей игры (Джон, Майкл, А).Существуют предыдущие игры типа A, поэтому мы можем получить информацию.Во-первых, Джон - победитель.Он выиграл 1 игру типа А в первом ряду таблицы.Таким образом, мы ставим выигрыш победителей = 1. Джон раньше не проигрывал игру типа A, поэтому мы ставим проигрыш победителей = 0. У Майкла нет истории игр, поэтому мы заполняем выигрыши проигравших = 0 и проигрыши проигравших = 0.

4) Для 4-й игры (Стив, Джон, A).Мы видим, что Стив ранее не выигрывал ни одной игры типа А, поэтому мы ставим победителей побед = 0. Он проиграл 1 игру типа А (первая строка).Таким образом, мы ставим проигрыш победителя = 1. Джон выиграл 2 игры типа А, поэтому проигравший выиграл = 2. Он проиграл

    +--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------+
| winner |  loser  | tournament | winner wins | loser wins | winner losses | loser losses | winner win % | loser win % |
+--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------+
|  John  |  Steve  |      A     |      0      |      0     |       0       |       0      | 0/(0+0)      | 0/(0+0)     |
+--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------+
|  Steve |   John  |      B     |      0      |      0     |       0       |       0      | 0/(0+0)      | 0/(0+0)     |
+--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------+
|  John  | Michael |      A     |      1      |      0     |       0       |       0      | 1/(1+0)      | 0/(0+0)     |
+--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------+
|  Steve |   John  |      A     |      0      |      2     |       1       |       0      | 0/(0+1)      | 2/(2+0)     |
+--------+---------+------------+-------------+------------+---------------+--------------+--------------+-------------

Ответы [ 3 ]

1 голос
/ 20 сентября 2019

Этот результат дает ожидаемый результат:

def win_los_percent(sdf):
    sdf['winner wins'] = sdf.groupby('winner').cumcount()
    sdf['winner losses'] = [(sdf.loc[0:i, 'loser'] == sdf.loc[i, 'winner']).sum() for i in sdf.index]
    sdf['loser losses'] = sdf.groupby('loser').cumcount()
    sdf['loser wins'] = [(sdf.loc[0:i, 'winner'] == sdf.loc[i, 'loser']).sum() for i in sdf.index]
    sdf['winner win %'] = sdf['winner wins'] / (sdf['winner wins'] + sdf['winner losses'])
    sdf['loser win %'] = sdf['loser wins'] / (sdf['loser wins'] + sdf['loser losses'])
    return sdf

ddf = df.groupby('tournament').apply(win_los_percent)

Используя предоставленные данные, ddf:

  winner    loser tournament  winner wins  winner losses  loser losses  loser wins  winner win %  loser win %
0   John    Steve          A            0              0             0           0           NaN          NaN
1  Steve     John          B            0              0             0           0           NaN          NaN
2   John  Michael          A            1              0             0           0           1.0          NaN
3  Steve     John          A            0              1             0           2           0.0          1.0

pandas groupby используется для группировкиданные того же турнира и передайте подкадр в функцию win_los_percent.Возвращаемое значение этой функции возвращается для построения окончательного кадра данных.

Для каждого подмножества функция вычисляет несколько столбцов:

  • sdf['winner wins'] и sdf['loser losses'] получаютсяиспользуя cumcount : для каждой строки этот метод подсчитывает предыдущие вхождения значения (имя игрока) в столбце группировки.
  • получение sdf['winner losses'] и sdf['loser wins'] немного большеуточнено, поскольку нам нужно посчитать предыдущее вхождение значения (имени игрока) в другом столбце.
    Понимание списка повторяется по индексу фрейма данных, чтобы выбрать предыдущие строки и проверить, является ли имя игрока в столбце 'winner'равно имени игрока в текущей строке в столбце loser или наоборот.sum() позволяет посчитать значения True: True - 1, False - 0, сумма дает желаемый результат: сколько раз имя игрока присутствует в предыдущих строках.
  • Столбцы в процентах получены свекторизации.Где результат NaN, потому что есть деление на 0.
0 голосов
/ 20 сентября 2019

Вот моя попытка

Объяснение

  1. Создайте новый фрейм данных, объединив столбцы «победитель» и «проигравший» со столбцом «игрок» и указав выигрыш/ проиграть по столбцу "выиграно"
  2. Сгруппировать новый фрейм данных по "игроку" и "турниру" и рассчитать% выигрыша, используя функцию "calc_winning_percent" для каждой строки
  3. теперь делит win% от new_df на победителяпобедить% и проиграть победить% и назначить обратно на df
d = {
    "winner": "John Steve John Steve".split(),
    "loser": "Steve John Michael John".split(),
    "tournament": "A B A A".split()
}

def calc_wining_percent (group):
    group["wining_percent"] = group["won"].cumsum().shift()/np.arange(1, len(group)+1)
    return group

df = pd.DataFrame(d)

new_df =  pd.DataFrame(np.ravel(df[["winner", "loser"]]), columns=["player"])
new_df["won"]= np.r_[np.ones(len(df)), np.zeros(len(df))]
new_df["tournament"] = np.tile(df["tournament"],2)

new_df = new_df.groupby(["player", "tournament"]).apply(calc_wining_percent)

df["winner win %"] = new_df["wining_percent"].values.reshape(-1,2)[:,0]
df["loser win %"] = new_df["wining_percent"].values.reshape(-1,2)[:,1]

display("result", df)
0 голосов
/ 20 сентября 2019

Первое решение, которое приходит мне в голову, - использовать объектно-ориентированное программирование .Я предлагаю некоторые рекомендации по реализации ниже.

Вы можете создать класс player с атрибутами firstName, lastName, numberWins и numberLosses.В конструкторе вы можете установить numberWins и numberLosses на 0. Я также рекомендую добавить методы wins и loses, которые, соответственно, увеличат numberWins и numberLosses на 1.

После каждого матча вы можете увеличивать атрибуты в соответствии с результатом матча (например, если я проигрываю, мое количество потерь увеличивается на 1, если я выигрываю, мое количество побед увеличивается на 1).В любой момент вы можете получить исторический выигрыш% с помощью player.numberWins / (player.numberWins + player.numberLosses).

. Если вы хотите вычислить это соотношение по турниру, вы можете определить атрибуты numberWins и numberLosses как фреймы данных.где каждый столбец представляет турнир (например, метки столбцов A, B, C ...), и каждый ряд соответствует соответствующему количеству побед.Затем вы также добавили бы аргумент в методы wins и loses, чтобы указать турнир под рукой.(Вы могли бы даже определить класс score для большей гибкости)

В вашем большом фрейме данных, где вы записываете совпадения, вы можете фактически хранить два объекта игрока (вместо Strings, идентифицирующих игроков, как вы делаете правильно).сейчас) и меняйте их атрибуты по ходу дела.

Тогда может быть какое-то быстрое математическое колдовство.Однако, на первый взгляд, объектно-ориентированная реализация выглядит особенно уместной в вашем случае (в конце концов, игрок - это объект со своими собственными атрибутами и методами ...).

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