1. 머신러닝Machine Learning이란 > 1-2. 머신러닝 준비

머신러닝 준비

1. 주제 선택

본격적으로 머신러닝을 하기 전에 크게 2가지 확인해 볼 점이 있습니다.

먼저 어떤 방법론을 써서 머신러닝을 수행할 것인가와 데이터 전처리와 같은 과정이 있습니다.

머신러닝의 방법론을 선택하는 과정은 주로 2가지 방법으로 나뉩니다.

데이터를 먼저 보고 그에 맞는 분석 방법을 설정하거나, 분석 목적에 따라 머신러닝의 방법론을 결정하는 방법입니다.

우리가 살펴볼 머신러닝 방법에는 분류, 회귀, 군집화가 있습니다.

여기서 분류와 회귀는 위에서 살펴봤듯이 지도학습이고, 군집화는 비지도학습입니다.

분류는 데이터가 범주형 변수를 예측하기 위한 지도학습입니다. 데이터에 레이블을 할당하는 경우에 해당합니다. 이때 레이블이 두 개인 경우를 이진 분류(binary classification)라고 하고, 범주가 두 개 이상이면 다중 클래스 분류(multi-class classification)라고 합니다. 분류 문제의 예로는 문서를 분류하거나, 이미지를 분류하는 작업 등이 있습니다.

회귀는 데이터가 연속된 값을 나타내며 이를 예측하기 위한 지도학습입니다. 훈련 데이터를 이용해 연속적인 값을 예측하려는 방법으로 주로 사용됩니다. 회귀분석의 예로는 주식 가격을 예측하거나 부동산 가격을 예측하는 방법이 있습니다.

군집화는 레이블이 없는 데이터를 특정 기준에 따라 유사한 데이터들을 하나의 세트로 그룹화하는 비지도학습입니다. 군집화는 주로 전체 데이터 세트를 여러 그룹으로 분류하기 위해 사용합니다. 이때, 사용자는 고유한 패턴을 찾기 위해서 개별 그룹 차원에서 분석을 수행할 수 있습니다. 군집화의 예로는 유사 단어 및 이미지 군집화 등이 있습니다.

2. 데이터 준비

2. 1. 데이터 보간

데이터 보간은 빈 데이터를 특징 규칙에 따라 메꾸는 작업입니다.

  • 결측치 확인: isna(). True, False 값 반환

  • 결측치 대체:fillna(). 괄호 안의 값으로 NaN값 대체해줘

  • 데이터 준비

from sklearn.datasets import load_iris
import pandas as pd

# numpy array 형식의 iris data
iris = load_iris()

# 특징feature 라벨
feature_names = iris.feature_names

# 특징feature 데이터
features = iris.data

# 타겟 라벨
target_names = iris.target_names

# 타겟 데이터
label = iris.target

iris_df = pd.DataFrame(data = iris.data, columns = iris.feature_names)
iris_df['target'] = iris.target

iris_df.head()

>>>
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)target
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2
2. 1. 1. 결측치 확인: isna()

T/F로 결측치인지 반환합니다.

iris_df.isna().head(3)
sepal length (cm)sepal width (cm)petal length (cm)width (cm)target
0FalseFalseFalseFalse
1FalseFalseFalseFalse
2FalseFalseFalseFalse
  • isna().sum(): 컬럼별 결손 데이터 개수 구하기! True 값만 1로 계산해서 sum() 연산하기
iris_df.isna().sum()

>>>
sepal length (cm)    0
sepal width (cm)     0
petal length (cm)    0
petal width (cm)     0
target               0
dtype: int64

iris 데이터에는 결측치가 없군요!

2. 1. 2. 결측치 대체: fillna(), replace(a, b)

iris 데이터는 결측치가 없으니 임의로 결측치를 만들고, 해당 값을 보간하는 실습을 해보겠습니다.

import numpy as np
 
iris_df = iris_df.replace(0.2, np.NaN)

iris_df.head()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)target
05.13.51.4NaN
14.93.01.4NaN
24.73.21.3NaN
34.63.11.5NaN
45.03.61.4NaN
  • fillna()

fillna()를 실행하면 괄호 안의 값으로 NaN값이 대체됩니다.

# 원본 데이터에 반영되지 않음
iris_df['petal width (cm)'].fillna(0.2)
>>>
0      0.2
1      0.2
2      0.2
3      0.2
4      0.2
      ... 
145    2.3
146    1.9
147    2.0
148    2.3
149    1.8
Name: petal width (cm), Length: 150, dtype: float64
iris_df['petal width (cm)']
>>>
0      NaN
1      NaN
2      NaN
3      NaN
4      NaN
      ... 
145    2.3
146    1.9
147    2.0
148    2.3
149    1.8
Name: petal width (cm), Length: 150, dtype: float64

하지만 원본 데이터에 적용되지 않아요.

  • fillna()의 반환 값을 새로운 DataFrame으로 만들거나,
  • inplace=True 파라미터를 fillna()에 추가해야

실제 데이터 세트 값이 변경됩니다.

예시원본 데이터에 반영
iris_df['petal width (cm)'].fillna(0.2)X
iris_df['petal width (cm)'] = titanic_df['petal width (cm)'].fillna(0.2)O
iris_df['petal width (cm)'].fillna(0.2, inplace = True)O

2. 2. dtype 변환

data type에는 int, float, object 등이 있죠. 이번 커리큘럼에서 우리가 연산할 데이터는 보통 숫자형 데이터예요. 따라서 문자형으로 된 데이터를 숫자로 바꿀 때가 있을 겁니다. 이때 크게

  • df.astype()
  • apply(pd.to_numeric)

를 사용해서 dtype을 바꿀 수 있어요!

# 모든 값이 문자열인 데이터프레임 생성
df_str = pd.DataFrame({'Orange':['1200', '1500'], 'Coconut':['250', '700']})
df_str

|Orange|Coconut| |0|1200|250| |1|1500|700|

모든 값이 문자열인 df_str을 만들었습니다. 하지만 우리 눈에는 숫자처럼 보입니다. 이럴때는 info()를 통해 확인할 수 있죠.

df_str.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   Orange   2 non-null      object
 1   Coconut  2 non-null      object
dtypes: object(2)
memory usage: 160.0+ bytes

이 데이터를 연산하려면 숫자형으로 바꿔줄 필요가 있습니다. 방법은 여러가지가 있습니다.

  • df.astype()
# astype()

df_str['Orange'] = df_str['Orange'].astype(int)

df_str.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   Orange   2 non-null      int32 
 1   Coconut  2 non-null      object
dtypes: int32(1), object(1)
memory usage: 152.0+ bytes

Orange 컬럼만 int로 바꿨습니다. 모든 컬럼을 바꾸려면 그냥 DataFrame에 직접 적용하시면 됩니다.

모든 컬럼의 자료형을 바꾸지 않아도 될 때 이용하시면 편리합니다.

df_num1 = df_str.astype(int)
df_num1.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype
---  ------   --------------  -----
 0   Orange   2 non-null      int32
 1   Coconut  2 non-null      int32
dtypes: int32(2)
memory usage: 144.0 bytes

df.astype()을 통해 int, float, str 등을 여러분이 알고 계신 자료형을 적용하실 수 있습니다. 혹시 int32, int64의 차이가 궁금하신가요? 간단하게 말씀드리면 할당되는 메모리의 수가 다릅니다. 대용량 데이터를 처리할 때 표현할 수 있는 숫자의 크기를 제한하면서 메모리를 아낄 수 있죠! 원하신다면 그냥 int 대신 numpy의 np.int(32) 등을 적용하시면 됩니다.

이번에는 다시 str 형태로 바꿔보겠습니다.

df_str2 = df_num1.astype(str)
df_str2.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   Orange   2 non-null      object
 1   Coconut  2 non-null      object
dtypes: object(2)
memory usage: 160.0+ bytes
  • pd.to_numeric()

pd.to_numeric을 이용해 숫자로 바뀐 컬럼을 하나 추가해보겠습니다.

df_str['Orange_num'] = pd.to_numeric(df_str['Orange'])
df_str.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 3 columns):
 #   Column      Non-Null Count  Dtype 
---  ------      --------------  ----- 
 0   Orange      2 non-null      int32 
 1   Coconut     2 non-null      object
 2   Orange_num  2 non-null      int32 
dtypes: int32(2), object(1)
memory usage: 160.0+ bytes

이번엔 전체 데이터를 바꿔보겠습니다.

# apply(pd.to_numeric)
df_num2 = df_str.apply(pd.to_numeric)
df_num2.info()
>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 3 columns):
 #   Column      Non-Null Count  Dtype
---  ------      --------------  -----
 0   Orange      2 non-null      int32
 1   Coconut     2 non-null      int64
 2   Orange_num  2 non-null      int32
dtypes: int32(2), int64(1)
memory usage: 160.0 bytes

짜잔~ int로 바뀌었습니다!

2. 3. Sampling

sampling → 정윤님 내용 참고

2. 4. Scaling스케일링

데이터 사이언스, AI, Machine Learning 프로젝트의 80%는 데이터 전처리에 있다고 해도 과장이 아닙니다. 일단 적합한 데이터여야 분석이 가능하고, 잘 전처리 될 수록 분석 결과가 좋습니다.

DataFrame에서 피처를 옮기거나 삭제하는 작업은 Pandas로 할 수 있습니다. 하지만 어떤 피처의 대부분 값이 10~90 사이인데 갑자기 200짜리, -100짜리 이상치가 있는 데이터 전처리를 Pandas로 하려면 어떻게 해야할까요? 지금 떠오르기로는 범위를 나누고, 조건문을 걸어서 삭제해야할 것 같네요.

그런데 피처가 100개라고 생각해 보세요! 모든 피처 하나씩 전처리를 할 수는 없겠죠?

그리고 값이 커지면 커질 수록 컴퓨팅 파워도 많이 사용될 겁니다.

sklearn에서는 preprocessing 모듈을 제공합니다. 여기서 우리는 Scaling을 위해 표준화Standardization 또는 정규화Normalization을 사용할 수 있습니다.

우리가 보통 이상치 제거, 연산량 감소를 위해 사용하는 전처리는 크게

  • Scaler
  • Standardizer
  • Normalizer
  • log 변환

등이 있고, Scaler에는 MinMax Scaler, MaxAbsScaler, RobustScaler 등이 있습니다.

scaler보다 log 변환이 더 좋은 전처리가 될 때도 있습니다. EDA를 통해 데이터를 잘 확인하고 적용해보세요.

자세한 코드와 설명은 Chapter2의 네번째 파트인 '전처리preprocessing'를 참고하세요.

마지막으로 업데이트 된 날짜:
2022년 10월 6일