코드 보기
import numpy as np
import pandas as pd
df = pd.DataFrame({"A": ["a", "b", "c", "a"]})
df["A"] = df["A"].astype("category")
df["A"]0 a
1 b
2 c
3 a
Name: A, dtype: category
Categories (3, object): ['a', 'b', 'c']
이 장에서는 범주형 변수, 즉 고정되고 알려진 가능한 값의 집합을 가진 변수를 다루는 방법을 소개합니다. 이 장은 pandas 문서의 도움을 많이 받았습니다.
이 장에서는 pandas 데이터 분석 패키지를 사용합니다.
파이썬의 모든 것은 타입을 가지고 있으며, pandas 데이터 프레임 열의 데이터도 마찬가지입니다. 숫자나 문자열에는 익숙하시겠지만, 범주형 데이터를 위한 Categorical이라는 특별한 데이터 타입도 있습니다. (적절한 경우) 범주형 변수를 사용하면 다음과 같은 몇 가지 장점이 있습니다:
pandas 열의 범주형 데이터 값은 지정된 범주 내에 있거나 np.nan 값을 가집니다.
범주형 데이터 열을 만들어 보겠습니다:
import numpy as np
import pandas as pd
df = pd.DataFrame({"A": ["a", "b", "c", "a"]})
df["A"] = df["A"].astype("category")
df["A"]0 a
1 b
2 c
3 a
Name: A, dtype: category
Categories (3, object): ['a', 'b', 'c']
표시된 시리즈의 하단에 추가 정보가 나타나는 것을 확인하세요. 이것이 범주형(categorical) 열 타입일 뿐만 아니라, ‘a’, ‘b’, ’c’라는 세 가지 값을 가지고 있다는 것을 알려줍니다.
또한 pd.cut()과 같은 특수 함수를 사용하여 데이터를 이산적인 빈(bins)으로 그룹화할 수 있습니다. 다음은 범주의 레이블을 직접 지정하는 예제입니다:
df = pd.DataFrame({"value": np.random.randint(0, 100, 20)})
labels = [f"{i} - {i + 9}" for i in range(0, 100, 10)]
df["group"] = pd.cut(df.value, range(0, 105, 10), right=False, labels=labels)
df.head()| value | group | |
|---|---|---|
| 0 | 2 | 0 - 9 |
| 1 | 63 | 60 - 69 |
| 2 | 90 | 90 - 99 |
| 3 | 43 | 40 - 49 |
| 4 | 65 | 60 - 69 |
위의 예제에서 group 열은 범주형 타입입니다.
범주형 변수를 만드는 또 다른 방법은 pd.Categorical() 함수를 직접 사용하는 것입니다:
raw_cat = pd.Categorical(
["a", "b", "c", "a", "d", "a", "c"], categories=["b", "c", "d"]
)
raw_cat[NaN, 'b', 'c', NaN, 'd', NaN, 'c']
Categories (3, object): ['b', 'c', 'd']
그런 다음 이를 데이터 프레임에 넣을 수 있습니다:
df = pd.DataFrame(raw_cat, columns=["cat_type"])
df["cat_type"]0 NaN
1 b
2 c
3 NaN
4 d
5 NaN
6 c
Name: cat_type, dtype: category
Categories (3, object): ['b', 'c', 'd']
우리가 지정한 범주에 속하지 않는 모든 값은 NaN으로 나타납니다. 이에 대한 자세한 내용은 누락된 값 (Missing Values) 에서 확인할 수 있습니다.
순서가 있는(ordered) 범주를 생성할 수도 있습니다:
ordered_cat = pd.Categorical(
["a", "b", "c", "a", "d", "a", "c"],
categories=["a", "b", "c", "d"],
ordered=True,
)
ordered_cat['a', 'b', 'c', 'a', 'd', 'a', 'c']
Categories (4, object): ['a' < 'b' < 'c' < 'd']
범주형 데이터는 categories와 ordered 속성을 가집니다. 이들은 각각 가능한 값의 목록과 순서가 중요한지 여부를 나타냅니다. 이 속성들은 .cat.categories와 .cat.ordered로 노출됩니다. 범주와 순서를 수동으로 지정하지 않으면 전달된 인수로부터 추론됩니다.
몇 가지 예제를 살펴보겠습니다:
df["cat_type"].cat.categoriesIndex(['b', 'c', 'd'], dtype='object')
df["cat_type"].cat.orderedFalse
범주형 데이터가 정렬되어 있으면(.cat.ordered == True), 범주의 순서가 의미를 가지며 특정 연산이 가능해집니다. 값을 정렬하거나(.sort_values), .min 및 .max를 적용할 수 있습니다.
범주 이름 변경은 rename_categories() 메서드를 통해 수행됩니다(리스트 또는 딕셔너리를 사용할 수 있습니다).
df["cat_type"] = df["cat_type"].cat.rename_categories(["alpha", "beta", "gamma"])범주를 추가해야 하는 상황도 자주 발생합니다. 이는 .add_categories()로 할 수 있습니다:
df["cat_type"] = df["cat_type"].cat.add_categories(["delta"])
df["cat_type"]0 NaN
1 alpha
2 beta
3 NaN
4 gamma
5 NaN
6 beta
Name: cat_type, dtype: category
Categories (4, object): ['alpha', 'beta', 'gamma', 'delta']
마찬가지로 .remove_categories() 함수와 .remove_unused_categories() 함수가 있습니다. .set_categories는 범주 추가와 제거를 한 번에 처리합니다. 어떤 범주(cat) 함수를 호출하기 전에는 반드시 df["columnname"].cat을 먼저 써야 한다는 점을 기억하세요.
앞서 언급했듯이 정렬된 범주는 이미 몇 가지 연산이 가능합니다. 하지만 모든 범주 집합에서 작동하는 연산들도 있습니다. 가장 유용한 것은 아마도 value_counts()일 것입니다.
df["cat_type"].value_counts()cat_type
beta 2
alpha 1
gamma 1
delta 0
Name: count, dtype: int64
’delta’가 전혀 나타나지 않더라도 개수(0)가 표시되는 것을 확인하세요. 누락된 값을 이렇게 추적하는 기능은 매우 유용할 수 있습니다.
mode()(최빈값)도 사용할 수 있습니다:
df["cat_type"].mode()0 beta
Name: cat_type, dtype: category
Categories (4, object): ['alpha', 'beta', 'gamma', 'delta']
또한 범주형 열이 연산이 가능한 요소들로 구성되어 있다면, 해당 요소들에 대한 연산도 여전히 작동합니다. 예를 들어:
time_df = pd.DataFrame(
pd.Series(pd.date_range("2015/05/01", periods=5, freq="M"), dtype="category"),
columns=["datetime"],
)
time_df/tmp/ipykernel_5877/379284818.py:2: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
pd.Series(pd.date_range("2015/05/01", periods=5, freq="M"), dtype="category"),
| datetime | |
|---|---|
| 0 | 2015-05-31 |
| 1 | 2015-06-30 |
| 2 | 2015-07-31 |
| 3 | 2015-08-31 |
| 4 | 2015-09-30 |
time_df["datetime"].dt.month0 5
1 6
2 7
3 8
4 9
Name: datetime, dtype: int32
마지막으로, 범주형 열의 실제 데이터 타입을 코드로 변환해야 하는 경우, .cat.codes를 사용하여 각 값에 대한 고유 코드를 얻을 수 있습니다.
time_df["datetime"].cat.codes0 0
1 1
2 2
3 3
4 4
dtype: int8