111

I was experimenting with the kaggle.com Titanic data set (data on every person on the Titanic) and came up with a gender breakdown like this:

df = pd.DataFrame({'sex': ['male'] * 577 + ['female'] * 314})
gender = df.sex.value_counts()
gender

male   577
female 314 

I would like to find out the percentage of each gender on the Titanic.

My approach is slightly less than ideal:

from __future__ import division
pcts = gender / gender.sum()
pcts

male      0.647587
female    0.352413

Is there a better (more idiomatic) way?

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Tim Stewart
  • 5,350
  • 2
  • 30
  • 45

4 Answers4

255

This function is implemented in pandas, actually even in value_counts(). No need to calculate :)

just type:

df.sex.value_counts(normalize=True)

which gives exactly the desired output.

Please note that value_counts() excludes NA values, so numbers might not add up to 1. See here: http://pandas-docs.github.io/pandas-docs-travis/generated/pandas.Series.value_counts.html (A column of a DataFrame is a Series)

fanfabbb
  • 2,734
  • 1
  • 14
  • 12
  • 9
    Any thing which gives as below `male 577 0.647587 female 314 0.352413` which can both, counts and pctcnts side by side ?? – subro Oct 30 '17 at 14:36
38

In case you wish to show percentage one of the things that you might do is use value_counts(normalize=True) as answered by @fanfabbb.

With that said, for many purposes, you might want to show it in the percentage out of a hundred.

That can be achieved like so:

gender = df.sex.value_counts(normalize=True).mul(100).round(1).astype(str) + '%'

In this case, we multiply the results by hundred, round it to one decimal point and add the percentage sign.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Shahar
  • 2,101
  • 18
  • 23
30

If you want to merge counts with percentage, can use:

c = df.sex.value_counts(dropna=False)
p = df.sex.value_counts(dropna=False, normalize=True)
pd.concat([c,p], axis=1, keys=['counts', '%'])
Layla
  • 413
  • 4
  • 7
15

I think I would probably do this in one go (without importing division):

1. * df.sex.value_counts() / len(df.sex)

or perhaps, remembering you want a percentage:

100. * df.sex.value_counts() / len(df.sex)

Much of a muchness really, your way looks fine too.

Andy Hayden
  • 359,921
  • 101
  • 625
  • 535