-
머신러닝 02 - sklearn 알아 보기 (전처리)빅데이터/Machine-Learning 2022. 2. 7. 21:40
패스트캠퍼스 '직장인을 위한 파이썬 데이터분석 올인원 패키치 Online' 참조
01 전처리 기본
- 전처리는 데이터를 분석에 적합하게 데이터를 가공/변형/처리/클리닝을 하는 작업이다
'Garbage in, Garbage out!'
데이터가 깔끔하지않으면(이상치가 많다거나) 성능이 현저하게 떨어진다. - 분석가의 80%시간을 데이터 수집 및 전처리에 사용 한다고 전해진다.
- 전처리 과정은 다음과 같다
- 결측치 (Imputer) - 데이터의 빠진 부분을 처리
- 이상치 - 데이터에 이상치가 있을때 처리
- 정규화(Normalization)
- 표준화(Standardization)
- 샘플링(over/under smapling)
- 피처 공학(Feature Enginerring)
- feature 생성/연산
- 구간 생성, 스케일 변형
▶ 실습을 통해 하나씩 볼 예정
- 정규화 (Normalization)
- 0~1 사이의 분포로 조정
데이터 = 데이터 최대값-최소값 / 데이터값-최소값을 하게 되면 0~1사이로 분포가 조정 된다 - 대표적으로 정규화는 다른 스케일에 있는 데이터를 동일한 스케일에 넣거나 데이터 분포가 너무 넓게 퍼져있으면 성능을 제대로 나오지 않기 때문에 주로 하게 된다
- 표준화(Standardization)
- 평균을 0, 표준편차를 1로 맞춤
- 데이터가 정규분포를 따른다는 가정하에 실시 (정규분포는 종모양의 분포). 평균은 0, 표준편차는 1이므로 변한 값이 0~1사이로 바뀌지 않게 된다. 하지만 평균은 0이므로 0의 근처로 많이 잡히게 된다.
02 전처리 데이터 만들기
- sklearn을 써서 train/validation/test set을 준비 해 보자
* 테스트 셋을 나누기 위한 라이브러리 import numpy as np import pandas as pd
- 케글에서 제공해주는 데이터를 들고 오자!
train = pd.read_csv('https://bit.ly/fc-ml-titanic') train.head()
타이타닉 사고에 대한 데이터다. Train-set에는 모든 데이터 내용이 들어 간다 - Train/Validation 세트 나누기
- 저번 강의 시간때 Train 80% / Validation 20% 정도로 데이터를 나눈다고 하였다. 이 비율 나누는것도 'sklearn'에서 제공해 준다
- 먼저 학습데이터와 예측 데이터에 쓰일 목록들을 정하고 구분을 지어 주자.
# feature = 학습을 하기위한 컬럼 feature = ['Pclass','Sex','Age','Fare'] # label = 예측해야될 컬럼 label = ['Survived']
▶ 'train' 데이터에서 리스트 형식으로 나눴기때문에 반드시 'train['']' 으로 호출 해야 한다
- 이제 'sklearn'에서 제공하는 패키지를 써서 데이터셋을 나눠 보자
from sklearn.model_selection import train_test_split # sklearn에서 제공하는 세트 분리 패키지 # return 받는 데이터의 순서가 중요!!! x_train, x_valid, y_train, y_valid = train_test_split(train[feature], train[label], test_size=0.2, shuffle=True, random_state=30) # train_test_split('학습데이터','에측데이터','옵션1,2,3...'') # 학습데이터는 train에, 예측데이터는 valid에 'sklearn'이 알아서 분류를 하여 넣어 준다 - test_size : validation set에 할당하는 비율(20% -> 0.2) - shuffle : 셔플 옵션 (기본 True) - shuffle - 무작위, shuffle=False - 순차적 - random_state : 랜덤 시드값 - 매번 테스트시 같은값을 받기위한 세팅 즉 30개를 매번 같은 값으로 받음)
x = feature, y = label - 값이 동일하게 배분된것을 볼 수 있다 ((데이터량, 컬럼개수)) → feature 컬럼 4개, label 컬럼 1개
- 총 891개의 데이터중 80%가 훈련으로, 20%가 검증으로 분리된것을 볼 수 있다
03 숫자형(Numerical) 결측치 처리
- 제일 먼저 .info()를 활용하면 개수를 통해 어디 부분이 결측치가 있는지 볼 수 있다
train.info()
- 이렇게 목록이 11개면 눈으로 체크가 가능하지만 80,90개로 늘어나면 특히 11번같은 데이터는 파악이 힘들 수 도 있다. 이럴때 꿀팁!
# pandas의 isnull()을 써서 결측치 확인과 총 합을 이용해 한 눈에 확인 train.isnull().sum() # 개별 결측치 확인 # train['Age'].isnull().sum()
- 결측치를 채워 보자
# 결측치 처리 # train['Age'].fillna(0).describe() - 결측치를 0으로 처리 train['Age'].fillna(train['Age'].mean()).describe() # 결측치를 'Age' 컬럼의 평균으로 채움
714에서 결측치가 채워져 891이 되었다 - 'sklearn' 패키지의 'imputer'를 써서 결측치 처리
- imputer - 2개 이상의 column을 한번에 처리 할 때 사용
# 'sklearn'의 패키지 'imputer'를 사용해서 결측치 처리 # imputer - 2개 이상의 column을 한번에 처리 할 때 사용 from sklearn.impute import SimpleImputer # imputer를 쓰기위해서 변수화를 진행하고 결측치를 'mean' 값으로 처리하겠다는 말 imputer = SimpleImputer(strategy='mean') # .fit()을 통해 결측치 처리 학습 진행 imputer.fit(train[['Age', 'Pclass']]) # .transform() 을 해야 실제로 결측치에 대한 처리를 해줌 result = imputer.transform(train[['Age','Pclass']]) # 실제 결측치 처리 이후 다시 원 데이터 컬럼에 넣어 줘야 변함 train[['Age', 'Pclass']] = result train[['Age', 'Pclass']].isnull().sum() train[['Age', 'Pclass']].describe()
결측치 없이 꽉 채워 졌다 ▶ 사실 .fit()/.transform() 을 합쳐서 할 수 있다 = .fin_transform()
04 카테고리(Categorical) 결측치 처리
- 숫자형 결측치 경우는 숫자를 넣어주거나 평균, 중앙값들로 채워 줄 수 있었다.
- 문자형 처리를 배워 보자
# 1개의 column 처리 train['Embarked'].fillna('S').describe() # imputer를 써 2개 이상의 column 처리 imputer = SimpleImputer(strategy='most_frequent') # 'most_frequent' - 가장 빈도수가 높은 것들로 채움 result = imputer.fit_transform(train[['Embarked','Cabin']]) train[['Embarked','Cabin']] = result train[['Embarked','Cabin']].isnull().sum() Embarked 0 Cabin 0 dtype: int64
05 라벨 인코딩
- 'Label Encoding'으로 문자(Categorical)를 수치(Numerical)로 변환
- 머신러닝시에 기계는 절대로 문자를 인식 할 수 없음. 수치로 변환 시켜주는 작업이 필요함
- Label Encoding 은 라이브러리의 하나로 각각의 다른 문자열에따라 알아서 숫자를 부여해주는 패키지
(알파벳 순으로 정렬하고 그 정렬된 기준으로 숫자를 매김)
성별 컬럼을 라벨 인코딩 해보자 train['Sex'].value_counts() male 577 female 314 Name: Sex, dtype: int64
- 함수화를 통해 진행하는 방법 1
# 함수를 만들어 컬럼에 있는 데이터 형태를 보고 숫자를 리턴하도록 만들어야함 def convert(data): if data == 'male': return 1 elif data == 'female': return 0 # 함수를 .apply() 를 통해 함수 적용이 가능 하도록 함 train['Sex'].apply(convert) 0 1 1 0 2 0 3 0 4 1 .. 886 1 887 0 888 0 889 1 890 1 Name: Sex, Length: 891, dtype: int64
- 이제 라벨인코더 패키지를 이용하여 진행 2
# 라벨 인코더 임포트 from sklearn.preprocessing import LabelEncoder le = LabelEncoder() train['Sex_num'] = le.fit_transform(train['Sex']) * Nan값이 있으면 라벨 인코더 정상 작동 안됨 train['Sex_num'].value_counts <bound method IndexOpsMixin.value_counts of 0 1 1 0 2 0 3 0 4 1 .. 886 1 887 0 888 0 889 1 890 1 Name: Sex_num, Length: 891, dtype: int32>
#.classes_ -> 어떤 값들이 있었는지 확인 가능 le.classes_ array(['female', 'male'], dtype=object) # .inverse_transform() -> 각 주소에 맞는 문자열을 리턴 le.inverse_transform([0,1,1,0,0,1,1]) array(['female', 'male', 'male', 'female', 'female', 'male', 'male'], dtype=object)
* NaN 값이 있을 경우 오류가 뜰 수 있다. 이럴때는 NaN값을 채워주고 진행하면 된다.
06 One Hot Encoding
- 라벨 인코딩과 비슷하다. 라벨 인코딩의 경우 알파벳순으로 숫자를 매기기 때문에 랭크된 숫자 정보가 데이터에 잘못 반영이 될 수 있다
- 쉽게 이야기 하면 목록화해서 개별로 그 목록값에 대한 이진값으로 만들어 주는 패키지
(https://azanewta.tistory.com/46) 링크 참조! - 쉽게 아래 그림으로 보면 두개를 비교 할 수 있다.
- 예를 보자
train = pd.read_csv('https://bit.ly/fc-ml-titanic') train['Embarked'].value_counts() S 644 C 168 Q 77 Name: Embarked, dtype: int64 # 2개의 NaN 값 채우기 train['Embarked'] = train['Embarked'].fillna('S') train['Embarked'].value_counts() S 646 C 168 Q 77 Name: Embarked, dtype: int64 #라벨 인코딩 train['Embarked_num'] = LabelEncoder().fit_transform(train['Embarked']) train['Embarked_num'].value_counts() 2 646 0 168 1 77 Name: Embarked, dtype: int64
- 위에서 간단하게 설명했던 데로 '라벨 인코더를 써서 0,1,2 로 숫자형으로 잘 바꾸었다. 하지만 이 데이터를 그대로 머신러닝을 시키게 되면 기계는 데이터 안에서 관계를 찾게 된다
(예: 'S' = 2, 'Q' = 1 인데 Q+Q = S 구나 라고 학습해 버리게 된다) - 그렇기 때문에 독립적인 데이터는 별도의 컬럼으로 분리하고 각각의 컬럼에 대해 해당하는 값에만 특정 숫자를 부여해야한다. 이를 원 핫 인코딩 이라 부른다
- 독립적으로 데이터를 처리하고 각각의 컬럼에 해당값에만 True 나머지는 False를 갖도록 해보자
# 원핫인코딩전에는 반드시 더미 데이터가 필요하다 pd.get_dummies(train['Embarked_num'][:6])
컬럼 S C Q # 변수화 one_hot = pd.get_dummies(train['Embarked_num'][:6]) one_hot.columns = ['C','Q','S'] one_hot
- 위와 같이 컬럼을 분리시켜 카테고리형 -> 수치형으로 변환하고 그에 따라 생기는 수치형 값의 관계를 끊어주서어 독립적인 형태로 바꿔야 한다
07 정규화(Normalization)
- 컬럼간에 다른 min,max 값을 가지는 경우 정규화를 통해 최소치/최대값의 척도를 맞추는 것
- 영화 평점을 예로 진행해보자. 네이버는 0~10점 기준, 넷플릭스는 0~5점 기준으로 영화평점을 준다 가정하고 네이버에서는 6점, 넷플릭스에서는 5점일때 그 영화는 과연 네이버 기준 형편없는 영화일까? 같은 영화임에도 이렇게 다르게 데이터가 있을 수 있다. 이에대한 척도를 맞추는게 정규화이다.
# 네이버 영화 평점 (0~10점) : [2,4,6,8,10] # 넷플릭스 영화 평점 (0~5점) : [1,2,3,4,5] movie = {'naver':[2,4,6,8,10], 'netflix':[1,2,3,4,5]} movie = pd.DataFrame(data=movie) movie
▶ 정규화 패키지 이용
# 정규화 패키지 MinMaxScaler from sklearn.preprocessing import MinMaxScaler min_max_scaler = MinMaxScaler() min_max_movie = min_max_scaler.fit_transform(movie) #.fit_transform() 을 통해 학습하고 처리 pd.DataFrame(min_max_movie, columns=['naver','netflix'])
08 정규화(Standardization)
- 평균이 0, 표준편차가 1이 되도록 변환해주는 작업
# 평균이 0, 표준편차가 1이 되도록 변환 from sklearn.preprocessing import StandardScaler standard_scaler = StandardScaler() # 샘플 데이터 x = np.arange(10) # outlier 추가 x[9] = 1000 x.mean(), x.std() (103.6, 298.8100399919654) scaled = standard_scaler.fit_transform(x.reshape(-1,1)) #.reshape(-1, 1) 한컬럼에 하나만 scaled.mean(), scaled.std() (4.4408920985006264e-17, 1.0) <- 작은값일때는 0으로 나오지 않음 round(scaled.mean(), 2), scaled.std() (0.0, 1.0)
'빅데이터 > Machine-Learning' 카테고리의 다른 글
머신러닝 05 - sklearn 알아 보기 (회귀 - 2) (0) 2022.02.14 머신러닝 04 - sklearn 알아 보기 (분류 - 3, 회귀 - 1) (0) 2022.02.11 머신러닝 03 - sklearn 알아 보기 (분류 - 2 (몇가지 알고리즘)) (0) 2022.02.08 머신러닝 03 - sklearn 알아 보기 (분류 - 1) (0) 2022.02.08 머신러닝 01 - 정의와 용어 그리고 sklearn 기본 (0) 2022.02.04 - 전처리는 데이터를 분석에 적합하게 데이터를 가공/변형/처리/클리닝을 하는 작업이다