데이터의 종류는 아래와 같이 나눌 수 있다.
Categorical / Numerical -Nominal -Discrete -Ordinal -Continuous
1.1 Nominal - 굳이 번역하자면 '명목형'
혈액형처럼 숫자의 크기나 순서와 아무런 상관이 없어서
A=1, B=2, AB=3, O=4 처럼 숫자를 붙이는 것이 정말 '네이밍' 그이상 그이하의 의미가 없는 경우.
### 1.2 Ordinal - '순서형'
금/은/동메달,
2.1 Discrete - '이산형'
동전을 n회 던져서 앞면이 나온 횟수처럼 정수형으로 셀 수 있는 변수.
2.2 Continuous - '연속형'
키, 몸무게처럼 실수로 나타낼 수 있는 변수.
#변수의 종류를 확인하고 인코딩까지 해보자
import numpy as np
import pandas as pd #넘파이와 판다스 어쩌구는 시간이 지나면 해결해줄 것이라 믿는다
data = {
'Name':['John', 'Sabre', 'Kim', 'Sato', 'Lee', 'Smith', 'David', 'Park'],
'Country':['USA', 'France', 'Korea', None, 'Korea', 'UK', 'USA', 'Korea'],
'Age':['31', 33, None, 40, 36, 55, np.nan, 35], # numerical인데 categorical처럼 인식될 수 있음
'Job':['Student', np.nan, 'Developer', 'Chef', 'Professor', 'CEO', 'Banker', 'Student'],
'Hand':['L', 'R', 'R', 'B', 'L', 'L', 'R', 'R'],
'Height':['T', 'S', 'M', 'S', 'T', 'S', 'S', 'T'],
'Capital':[48.35, 150.8, 99.0, 100.0, 182.3, 1101.65, 131.87, 65.8]
}
#강사님이 주신 데이터
df_nan = pd.DataFrame(data)
df = df_nan.copy()
print(df)
Name Country Age Job Hand Height Capital 0 John USA 31 Student L T 48.35 1 Sabre France 33 NaN R S 150.80 2 Kim Korea None Developer R M 99.00 3 Sato None 40 Chef B S 100.00 4 Lee Korea 36 Professor L T 182.30 5 Smith UK 55 CEO L S 1101.65 6 David USA NaN Banker R S 131.87 7 Park Korea 35 Student R T 65.80
df.info() #각 열의 데이터 타입을 확인해 볼 수 있다
<class 'pandas.core.frame.DataFrame'> RangeIndex: 8 entries, 0 to 7 Data columns (total 7 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Name 8 non-null object 1 Country 7 non-null object 2 Age 6 non-null object 3 Job 7 non-null object 4 Hand 8 non-null object 5 Height 8 non-null object 6 Capital 8 non-null float64 dtypes: float64(1), object(6) memory usage: 576.0+ bytes
#나이 데이터를 다루려면 Age의 type을 int로 바꿔줄 필요가 있다.
df['Age'] = df['Age'].astype('Float32').astype('Int16') #실수로 바꿔주고 (flt은 null값 받아들이기 가능) 정수화시키기
df
#None과 NaN의 차이는 나중에 알아보기로 하자.
| Name | Country | Age | Job | Hand | Height | Capital | |
|---|---|---|---|---|---|---|---|
| 0 | John | USA | 31 | Student | L | T | 48.35 |
| 1 | Sabre | France | 33 | NaN | R | S | 150.80 |
| 2 | Kim | Korea | <NA> | Developer | R | M | 99.00 |
| 3 | Sato | None | 40 | Chef | B | S | 100.00 |
| 4 | Lee | Korea | 36 | Professor | L | T | 182.30 |
| 5 | Smith | UK | 55 | CEO | L | S | 1101.65 |
| 6 | David | USA | <NA> | Banker | R | S | 131.87 |
| 7 | Park | Korea | 35 | Student | R | T | 65.80 |
Age의 data type이 바뀌어있는 것을 확인할 수 있다.
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 8 entries, 0 to 7 Data columns (total 7 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Name 8 non-null object 1 Country 7 non-null object 2 Age 6 non-null Int16 3 Job 7 non-null object 4 Hand 8 non-null object 5 Height 8 non-null object 6 Capital 8 non-null float64 dtypes: Int16(1), float64(1), object(5) memory usage: 536.0+ bytes
범주형 열과 숫자형 열들을 분리해서 리스트화시켰다.
cat_cols = ['Name', 'Country', 'Job', 'Hand', 'Height']
num_cols = ['Age', 'Capital']
print(cat_cols)
print(num_cols)
['Name', 'Country', 'Job', 'Hand', 'Height'] ['Age', 'Capital']
우리가 원하는 것은 범주형 열의 데이터들을 숫자로 바꿔주기 ! = 인코딩이라고 부르기로 했어요. LabelEncoding하는 방법에는
df[cat_cols]
df_enc = df.copy() #원본은 복사본 만들어두고
오디널 인코더..뭐요??
항목을 순서로 바꿔주자. 순서가 무조건 부여되는 것은 아니라고 한다.
아래 결과를 통해 왼손은 1, 오른손은 2, 양손잡이는 0으로 변환된 것을 확인할 수 있다.
from sklearn.preprocessing import OrdinalEncoder
# Hand 칼럼 ordinal [+]
ord_enc=OrdinalEncoder()
ord_enc.fit(df[['Hand']])
ord_enc.transform(df[['Hand']])
array([[1.],
[2.],
[2.],
[0.],
[1.],
[1.],
[2.],
[2.]])
df_enc['Hand'] = ord_enc.transform(df[['Hand']])
df_enc
| Name | Country | Age | Job | Hand | Height | Capital | |
|---|---|---|---|---|---|---|---|
| 0 | John | USA | 31 | Student | 1.0 | T | 48.35 |
| 1 | Sabre | France | 33 | NaN | 2.0 | S | 150.80 |
| 2 | Kim | Korea | <NA> | Developer | 2.0 | M | 99.00 |
| 3 | Sato | None | 40 | Chef | 0.0 | S | 100.00 |
| 4 | Lee | Korea | 36 | Professor | 1.0 | T | 182.30 |
| 5 | Smith | UK | 55 | CEO | 1.0 | S | 1101.65 |
| 6 | David | USA | <NA> | Banker | 2.0 | S | 131.87 |
| 7 | Park | Korea | 35 | Student | 2.0 | T | 65.80 |
왼손이 1, 오른손이 2라고 해서 왼손이 오른손보다 낫다든가 먼저라든가 하는 순서가 없는 nomianl 명목형 변수지만,
추후에 모델이 학습될 때 이 순서가 영향을 줄 수도 있으므로
'원 핫 인코딩 '을 적용해보기로 하자.
'목적하는 변수 외에는 데이터 값을 0으로 만들어주는 것'인 것까지만 이해했다.
아래 코드를 실행하면 약간 행렬스러운 어레이와 그 설명을 볼 수 있다.
from sklearn.preprocessing import OneHotEncoder
# Hand 칼럼 onehot [+]
oh_enc = OneHotEncoder(sparse=False)
oh_enc.fit(df[['Hand']])
oh_enc.transform(df[['Hand']])
oh_enc.get_feature_names_out()
array(['Hand_B', 'Hand_L', 'Hand_R'], dtype=object)
표를 다시 불러와볼까요?
df_enc = pd.concat( [df_enc, pd.DataFrame(oh_enc.transform(df[['Hand']]),
columns=oh_enc.get_feature_names_out())], axis=1).drop('Hand', axis=1) #원래 Hands열은 버려준다
df_enc
| Name | Country | Age | Job | Height | Capital | Hand_B | Hand_L | Hand_R | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | John | USA | 31 | Student | T | 48.35 | 0.0 | 1.0 | 0.0 |
| 1 | Sabre | France | 33 | NaN | S | 150.80 | 0.0 | 0.0 | 1.0 |
| 2 | Kim | Korea | <NA> | Developer | M | 99.00 | 0.0 | 0.0 | 1.0 |
| 3 | Sato | None | 40 | Chef | S | 100.00 | 1.0 | 0.0 | 0.0 |
| 4 | Lee | Korea | 36 | Professor | T | 182.30 | 0.0 | 1.0 | 0.0 |
| 5 | Smith | UK | 55 | CEO | S | 1101.65 | 0.0 | 1.0 | 0.0 |
| 6 | David | USA | <NA> | Banker | S | 131.87 | 0.0 | 0.0 | 1.0 |
| 7 | Park | Korea | 35 | Student | T | 65.80 | 0.0 | 0.0 | 1.0 |
이번에는 숫자형 변수인 키 열을 인코딩해보자.
키는 Tall, Middle, Small로 구분된 모양이지만,
안타깝게도 파이썬은 큰 사람을 2, 작은 사람들 1, 중간인 사람을 0으로 지정해버렸다.
ord_enc.fit(df[['Height']])
ord_enc.transform(df[['Height']])
array([[2.],
[1.],
[0.],
[1.],
[2.],
[1.],
[1.],
[2.]])
대참사를 막기 위해 올바른 순서를 다시 알려주자. S, M, T 순서대로 지정해!
ord_enc = OrdinalEncoder(categories=[['S', 'M', 'T']])
ord_enc.fit(df[['Height']])
ord_enc.transform(df[['Height']])
결과 확인은 이렇게.
df_enc['Height'] = ord_enc.transform(df[['Height']])
df_enc
이 한 페이지를 정리하기 위해 한 시간이나 걸렸다니 믿을 수 없다. 앞으로 공부 더 열심히 해야겠구나를 느낀 순간..