인코딩과 범주화

강림·2023년 12월 3일
0

Data Pre-processing

목록 보기
9/11

1. 인코딩

인코딩(Encoding)

  • 많은 실제 데이터셋에는 수치형(numerical)범주형(categorical) 변수가 혼재하고 있음
  • 인코딩은 컴퓨터가 처리하기 용이하도록 기존의 데이터를 변경하는 것
    • 범주형 데이터는 일반적으로 텍스트(string)로 되어 있으므로 이를 숫자(일반적으로 양의 정수)로 변환
      → 레이블 인코딩(Label encoding)
    • 분류(classification) 문제에서는 종속변수가 범주형이어야 하므로 수치형(numerical) 데이터는 범주형으로 변환해주어야 함
      → 이진화(Binarizsaztion), 이산화(Discretization)
    • 회귀(regression) 모형이나 신경망에서는 독립변수는 수치형 변수이어야 하므로 범주형 변수를 수치형으로 변환해주어야 함
      → 원핫인코딩(One-hot encoding), 더미변수화(Dummy encoding)
    • 텍스트 데이터는 자연어 처리를 위해 토큰화(tokenization) 과정을 거쳐야 함
      → 정수인코딩(Integer encoding)
      인코딩된 코드를 원래의 데이터로 변환하는 것은 디코딩(Decoding)이라고 함

1.2 인코딩 분류

1. 범주형 데이터 → 이산 수치형 데이터

  • OrdinalEncoder() (1:1)
    • 범주형 데이터를 정수로 인코딩
    • 여러 컬럼(독립변수)에 사용 가능
  • LabelEncoder() (1:1)
    • 범주형 데이터를 정수로 인코딩
    • 하나의 컬럼(종속변수, 타겟)에만 사용 가능
  • TargetEncoder() (1:1)
    • 범주형 데이터를 특정한 컬럼(타겟)의 값의 크기와 비례한 숫자로 인코딩

2. 범주형 데이터 → 이진 데이터

  • One-hot encoding (1:M)
    • 하나의 컬럼에 있는 범주형 데이터를 여러개의 이진수 컬럼(수치형 데이터)로 인코딩
    • one-of-K 인코딩이라고도 함
  • Dummy encoding (1:M)
    • One-hot encoding과 동일한 기능
    • 회귀분석에서 범주형 변수를 고려할 때 사용

3. 연속 수치형 데이터 → 이진 데이터

  • Binarizer() (1:1)
    • 연속 수치형 데이터를 기준값(threshold)을 기준으로 이진수로 인코딩
  • LabelBinarizer() (1:M)
    • 연속형 데이터를 이진수 컬럼으로 인코딩
    • 하나의 컬럼(종속변수, 타겟)에만 사용 가능
  • MultiLabelBinarizer() (1:M)
    • multi-class(여러개의 범주가 있는) 데이터를 이진수 컬럼으로 인코딩
    • 하나의 컬럼(종속변수, 타겟)에만 사용 가능

2. 인코딩 방법

2.1 범주형 데이터 → 이산 수치형 데이터

💠 테스트를 위한 데이터 세트 생성하기

import pandas as pd

df = pd.DataFrame({'weight':[40, 80, 60, 50, 90], # feature: weight, continuous
                   'height':[162, 155, 182, 173, 177], # feature: height, continuous
                   'sex':['f', 'm', 'm', 'f', 'm'], # feature: sex, categorical
                   'blood_type':['O', 'A', 'B', 'O', 'A'], # feature: blood_type, categorical
                   'health':['good', 'excellent', 'bad', 'bad', 'good'], # target: health, categorical
                   })
df

-> 데이터프레임 생성 5사람의 체중, 키, 성별, 혈액형, 건강 의 특성으로 분류

💠 테스트를 위한 데이터 세트 생성하기

  • 범주형 데이터를 정수로 인코딩
  • 여러 컬럼(독립변수)에 사용 가능
from sklearn.preprocessing import OrdinalEncoder

# 데이터프레임 복사
df_oe = df.copy()

# OrdinalEncoder에 대한 객체 생성
oe = OrdinalEncoder()

# 데이터로 oe 학습
oe.fit(df)

# 학습된 결과 
print(f'{oe.categories_=}')
# OrdinalEncoder는 수치형 weight와 height도 범주형으로 인식하여 변경하므로 주의

# 학습된 결과를 적용하여 변환
df_oe = pd.DataFrame(oe.transform(df), columns=df.columns)
df_oe

oe.categories_=[array([40, 50, 60, 80, 90]), array([155, 162, 173, 177, 182]), array(['f', 'm'], dtype=object), array(['A', 'B', 'O'], dtype=object), array(['bad', 'excellent', 'good'], dtype=object)]

  • scikit-learn 라이브러리에서 제공하는 OrdinalEncoder를 사용
  • 데이터프레임의 범주형 변수를 순서형으로 변환하는 과정
  • 코드 주석에도 언급되어 있듯이, OrdinalEncoder는 기본적으로 모든 변수를 범주형으로 처리
# OrdinalEncoder 수정된 사용

# 데이터프레임 복사
df_oe = df.copy()

# OrdinalEncoder에 대한 객체 생성
oe = OrdinalEncoder()

# 데이터로 oe 학습
oe.fit(df[['sex', 'blood_type']])

# 학습된 결과 
print(f'{oe.categories_=}')

# 학습된 결과를 적용하여 삽입
df_oe.iloc[:,2:4] = oe.transform(df[['sex', 'blood_type']])
df_oe

oe.categories_=[array(['f', 'm'], dtype=object), array(['A', 'B', 'O'], dtype=object)]
:16: DeprecationWarning: In a future version, df.iloc[:, i] = newvals will attempt to set the values inplace instead of always setting a new array. To retain the old behavior, use either df[df.columns[i]] = newvals or, if columns are non-unique, df.isetitem(i, newvals)
df_oe.iloc[:,2:4] = oe.transform(df[['sex', 'blood_type']])

  • OrdinalEncoder를 수정하여 특정 열에 대해서만 학습 및 변환을 수행하는 방식
  • sex'와 'blood_type' 열만 순서형으로 변환되며, 다른 열은 그대로 유지
  • 특정 열에 대해서만 범주형 변수를 처리하고자 할 때 유용
# 디코딩(decoding)
oe.inverse_transform(df_oe.iloc[:,2:4])  

  • OrdinalEncoder를 사용하여 변환된 데이터를 다시 원래의 범주형 값으로 디코딩하는 과정
    • 디코딩은 인코딩의 반대 과정으로, 어떤 형태의 데이터를 다른 형태로 변환한 것을 다시 원래의 형태로 돌리는 것을 의미
    • OrdinalEncoder의 inverse_transform 메서드는 인코딩된 데이터를 다시 디코딩하여 원래의 형태로 돌리는 역할
  • 'sex'와 'blood_type' 열에 대한 순서형 값을 다시 해당 범주형 값으로 디코딩한 데이터프레임이 생성

💠 LabelEncoder

  • 범주형 데이터를 정수로 인코딩
  • 하나의 컬럼(종속변수, 타겟)에만 사용 가능
from sklearn.preprocessing import LabelEncoder

# 데이터프레임 복사
df_le = df.copy()

# LabelEncoder는 하나의 변수에 대해서만 변환 가능
# LabelEncoder 객체 생성과 fit을 동시에 적용
health_le = LabelEncoder().fit(df.health)
df_le['health'] = health_le.transform(df.health)
df_le

  • LabelEncoder를 사용하여 'health' 열을 변환하는 과정
  • 이렇게 하면 'health' 열이 순서형으로 변환되어, 각 값에 대해 정수로 매핑된 결과를 얻게 됨
  • 머신 러닝 모델에서 범주형 타겟 변수를 처리할 때 유용
# fit_transform() 메서드를 사용하여 한번에 인코딩 수행가능

# 데이터프레임 복사
df_le = df.copy()

# LabelEncoder 객체 생성과 fit을 동시에 적용
df_le['health'] = LabelEncoder().fit_transform(df.health)
df_le

  • fit_transform() 메서드는 Scikit-learn 라이브러리에서 제공하는 메서드
  • 데이터프레임의 'health' 열을 Label Encoding하는 과정
  • 앞코드와 차이점은 LabelEncoder().fit_transform() 대신 LabelEncoder().fit()와 transform()을 따로 사용하여 'health' 열을 변환
  • fit() 단계에서 LabelEncoder를 학습하고, 이후에 transform() 단계에서 해당 학습을 기반으로 데이터를 변환
  • 학습된 LabelEncoder 객체를 다른 열이나 데이터에도 적용해야 할 경우에 편리

💠 TargetEncoder 적용

  • 범주형 데이터를 특정한 컬럼(타겟)의 값의 크기와 비례한 숫자로 인코딩
from sklearn.preprocessing import TargetEncoder

# 데이터프레임 복사
df_te = df.copy()

# TargetEncoder에 대한 객체 생성
# smooth는 정밀도를 조정하고 target_type은 인코딩 타입을 지정
te = TargetEncoder(smooth=0, target_type='continuous')

# 데이터로 te 학습
# 타겟을 weight라고 가정하고 blood_type을 인코딩
# blood_type_target은 weight와 비례하여 인코딩된 값
# 인코딩이 되는 값은 2차원으로 변환해야 함
te.fit(df['blood_type'].values.reshape(-1, 1), df.weight)

# 학습된 결과 
print(f'{te.categories_=}')

# 학습된 결과를 적용하여 새로운 컬럼 삽입
df_te['blood_type_target'] = te.transform(df['blood_type'].values.reshape(-1, 1))
df_te

-> 코드가 오류가 계속 뜸... 확인이 불가.. 교수님께서 보여주신 결과를 첨부

2.2 범주형 데이터 → 이진 데이터

💠 원핫인코딩(One-Hot-Encoding)

  • 하나의 컬럼에 있는 범주형 데이터를 여러개의 이진수 컬럼(수치형 데이터)로 인코딩
  • one-of-K 인코딩이라고도 함
from sklearn.preprocessing import OneHotEncoder

# 데이터프레임 복사
df_ohe = df.copy()

# OneHotEncoder에 대한 객체 생성 후 fit
ohe = OneHotEncoder().fit(df_ohe[['blood_type']])

# 학습된 결과 
print(f'{ohe.categories_=}')

# 학습된 결과를 적용하여 새로운 컬럼 삽입
# OneHotEncoder는 결과를 sparse matrix로 반환하므로 toarray()를 통해 ndarray로 변환
df_ohe[ohe.categories_[0]] = ohe.transform(df_ohe[['blood_type']]).toarray()
df_ohe

  • scikit-learn의 OneHotEncoder를 사용하여 DataFrame('df')의 'blood_type' 열을 One-Hot 인코딩
  • 'blood_type' 열의 각 범주에 대해 새로운 컬럼이 생성되고, 해당 범주에 속하는 경우에는 1로 표시되고 다른 경우에는 0으로 표시
  • 범주형 변수를 다룰 때 주로 사용되는 방법

💠 Dummy encoding

  • Pandas에서 제공하는 get_dummies는 One-hot encoding과 동일한 기능
    여러 컬럼을 한 번에 변환 가능
  • 회귀분석에서 범주형 변수를 고려할 때 사용
pd.get_dummies(df, columns=['sex', 'blood_type'], drop_first=False)
  • pandas의 get_dummies 함수를 사용하여 'sex'와 'blood_type' 열을 더미 변수로 변환하는 과정
  • sex'와 'blood_type' 열의 각 범주에 대해 더미 변수가 생성되고, 이를 원본 데이터프레임에 추가한 결과
  • One-Hot Encoding을 쉽게 수행할 수 있고, 더미 변수의 첫 번째 열을 유지함으로써 다중공선성을 피할 수 있음

2.3 연속 수치형 데이터 → 이진 데이터

💠 Binerizer

  • 연속 수치형 데이터를 기준값(threshold)을 기준으로 이진수로 인코딩
from sklearn.preprocessing import Binarizer

# 데이터 불러오기
df_bin = df.copy()

# Binarizer 객체 생성과 fit, transform을 동시에 적용
# Binarizer는 수치형 변수에 대해서만 변환 가능
df_bin['weight_bin'] = Binarizer(threshold=50).fit_transform(df.weight.values.reshape(-1,1))
df_bin['height_bin'] = Binarizer(threshold=170).fit_transform(df.height.values.reshape(-1,1))
df_bin

  • Binarizer를 사용하여 수치형 변수인 'weight'와 'height' 열을 이진화하는 과정
  • 이진화는 주어진 기준값을 기준으로 변수를 0 또는 1로 변환하는 과정을 말하며, 이는 주로 임계값을 정하여 변수를 이진 형태로 나타내고자 할 때 사용
  • 'weight_bin' 및 'height_bin' 열은 각각 'weight'와 'height' 열의 값이 기준값보다 크면 1, 작거나 같으면 0으로 변환

💠 LabelBinerizer

  • 연속형 데이터를 이진수 컬럼으로 인코딩
  • 하나의 컬럼(종속변수, 타겟)에만 사용 가능
from sklearn.preprocessing import LabelBinarizer

# 데이터프레임 복사
df_lb = df.copy()

# LabelBinarizer 객체 생성과 fit을 적용
lb = LabelBinarizer().fit(df.health)

# lb.classes_ : LabelBinarizer가 인코딩한 클래스 확인
print(f'{lb.classes_ = }')

# lb.transform() : 인코딩 변환
health_lb = lb.transform(df.health)
print('health_lb = \n', health_lb)

# 인코딩된 데이터를 데이터프레임으로 변환
df_lb[lb.classes_] = health_lb
df_lb

  • LabelBinarizer를 사용하여 범주형 변수인 'health' 열을 이진화하는 과정
  • 'health' 열의 각 범주에 대해 이진화된 변수가 생성되고, 이를 원본 데이터프레임에 추가
  • 이진화된 변수는 해당 범주에 속하는 경우에는 1로 표시되고, 다른 경우에는 0으로 표시

💠 MultiLabelBinerizer

multi-class(여러개의 범주가 있는) 데이터를 이진수 컬럼으로 인코딩
하나의 컬럼(종속변수, 타겟)에만 사용 가능

from sklearn.preprocessing import MultiLabelBinarizer

# 데이터프레임 복사
df_mlb = df.copy()

# multi-class를 위한 컬럼 추가
df_mlb['test'] = [['math', 'english'], ['math', 'science'], ['science'], ['math', 'english'], 
                           ['science']] # target: test, categorical, multi-class
df_mlb

  • MultiLabelBinarizer를 사용하여 다중 클래스 다중 레이블 (multi-class multi-label)인 'test' 열을 이진화하는 과정
  • 'test' 열의 다중 클래스 다중 레이블에 대해 각 클래스에 속하는지 여부를 나타내는 이진화된 변수가 생성되고, 이를 원본 데이터프레임에 추가
# MultiLabelBinarizer 객체를 생성하고 fit() 메소드를 호출하여 클래스를 인코딩
mlb = MultiLabelBinarizer().fit(df_mlb.test)

# classes_ 속성을 사용하면 어떤 클래스가 인코딩되었는지 확인 가능
print(f'{mlb.classes_ = }')

# 인코딩된 데이터를 데이터프레임으로 변환
df_mlb[mlb.classes_] = mlb.transform(df_mlb.test)
df_mlb

  • MultiLabelBinarizer를 사용하여 다중 클래스 다중 레이블인 'test' 열을 이진화하는 과정
  • 'test' 열의 다중 클래스 다중 레이블에 대해 각 클래스에 속하는지 여부를 나타내는 이진화된 변수가 생성되고, 이를 원본 데이터프레임에 추가

3. 범주화

3.1 범주화(Discritization)

  • 연속형 변수를 구간별로 나누어 범주형 변수로 변환하는 것
  • quantization 또는 binning이라고도 함

💠 K-bins discretization

from sklearn.preprocessing import KBinsDiscretizer

# 데이터프레임 복사
df_kbd = df.copy()

# KBinsDiscretizer 객체 생성과 fit을 적용
kbd = KBinsDiscretizer(n_bins=3, encode='ordinal').fit(df[['weight', 'height']])

# kbd.transform() : 인코딩 변환
# 인코딩된 데이터를 데이터프레임으로 변환
df_kbd[['weight_bin', 'height_bin']] = kbd.transform(df[['weight', 'height']])
df_kbd

  • KBinsDiscretizer를 사용하여 'weight'와 'height' 열을 구간화(discretization)하는 과정
  • 'weight'와 'height' 열의 각 값이 주어진 구간에 속하는지를 나타내는 이산형 변수가 생성되고, 이를 원본 데이터프레임에 추가

코드 예시

import pandas as pd
from sklearn.preprocessing import OrdinalEncoder, LabelEncoder, TargetEncoder, OneHotEncoder, Binarizer, LabelBinarizer, MultiLabelBinarizer, KBinsDiscretizer

# 새로운 성적 데이터프레임 생성
grade_data = pd.DataFrame({'math':[85, 90, 78, 92, 88],
                           'english':[70, 85, 92, 80, 95],
                           'science':[88, 75, 90, 82, 88],
                           'subject':['math', 'english', 'science', 'math', 'english'],
                           })

# OrdinalEncoder 예시
oe = OrdinalEncoder()
grade_data_oe = grade_data.copy()
grade_data_oe[['subject']] = oe.fit_transform(grade_data[['subject']])

# LabelEncoder 예시
le = LabelEncoder()
grade_data_le = grade_data.copy()
grade_data_le['subject'] = le.fit_transform(grade_data['subject'])

# TargetEncoder 예시
te = TargetEncoder(smooth=0, target_type='continuous')
te.fit(grade_data['subject'].values.reshape(-1, 1), grade_data['math'])
grade_data_te = grade_data.copy()
grade_data_te['subject_target'] = te.transform(grade_data['subject'].values.reshape(-1, 1))

# OneHotEncoder 예시
ohe = OneHotEncoder(drop='first', sparse=False)
grade_data_ohe = pd.DataFrame(ohe.fit_transform(grade_data[['subject']]), columns=['subject_english', 'subject_science'])
grade_data_ohe = pd.concat([grade_data, grade_data_ohe], axis=1)

# Binarizer 예시
binarizer = Binarizer(threshold=80)
grade_data_bin = grade_data.copy()
grade_data_bin['math_bin'] = binarizer.fit_transform(grade_data['math'].values.reshape(-1, 1))

# KBinsDiscretizer 예시
kbd = KBinsDiscretizer(n_bins=3, encode='ordinal')
grade_data_kbd = pd.DataFrame(kbd.fit_transform(grade_data[['math', 'english']]), columns=['math_bin', 'english_bin'])
grade_data_kbd = pd.concat([grade_data, grade_data_kbd], axis=1)
profile
DRUDGER

0개의 댓글