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 pandas as pd
import numpy as np

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

df
[1]:
Age
0 12
1 6
2 47
3 14
4 73
... ...
245 97
246 17
247 24
248 91
249 48

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]:
[(10.0, 20.0], (-0.1, 10.0], (39.0, 49.0], (10.0, 20.0], (69.0, 78.0], ..., (88.0, 98.0], (10.0, 20.0], (20.0, 29.0], (88.0, 98.0], (39.0, 49.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([1, 0, 4, 1, 7, 2, 7, 4, 0, 7, 7, 3, 0, 1, 0, 5, 9, 8, 8, 9, 8, 4,
       6, 0, 1, 7, 0, 1, 4, 2, 2, 1, 6, 8, 6, 2, 9, 5, 5, 5, 4, 7, 0, 2,
       2, 0, 8, 7, 7, 7, 6, 9, 8, 1, 9, 9, 1, 9, 8, 5, 8, 2, 4, 2, 8, 4,
       5, 2, 2, 2, 3, 8, 4, 2, 5, 6, 3, 4, 8, 1, 2, 7, 8, 3, 7, 3, 9, 4,
       0, 4, 9, 8, 9, 6, 2, 6, 9, 8, 4, 9, 7, 1, 4, 5, 9, 4, 9, 8, 5, 2,
       2, 3, 5, 6, 9, 9, 5, 7, 7, 1, 3, 8, 0, 2, 7, 4, 2, 7, 5, 4, 5, 6,
       7, 4, 8, 2, 2, 7, 1, 6, 3, 9, 4, 3, 1, 2, 0, 9, 3, 6, 2, 3, 6, 1,
       2, 5, 3, 1, 6, 2, 3, 9, 5, 5, 6, 5, 9, 4, 9, 3, 8, 0, 7, 6, 3, 3,
       7, 4, 8, 8, 9, 7, 2, 2, 9, 8, 0, 9, 3, 7, 0, 0, 8, 5, 9, 1, 9, 4,
       6, 3, 7, 2, 7, 1, 0, 1, 7, 2, 3, 6, 6, 5, 4, 7, 9, 1, 7, 6, 3, 8,
       8, 1, 1, 7, 6, 0, 9, 6, 6, 6, 4, 5, 5, 7, 0, 4, 8, 6, 3, 7, 7, 0,
       8, 5, 4, 9, 1, 2, 9, 4], 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]:
(69.0, 78.0]    31
(88.0, 98.0]    30
(20.0, 29.0]    29
(39.0, 49.0]    26
(78.0, 88.0]    26
(59.0, 69.0]    24
(10.0, 20.0]    22
(49.0, 59.0]    22
(29.0, 39.0]    21
(-0.1, 10.0]    19
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]:
(12.0, 23.0]    27
(52.0, 64.0]    27
(-1.0, 12.0]    26
(64.0, 73.0]    26
(91.0, 98.0]    25
(23.0, 31.0]    24
(31.0, 42.0]    24
(42.0, 52.0]    24
(81.0, 91.0]    24
(73.0, 81.0]    23
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 12 10 - 19
1 6 0 - 9
2 47 40 - 49
3 14 10 - 19
4 73 70 - 79
... ... ...
245 97 90 - 99
246 17 10 - 19
247 24 20 - 29
248 91 90 - 99
249 48 40 - 49

250 rows × 2 columns