Boxplot with pandas, groupby, subplotting, computations/descriptive stats, aggregation

Viewed 1842

Let's say multiple soccer matches are being played. A datapoint is generated when a team has lost possession of the ball and the duration of possession is recorded in a text file like so:

'Game','Country','Team','Ball Possession Interval (sec)' 1,Croatia,A,9 2,France,B,11 1,Croatia,A,8 4,Spain,C,10 1,Croatia,B,6 2,France,B,7 3,Germany,C,12 2,France,A,8 ...

Game is a count of games thus far played by a team. For example 2,France,B,7 means that team B from France, now on their 2nd game, has just lost possession of the ball after a duration of 7 seconds.

I would like a plot grouped by country (a subplot for each country), with teams along the axis, and a boxplot of the sum of 'Ball Possession Interval (sec)' per game per team. I tried the following,

df.groupby('Country').boxplot(by='Team',column=*vector of sum of ball possession intervals per game*)

but I don't know what to set column to. I wish I could set it to the following,

df.groupby(['Country','Team','Game'])['Ball Possession Interval (sec)'].sum()

but it doesn't work.

Is there a simple way to do this?

2 Answers

I've learned my desired solution with the use of pivot_table:

plotdf = df.pivot_table(index=['Country','Team','Game'], values='Ball Possession Interval (sec)', aggfunc=np.sum)

From the documentation on pivot_table, values is the column to aggregate, aggfunc is the aggregation method. Now for grouped boxplotting...

plotdf.groupby('Country').boxplot(by='Team', column='Ball Possession Interval (sec)')

This works because pivot_table returns a dataframe object which is amenable to boxplot.

The reason the following didn't work is because it returns a series which is not amenable to boxplot, df.groupby(['Country','Team','Game'])['Ball Possession Interval (sec)'].sum().

This can be done simply by pd.DataFrame.boxplot -

from matplotlib import pyplot as plt
df = pd.DataFrame({'A': ['a1', 'a2']*16,
         'B': ['b1', 'b2', 'b3', 'b4']*8,
         'val': [i for i in range(32)]
     })

df.head()
#    A   B  val
#0  a1  b1    0
#1  a2  b2    1
#2  a1  b3    2
#3  a2  b4    3
#4  a1  b1    4

df.boxplot(column='val', by=['A', 'B']) 
# In your case, df.boxplot(column = 'Ball Possession Interval(s)', by=['Country','Team','Game'])
plt.show() # if you're running this in an ipython terminal

enter image description here

Related