Как выполнять операции между разными столбцами после группирования по столбцу в pandas?

#python #pandas #pandas-groupby

#python #pandas #pandas-groupby

Вопрос:

Я не уверен, что я сделал, но я ожидал того же результата для этих двух методов, чтобы вычислить среднее значение попадания для бейсболистов из набора данных Lahmans Baseball:

 import numpy as np
import pandas as pd

batting = pd.read_csv('https://github.com/bhishanpdl/Datasets/blob/master/Lahman_batting.csv?raw=true')

# create new col
batting['ba'] = batting['H'] / batting['AB']

# groupby for each baseball player
print(batting.groupby('playerID')[['ba','AB']]
             .sum().head().reset_index())
  

Это дает:

     playerID        ba     AB
0  aardsda01  0.000000      4
1  aaronha01  6.924731  12364
2  aaronto01  1.544619    944
3   aasedo01  0.000000      5
4   abadan01  0.117647     21
  

Но, глядя только на второго игрока, результат неверен.

 # sanity check for aaronha01
a = batting.query(""" playerID == 'aaronha01'  """)['H'].sum()
b = batting.query(""" playerID == 'aaronha01'  """)['AB'].sum()
a,b,a/b
(3771, 12364, 0.30499838240051763)
  

Как исправить результат?

Для второго вызываемого игрока aaronha01 результат должен быть 0.30499838240051763 , но groupby выдает 6.924731 .

Обновить
В R мы получаем правильное, но я искал путь в Pandas:

 library(Lahman)

batting = as_tibble(Lahman::Batting)
batters = batting  %>%  
    group_by(playerID) %>%  
    summarize(
      ba = sum(H, na.rm = TRUE) / sum(AB, na.rm = TRUE),
      ab = sum(AB, na.rm = TRUE)
    )

head(batters)

playerID    ba  ab
aardsda01   0.0000000   4
aaronha01   0.3049984   12364
aaronto01   0.2288136   944
aasedo01    0.0000000   5
abadan01    0.0952381   21
abadfe01    0.1111111   9
  

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

1. @ALollz Спасибо за информацию, но, пожалуйста, помогите решить проблему с помощью groupby, требуемое значение для второго игрока равно 0.3.

Ответ №1:

Вы можете суммировать оба столбца, а затем вычислить среднее значение после groupby:

 gp = batting.groupby('playerID')[['H', 'AB']].sum()
gp['ba'] = gp.H/gp.AB
print(gp)

#              H     AB        ba
#playerID                        
#aardsda01     0      4  0.000000
#aaronha01  3771  12364  0.304998
#aaronto01   216    944  0.228814
#aasedo01      0      5  0.000000
#abadan01      2     21  0.095238
#abadfe01      1      9  0.111111
#abadijo01    11     49  0.224490
  

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

 batting.groupby('playerID')[['H', 'AB']].sum().eval('ab = H / AB')
  

Чтобы объяснить вашу первоначальную проблему, приведенное выше среднее значение ватина, где каждому AB присваивается одинаковый вес. В вашей первоначальной формулировке, сначала вычисляя a 'ba' для каждой строки, а затем беря среднее значение, вы придаете равный вес каждому наблюдению (в данном случае в основном каждый год) вместо каждого отдельного человека. Если бы вы взвесили это среднее значение по количеству АБС в каждой строке, вы бы получили тот же ответ, что и выше.

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

1. Спасибо, если мой набор данных больше, чем 15k строки, которые я люблю использовать eval and query в pandas, в противном случае они работают немного медленнее.