# [데이터 전처리] 범주형 변수 전처리

## 변주형 변수 전처리

---

- 변주형 변수는 보통 문자열로 되어 있어 머신러닝 모델의 입력 데이터로 사용할 수 없다.

- 수치형 변수로 인코딩 encoding 해주는 과정이 필요하다.

### 인코딩 방법

- Label Encoding

- One-Hot Encoding

- Frequency Encoding

- Target Encoding

- Embeding

## Label Encoding

---

- 알파벳 순서로 숫자를 할당해주는 방법

- 문자열 값을 숫자형 카테고리 값으로 변환한다.

    - ex) ‘Bangul’: 1, ‘Bonn’: 2, …

- 순서형 데이터에는 적합할 수 있으나, 명목형 데이터에는 적합하지 않다.

- 숫자의 순서가 특징으로 여겨질 수 있다.

    - 몇몇 ML 알고리즘에서는 예측 성능이 떨어지는 경우가 발생한다.

    - 숫자형 카테고리 값이 중요도로 인식될 수 있으므로 선형회귀와 같은 ML 알고리즘에는 적용하지 않아야 한다.

    - 트리 계열의 ML 알고리즘은 숫자의 이러한 특성을 반영하지 않으므로 레이블 인코딩이 문제 없다.

### LabelEncoder

**[sklearn.preprocessing.LabelEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html)**

```javascript
from sklearn.preprocessing import LabelEncoder

city = ['Bonn', 'Zomba', 'Paris', 'Tokyo', 'Seoul', 'Lagos', 'Bangul']

# 레이블 인코딩 수
encoder = LabelEncoder()
encoder.fit(city)
labels = encoder.transform(city)
print('인코딩 변환값:',labels)
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175338_gATYTnTDjLCSJShc7U?q=80&s=1280x180&t=outside&f=webp)

```javascript
# 데이터가 많은 경우
print('인코딩 클래스: ', encoder.classes_)
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175320_i7uNyYJ2nBGFdQlAoC?q=80&s=1280x180&t=outside&f=webp)

```javascript
# 디코딩
print('디코딩 원본값: ', encoder.inverse_transform([4, 6, 0, 3, 5, 4, 4, 2, 4, 6, 0]))
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175328_JEQs5dWFljQzRumL6e?q=80&s=1280x180&t=outside&f=webp)

```javascript
# 타이타닉 데이터 실습
from sklearn.preprocessing import LabelEncoder
import seaborn as sns

df = sns.load_dataset('titanic')
df_sns = df[['sex', 'embarked', 'class']]
df_encoded = pd.DataFrame()

for col in df_sns.columns:
  encoder = LabelEncoder()
  encoder = encoder.fit(df_sns[col])
  labels = encoder.transform(df_sns[col].values.ravel())

  df_temp = pd.DataFrame(labels, columns=[col])
  df_encoded = pd.concat([df_encoded, df_temp], axis=1)

df_encoded
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175238_UWfRovmJBEsymPtGVZ?q=80&s=1280x180&t=outside&f=webp)

```javascript
df_tt = pd.concat([df, df_encoded], axis=1)
df_tt.head()
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175251_80eYJ8ihFhRsWNMls3?q=80&s=1280x180&t=outside&f=webp)

## One-Hot Encoding

---

- 피처 값마다 변수를 추가해 이진값으로 만드는 방법

- 피처 값의 유형에 따라 새로운 피처를 추가해 피처 값에 해당하는 컬럼만 1을 표시, 나머지 컬럼에는 0을 표시한다.

- 레이블 인코딩의 문제점을 해결하기 위한 인코딩 방법이다.

- 장점: 변수의 의미가 명확하다.

- 단점:

    - 변수의 종류가 많아질수록 변수의 개수가 종류만큼 늘어나게 되거 Parse한 행렬이 많들어지게 된다. (차원의 저주)

    - 다중 공선성 문제, 메모리 문제가 발생할 수 있다.

### One-Hot Encoder

**[sklearn.preprocessing.OneHotEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html#sklearn.preprocessing.OneHotEncoder)**

```javascript
from sklearn.preprocessing import OneHotEncoder
import numpy as np

city = ['Bonn', 'Zomba', 'Paris', 'Tokyo', 'Seoul', 'Lagos', 'Bangul']

# 2차원 ndarray로 변환
city = np.array(city).reshape(-1, 1)

# 원핫인코딩
oh_encoder = OneHotEncoder()
oh_encoder.fit(city)
oh_labels = oh_encoder.transform(city)

print('원-핫 인코딩 데이터')
print(oh_labels.toarray())
print('원-핫 인코딩 데이터 차원')
print(oh_labels.shape)
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175402_sfVIqQt8xGILwDHNNo?q=80&s=1280x180&t=outside&f=webp)

```javascript
# 타이타닉 데이터 실습
import seaborn as sns
from sklearn.preprocessing import OneHotEncoder

df = sns.load_dataset('titanic')
df_sns = df[['sex', 'embarked', 'class']]
df_encoded = pd.DataFrame()

for col in df_sns.columns:
  encoder = OneHotEncoder()
  encoder = encoder.fit(df_sns[[col]])
  labels = encoder.transform(df_sns[[col]])
  labels_dense = labels.toarray().astype(int)

  col_names = [f"{col}_{value}" for value in encoder.categories_[0]]
  df_temp = pd.DataFrame(labels_dense, columns=col_names)

  df_encoded = pd.concat([df_encoded, df_temp], axis=1)

df_encoded
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175418_FFVRTNDyAPNq4C6m5C?q=80&s=1280x180&t=outside&f=webp)

```javascript
df_tt = pd.concat([df, df_encoded], axis=1)
df_tt.head()
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175430_mWEkt89xTf1Nah4kL4?q=80&s=1280x180&t=outside&f=webp)

### get_dummies

**[pd.get_dummies](https://pandas.pydata.org/docs/reference/api/pandas.get_dummies.html)**

> pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)

- drop_fist=True로 설정하면 컬럼 중 하나가 삭제된다.

    - 하나의 컬럼이 없어도 다른 컬럼들에 속하지 않는 값들로 구분 가능하다.

    -   → 불필요한 피처의 수를 줄일 수 있다. 

    - 2개 카테고리를 갖는 피처의 경우 label encoding을 get_dummies로 구현 가능하다.

```javascript
import pandas as pd

df = pd.DataFrame({'수도': ['Bonn', 'Zomba', 'Paris', 'Tokyo', 'Seoul', 'Lagos', 'Bangul']})
pd.get_dummies(df)
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175519_PArwu1SFjhJFWbqhXk?q=80&s=1280x180&t=outside&f=webp)

```javascript
# 타이타닉 데이터 실습
import pandas as pd
import seaborn as sns

df = sns.load_dataset('titanic')
df_sns = df[['sex', 'embarked', 'class']]

df_encoded = pd.get_dummies(df_sns)
df_tt = pd.concat([df, df_encoded], axis=1)

df_tt.head()
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/175535_IRlZavtxwqq4dMfKZh?q=80&s=1280x180&t=outside&f=webp)

## Frequency Encoding

---

- SVD 잠재 의미 분석하는 인코딩

## Target Encoding

---

- 각각의 변수 종류가 가지는 Target 변수의 평균으로 인코딩

    - ex) "개"는 사료의 비용이 평균값 2000원 ((1000 + 1500 + 3500)/3 )

- 단점: 1, 3, 4, 5 ID처럼 다른 종이 같은 Target Encoding을 갖게 될 수 있다.

## Embedding

---

- Entity Embedding이라고도 하는 이 방법은 Word2Vec과 같은 모델을 이용해 Text 데이터를 더 낮은 차원으로 임베딩하는 방법

## 데이터 구간화 Binning

---

- 변수구간화: 연속형 변수를 구간 또는 범주로 나누는 것

- 연속형 변수를 다룰 때 
- → 나이와 같은 데이터의 경우 구간으로 나누어 새로운 변수를 만들 수 있다

- 모델의 복잡도를 줄이고 특정 패턴이나 추세를 확인할 때 유용하다

- binning을 통해 해당 변수의 스케일이나 분포가 모델에 미치는 영향을 줄일 수 있다

**구간화 순서**

1. 구간 설정: 연속형 변수를 나눌 구간 설정 → 개수나 도메인 지식으로 결정

2. 구간 경계 설정: 어디까지 어떤 값으로 할때 구간을 정하는 경계값 필요

3. 데이터 비닝: 설정 구간에 따라 연속형 변수들을 구간 또는 범주에K 할당

## [KBinsDiscretizer](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.KBinsDiscretizer.html)

---

- scikit-learn 라이브러리에서 제공하는 패키지

- 연속형 변수를 구간으로 나누어 범주형 변수로 변환하는 작업 수행

```javascript
sklearn.preprocessing.KBinsDiscretizer(n_bins=5, *, encode='onehot', 
                strategy='quantile', dtype=None, subsample=200000, random_state=None) 
```

- encode : onehot(원핫인코딩) ordinal(레이블인코딩)

- strategy : 구간 나누는 전략, uniform - 데이터를 균일하게 나누기, quantile 데이터 분포 분위수 기반, 'kmeans' - K means 방법으로 진행

**예시**

```javascript
from sklearn.preprocessing import KBinsDiscretizer

data = [[1, 2, 3, 4],
        [11, 12, 13, 14],
        [21, 22, 23, 24],
        [31, 32, 33, 34]]

est=KBinsDiscretizer(n_bins= 15, encode='ordinal', strategy ='uniform')
est.fit(data)
est.transform(data)
```

For the site tree, see the [root Markdown](https://slashpage.com/yerim-devnote.md).
