Unterteilen und Kategorisieren von Daten#

Kontinuierliche Daten werden häufig in Bereiche unterteilt oder auf andere Weise für die Analyse gruppiert.

Angenommen, ihr habt Daten über eine Gruppe von Personen in einer Studie, die ihr in diskrete Altersgruppen einteilen möchtet. Hierfür generieren wir uns einen Dataframe mit 250 Einträgen zwischen 0 und 99:

[1]:
import numpy as np
import pandas as pd


ages = np.random.randint(0, 99, 250)
df = pd.DataFrame({"Age": ages})

df
[1]:
Age
0 60
1 16
2 75
3 82
4 40
... ...
245 16
246 35
247 21
248 26
249 87

250 rows × 1 columns

Anschließend bietet uns pandas mit pandas.cut eine einfache Möglichkeit, die Ergebnisse in zehn Bereiche aufzuteilen. Um nur ganze Jahre zu erhalten, setzen wir zusätzlich precision=0:

[2]:
cats = pd.cut(ages, 10, precision=0)

cats
[2]:
[(59.0, 69.0], (10.0, 20.0], (69.0, 78.0], (78.0, 88.0], (39.0, 49.0], ..., (10.0, 20.0], (29.0, 39.0], (20.0, 29.0], (20.0, 29.0], (78.0, 88.0]]
Length: 250
Categories (10, interval[float64, right]): [(-0.1, 10.0] < (10.0, 20.0] < (20.0, 29.0] < (29.0, 39.0] ... (59.0, 69.0] < (69.0, 78.0] < (78.0, 88.0] < (88.0, 98.0]]

Mit pandas.Categorical.categories könnt ihr euch die Kategorien anzeigen lassen:

[3]:
cats.categories
[3]:
IntervalIndex([(-0.1, 10.0], (10.0, 20.0], (20.0, 29.0], (29.0, 39.0], (39.0, 49.0], (49.0, 59.0], (59.0, 69.0], (69.0, 78.0], (78.0, 88.0], (88.0, 98.0]], dtype='interval[float64, right]')

…oder auch nur eine einzelne Kategorie:

[4]:
cats.categories[0]
[4]:
Interval(-0.1, 10.0, closed='right')

Mit pandas.Categorical.codes könnt ihr euch ein Array anzeigen lassen, in dem für jeden Wert die zugehörige Kategorie angezeigt wird:

[5]:
cats.codes
[5]:
array([6, 1, 7, 8, 4, 7, 7, 5, 1, 6, 9, 7, 9, 1, 7, 7, 6, 8, 4, 4, 2, 5,
       5, 4, 9, 0, 5, 7, 9, 2, 7, 2, 4, 2, 8, 1, 2, 2, 0, 2, 1, 3, 1, 1,
       9, 0, 2, 6, 7, 5, 9, 2, 8, 0, 9, 7, 6, 6, 7, 6, 0, 2, 4, 8, 1, 1,
       9, 0, 7, 4, 8, 0, 0, 2, 6, 4, 2, 9, 0, 3, 3, 9, 3, 9, 3, 6, 5, 6,
       3, 5, 6, 3, 0, 3, 1, 2, 4, 3, 9, 5, 8, 0, 4, 2, 0, 9, 6, 9, 7, 0,
       8, 3, 1, 8, 8, 9, 3, 2, 7, 7, 0, 7, 5, 4, 7, 9, 1, 6, 0, 1, 0, 7,
       8, 5, 4, 1, 2, 8, 0, 3, 0, 4, 7, 4, 9, 2, 6, 4, 9, 9, 7, 0, 6, 1,
       9, 9, 9, 5, 1, 4, 8, 6, 9, 8, 5, 1, 8, 5, 4, 4, 8, 5, 1, 4, 7, 3,
       3, 7, 6, 7, 4, 0, 9, 7, 0, 7, 5, 6, 0, 6, 6, 2, 5, 4, 6, 2, 9, 0,
       1, 1, 3, 2, 2, 9, 0, 8, 7, 2, 7, 2, 7, 8, 2, 4, 7, 2, 2, 9, 2, 3,
       7, 2, 0, 6, 1, 4, 3, 0, 7, 8, 1, 2, 0, 3, 6, 8, 1, 9, 9, 1, 0, 2,
       3, 8, 8, 1, 3, 2, 2, 8], dtype=int8)

Mit value_counts können wir uns nun anschauen, wie sich die Anzahl auf die einzelnen Bereiche verteilt:

[6]:
pd.value_counts(cats)
[6]:
(20.0, 29.0]    32
(69.0, 78.0]    31
(88.0, 98.0]    29
(-0.1, 10.0]    28
(10.0, 20.0]    25
(39.0, 49.0]    23
(59.0, 69.0]    23
(78.0, 88.0]    23
(29.0, 39.0]    20
(49.0, 59.0]    16
Name: count, dtype: int64

Auffalend ist, dass die Altersbereiche nicht gleich viele Jahre enthalten, sondern mit 20.0, 29.0 und 69.0, 78.0 zwei Bereiche nur 9 Jahre umfassen. Dies hängt damit zusammen, dass der Altersumfang nur von 0bis 98 reicht:

[7]:
df.min()
[7]:
Age    0
dtype: int64
[8]:
df.max()
[8]:
Age    98
dtype: int64

Mit pandas.qcut wird die Menge hingegen in Bereiche unterteilt, die annähernd gleich groß sind:

[9]:
cats = pd.qcut(ages, 10, precision=0)
[10]:
pd.value_counts(cats)
[10]:
(-1.0, 9.0]     28
(18.0, 26.0]    26
(36.0, 46.0]    26
(62.0, 72.0]    26
(79.0, 92.0]    26
(26.0, 36.0]    25
(46.0, 62.0]    25
(92.0, 98.0]    24
(9.0, 18.0]     22
(72.0, 79.0]    22
Name: count, dtype: int64

Wollen wir gewährleisten, dass jede Altersgruppe tatsächlich genau zehn Jahre umfasst, können wir dies mit pandas.Categorical direkt angeben:

[11]:
age_groups = ["{0} - {1}".format(i, i + 9) for i in range(0, 109, 10)]
cats = pd.Categorical(age_groups)

cats.categories
[11]:
Index(['0 - 9', '10 - 19', '100 - 109', '20 - 29', '30 - 39', '40 - 49',
       '50 - 59', '60 - 69', '70 - 79', '80 - 89', '90 - 99'],
      dtype='object')

Für die Gruppierung wird nun pandas.cut verwendet:

[12]:
df["Age group"] = pd.cut(df.Age, range(0, 111, 10), right=False, labels=cats)

df
[12]:
Age Age group
0 60 60 - 69
1 16 10 - 19
2 75 70 - 79
3 82 80 - 89
4 40 40 - 49
... ... ...
245 16 10 - 19
246 35 30 - 39
247 21 20 - 29
248 26 20 - 29
249 87 80 - 89

250 rows × 2 columns