value_counts() - monitoimityökalu lukumäärien laskemiseen

Frekvenssitaulukot ja ristiintaulukoinnit voin laskea crosstab()-toiminnolla, mutta taitavalle käyttäjälle value_counts() on kätevämpi ja antaa enemmän mahdollisuuksia.

value_counts()-toimintoa käytettäessä täytyy olla huolellinen ja tuntea funktion käyttäytyminen eri tilanteissa. Seuraavassa esittelen value_counts()-funktion käyttöön liittyviä niksejä.

In [1]:
import pandas as pd

# Avaan esimerkkidatan
df=pd.read_excel('http://taanila.fi/data1.xlsx')

# Luon dataan yhden object-tyyppisen muuttujan
df['työteht_obj'] = df['työteht'].replace({1: 'Erittäin tyytymätön',2:'Tyytymätön',3:'Siltä väliltä',
                                       4:'Tyytyväinen',5:'Erittäin tyytyväinen'})

# Nyt datassa on kokonaisluku (int64), liukuluku (float64) ja object-tyyppisiä muuttujia
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 82 entries, 0 to 81
Data columns (total 17 columns):
nro            82 non-null int64
sukup          82 non-null int64
ikä            82 non-null int64
perhe          82 non-null int64
koulutus       81 non-null float64
palveluv       80 non-null float64
palkka         82 non-null int64
johto          82 non-null int64
työtov         81 non-null float64
työymp         82 non-null int64
palkkat        82 non-null int64
työteht        82 non-null int64
työterv        47 non-null float64
lomaosa        20 non-null float64
kuntosa        9 non-null float64
hieroja        22 non-null float64
työteht_obj    82 non-null object
dtypes: float64(7), int64(9), object(1)
memory usage: 11.0+ KB
In [2]:
# Oletuksena value_counts() tuottaa frekvenssien mukaisen järjestyksen
df['työymp'].value_counts()
Out[2]:
3    30
4    23
5    11
2     9
1     9
Name: työymp, dtype: int64
In [3]:
# Jos tulos ei ole dataframe, niin to_frame() muuntaa sen dataframeksi
df['työymp'].value_counts().to_frame()
Out[3]:
työymp
3 30
4 23
5 11
2 9
1 9

Kokonaisluku (int) ja value_counts()

In [4]:
# Lisäparametri sort=False kumoaa frekvenssien mukaan järjestämisen
# Kokonaisluku (int) -tyyppisen muuttujan arvot järjestyvät kokonaislukujen suuruusjärjestykseen
df['työymp'].value_counts(sort = False)
Out[4]:
1     9
2     9
3    30
4    23
5    11
Name: työymp, dtype: int64

Liukuluku (float) ja value_counts()

In [5]:
# Järjestys yllättää, jos tarkasteltava muuttuja on liukuluku (float) -tyyppinen
df['työtov'].value_counts(sort = False)
Out[5]:
3.0    16
5.0    27
4.0    35
2.0     3
Name: työtov, dtype: int64
In [6]:
# Indeksin mukaan järjestäminen laittaa liukuluvut lukujen mukaiseen järjestykseen
df['työtov'].value_counts().sort_index()
Out[6]:
2.0     3
3.0    16
4.0    35
5.0    27
Name: työtov, dtype: int64

Object-tyyppinen muuttuja ja value_counts()

In [7]:
# Järjestys yllättää, jos tarkasteltava muuttuja on object-tyyppinen
df['työteht_obj'].value_counts(sort = False)
Out[7]:
Tyytyväinen             25
Siltä väliltä           29
Tyytymätön              15
Erittäin tyytyväinen     8
Erittäin tyytymätön      5
Name: työteht_obj, dtype: int64
In [8]:
# Indeksin mukaan järjestäminen laittaa object-tyypin aakkosjärjestykseen
# Tämä ei useinkaan ole haluttu järjestys
df['työteht_obj'].value_counts().sort_index()
Out[8]:
Erittäin tyytymätön      5
Erittäin tyytyväinen     8
Siltä väliltä           29
Tyytymätön              15
Tyytyväinen             25
Name: työteht_obj, dtype: int64
In [9]:
# Halutun järjestyksen saan listan ja reindex()-toiminnon avulla
tyytyväisyydet = ['Erittäin tyytymätön', 'Tyytymätön', 'Siltä väliltä', 'Tyytyväinen', 'Erittäin tyytyväinen']
df['työteht_obj'].value_counts().reindex(tyytyväisyydet)
Out[9]:
Erittäin tyytymätön      5
Tyytymätön              15
Siltä väliltä           29
Tyytyväinen             25
Erittäin tyytyväinen     8
Name: työteht_obj, dtype: int64

value_counts() osaa näyttää myös puuttuvat arvot

In [10]:
# Voin halutessani näyttää puuttuvat arvot
df['työtov'].value_counts(dropna = False).sort_index()
Out[10]:
 2.0     3
 3.0    16
 4.0    35
 5.0    27
NaN      1
Name: työtov, dtype: int64
In [11]:
# Muunnan tuloksen dataframeksi
df1 = df['työtov'].value_counts(dropna = False).sort_index().to_frame()

# Lasken prosenttisarakkeen value_counts()-toiminnolla
df1['%'] = df['työtov'].value_counts(normalize = True, dropna = False).to_frame() * 100

# Korvaan indeksin luvut tekstiarvoilla
df1.index = ['Tyytymätön', 'Siltä väliltä', 'Tyytyväinen', 'Erittäin tyytyväinen', 'Vastaus puuttuu']

# Lisään Yhteensä-rivin
df1.loc['Yhteensä'] = df1.sum()

# Sarakkeiden muotoilu
df1.style.format({'työtov' : '{:.0f}', '%' : '{:.1f} %'})
Out[11]:
työtov %
Tyytymätön 3 3.7 %
Siltä väliltä 16 19.5 %
Tyytyväinen 35 42.7 %
Erittäin tyytyväinen 27 32.9 %
Vastaus puuttuu 1 1.2 %
Yhteensä 82 100.0 %

value_counts() osaa myös luokitella

In [12]:
# Luokkarajat
bins = [1500, 2000, 2500, 3000, 8000]

df['palkka'].value_counts(bins = bins).sort_index()
Out[12]:
(1499.999, 2000.0]    19
(2000.0, 2500.0]      28
(2500.0, 3000.0]      22
(3000.0, 8000.0]      13
Name: palkka, dtype: int64

groupby() + value_counts() mahdollistaa ristiintaulukoinnin

In [13]:
df2=df.groupby('sukup')['palkka'].value_counts(sort=False, bins=bins).unstack('sukup')

# Sarakkeessa voi olla vain yhdentyyppistä tietoa
# Yhteensä-rivin lisäämiseksi interval-tyypin luokkarajat täytyy muuntaa merkkijonoiksi (str)
df2.index=df2.index.astype(str)
df2.loc['Yhteensä']=df2.sum()

# Sarakeotsikot
df2.columns=['Mies', 'Nainen']

df2
Out[13]:
Mies Nainen
palkka
(1499.999, 2000.0] 13 6
(2000.0, 2500.0] 20 8
(2500.0, 3000.0] 17 5
(3000.0, 8000.0] 13 0
Yhteensä 63 19

value_counts() mahdollistaa usean samalla asteikolla mitatun muuttujan frekvenssitaulukon

In [14]:
# Lasken lukumääriä value_counts()-funktiolla ja muutan tuloksen dataframeksi
df3 = df['johto'].value_counts(sort = False, normalize = True).to_frame()

# Lisään dataframeen uusia sarakkeita
df3['työtov'] = df['työtov'].value_counts(sort = False, normalize = True)
df3['työymp'] = df['työymp'].value_counts(sort = False, normalize = True)
df3['palkkat'] = df['palkkat'].value_counts(sort = False, normalize = True)
df3['työteht'] = df['työteht'].value_counts(sort = False, normalize = True)

# Riviotsikot aiemmin määritellystä tyytyväisyys-listasta
df3.index = tyytyväisyydet

# Yhteensä-rivi
df3.loc['Yhteensä'] = df3.sum()

# Loppusilaus
(df3*100).style.format('{:.1f} %')
Out[14]:
johto työtov työymp palkkat työteht
Erittäin tyytymätön 8.5 % nan % 11.0 % 40.2 % 6.1 %
Tyytymätön 19.5 % 3.7 % 11.0 % 23.2 % 18.3 %
Siltä väliltä 36.6 % 19.8 % 36.6 % 23.2 % 35.4 %
Tyytyväinen 28.0 % 43.2 % 28.0 % 12.2 % 30.5 %
Erittäin tyytyväinen 7.3 % 33.3 % 13.4 % 1.2 % 9.8 %
Yhteensä 100.0 % 100.0 % 100.0 % 100.0 % 100.0 %