데이터분석

빅데이터 분석기사 작업 유형 2 - 데이터 전처리

환성 2022. 8. 9. 22:31
728x90

다음은 펭귄 데이터를 이용하여 빅데이터 분석기사에서 활용할 수 있는 전처리에 대해 설명하고자 합니다.

# 작업 유형2 - 데이터 전처리
# 펭귄 데이터를 이용해서 전처리

import seaborn as sns
df = sns.load_dataset('penguins')
print(df.head())


# 결과
  species     island  bill_length_mm  bill_depth_mm  flipper_length_mm  \
0  Adelie  Torgersen            39.1           18.7              181.0   
1  Adelie  Torgersen            39.5           17.4              186.0   
2  Adelie  Torgersen            40.3           18.0              195.0   
3  Adelie  Torgersen             NaN            NaN                NaN   
4  Adelie  Torgersen            36.7           19.3              193.0   

   body_mass_g     sex  
0       3750.0    Male  
1       3800.0  Female  
2       3250.0  Female  
3          NaN     NaN  
4       3450.0  Female


df.isna().sum()  # isna를 통해 데이터셋에 결측치가 있는지 확인하고 sum을 통해 합계를 보여준다

# 결과 
species               0
island                0
bill_length_mm        2
bill_depth_mm         2
flipper_length_mm     2
body_mass_g           2
sex                  11
dtype: int64

이후 결측치가 존재하는 열을 확인한 후 missing이라는 배열에 담아 결측치를 중앙값으로 채워넣는다.

#1. 결측치 제거
missing = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g'] # 결측치 존재 열 
for i in missing:
    df[i] = df[i].fillna(df[i].median()) # 중앙값으로 다 채워넣음
df['sex'] = df['sex'].fillna('Male') # 성별과 같은 범주형의 경우 비중이 높은 남성으로 입력
df

# 결과
	species	island	bill_length_mm	bill_depth_mm	flipper_length_mm	body_mass_g	sex
0	Adelie	Torgersen	39.10	18.7	181.0	3750.0	Male
1	Adelie	Torgersen	39.50	17.4	186.0	3800.0	Female
2	Adelie	Torgersen	40.30	18.0	195.0	3250.0	Female
3	Adelie	Torgersen	44.45	17.3	197.0	4050.0	Male
4	Adelie	Torgersen	36.70	19.3	193.0	3450.0	Female
...	...	...	...	...	...	...	...
339	Gentoo	Biscoe	44.45	17.3	197.0	4050.0	Male
340	Gentoo	Biscoe	46.80	14.3	215.0	4850.0	Female
341	Gentoo	Biscoe	50.40	15.7	222.0	5750.0	Male
342	Gentoo	Biscoe	45.20	14.8	212.0	5200.0	Female
343	Gentoo	Biscoe	49.90	16.1	213.0	5400.0	Male
344 rows × 7 columns

 

이후 사이킷런 패키지의 LabelEncoder를 불러와 수치형이 아닌 변수들을 지도학습을 편리하게 하기 위해 수치형으로 다 라벨링을 해준다. 

 

#2. 라벨 인코딩

from sklearn.preprocessing import LabelEncoder
label = ['species', 'island', 'sex'] # 수치형이 아닌 변수들을 수치로 라벨링 해줌
df[label] = df[label].apply(LabelEncoder().fit_transform) # apply 함수로 리스트화 되어 있는 변수들의 라벨인코딩
df

# 결과
	species	island	bill_length_mm	bill_depth_mm	flipper_length_mm	body_mass_g	sex
0	0	2	39.10	18.7	181.0	3750.0	1
1	0	2	39.50	17.4	186.0	3800.0	0
2	0	2	40.30	18.0	195.0	3250.0	0
3	0	2	44.45	17.3	197.0	4050.0	1
4	0	2	36.70	19.3	193.0	3450.0	0
...	...	...	...	...	...	...	...
339	2	0	44.45	17.3	197.0	4050.0	1
340	2	0	46.80	14.3	215.0	4850.0	0
341	2	0	50.40	15.7	222.0	5750.0	1
342	2	0	45.20	14.8	212.0	5200.0	0
343	2	0	49.90	16.1	213.0	5400.0	1
344 rows × 7 columns

이후 데이터를 변환해주는데 정수형을 카테고리형으로 변경해준다.

#3. 데이터 변환, 더미

import pandas as pd
category = ['island', 'sex'] 
for i in category:
    df[i] = df[i].astype('category') # 정수형을 카테고리형으로 변경
df = pd.get_dummies(df) # 더미변수로 변환
df

# 결과 	
species	bill_length_mm	bill_depth_mm	flipper_length_mm	body_mass_g	island_0	island_1	island_2	sex_0	sex_1
0	0	39.10	18.7	181.0	3750.0	0	0	1	0	1
1	0	39.50	17.4	186.0	3800.0	0	0	1	1	0
2	0	40.30	18.0	195.0	3250.0	0	0	1	1	0
3	0	44.45	17.3	197.0	4050.0	0	0	1	0	1
4	0	36.70	19.3	193.0	3450.0	0	0	1	1	0
...	...	...	...	...	...	...	...	...	...	...
339	2	44.45	17.3	197.0	4050.0	1	0	0	0	1
340	2	46.80	14.3	215.0	4850.0	1	0	0	1	0
341	2	50.40	15.7	222.0	5750.0	1	0	0	0	1
342	2	45.20	14.8	212.0	5200.0	1	0	0	1	0
343	2	49.90	16.1	213.0	5400.0	1	0	0	0	1

이후 파생변수를 통해 qcut으로 분위수를 계산한 뒤 이를 기반으로 이산화를 수행해준다. 이 경우 구간은 5개로 설정해주었고 labels를 False로 해주어야 올바르게 값이 열에 들어가게 된다.

#4. 파생변수
# qcut으로 특정변수의 분위수를 계산하여 이를 기반으로 이산화 수행
# 구간은 5개 
df['body_mass_g_qcut'] = pd.qcut(df['body_mass_g'],5, labels=False)
df.head()

# 결과
	species	bill_length_mm	bill_depth_mm	flipper_length_mm	body_mass_g	island_0	island_1	island_2	sex_0	sex_1	body_mass_g_qcut
0	0	39.10	18.7	181.0	3750.0	0	0	1	0	1	1
1	0	39.50	17.4	186.0	3800.0	0	0	1	1	0	1
2	0	40.30	18.0	195.0	3250.0	0	0	1	1	0	0
3	0	44.45	17.3	197.0	4050.0	0	0	1	0	1	2
4	0	36.70	19.3	193.0	3450.0	0	0	1	1	0	0

스케일을 통해 fit, transform을 해준다. 이때 사이킷런 패키지의 MinMaxScaler를 통해 fit, transform을 한다. MinMaxScaler외에도 PCA클래스, Feature Vectorization 클래스등 여러가지가 있지만 이 경우 MinMaxScaler를 사용해준다.

#5. 스케일
# 스케일할 변수를 리스트화
# fit하고 transform을 통해 스케일 변환 진행
from sklearn.preprocessing import MinMaxScaler
scaler = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']
min = MinMaxScaler()
min.fit(df[scaler])
df[scaler] = min.transform(df[scaler])
df

# 결과
	species	bill_length_mm	bill_depth_mm	flipper_length_mm	body_mass_g	island_0	island_1	island_2	sex_0	sex_1	body_mass_g_qcut
0	0	0.254545	0.666667	0.152542	0.291667	0	0	1	0	1	1
1	0	0.269091	0.511905	0.237288	0.305556	0	0	1	1	0	1
2	0	0.298182	0.583333	0.389831	0.152778	0	0	1	1	0	0
3	0	0.449091	0.500000	0.423729	0.375000	0	0	1	0	1	2
4	0	0.167273	0.738095	0.355932	0.208333	0	0	1	1	0	0
...	...	...	...	...	...	...	...	...	...	...	...
339	2	0.449091	0.500000	0.423729	0.375000	1	0	0	0	1	2
340	2	0.534545	0.142857	0.728814	0.597222	1	0	0	1	0	3
341	2	0.665455	0.309524	0.847458	0.847222	1	0	0	0	1	4
342	2	0.476364	0.202381	0.677966	0.694444	1	0	0	1	0	4
343	2	0.647273	0.357143	0.694915	0.750000	1	0	0	0	1	4

 

이후 데이터를 지도학습 시키기 위하여 train셋과 test셋으로 나누어준다.  이때 test_size는 0.2로 20%만 test셋으로 나누고 random_state경우 1을 기준으로 진행하였다.

# 6. 데이터 분리

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df.iloc[:, 1:], df['species'], 
test_size=0.2, stratify=df['species'], random_state=1)
print('x_train', X_train.shape)
print('x_test', X_test.shape)
print('y_train', y_train.shape)
print('y_test', y_test.shape)

# 결과
x_train (275, 10)
x_test (69, 10)
y_train (275,)
y_test (69,)

이후 모형학습을 해주는데 여러가지 방법이 있다. 랜덤포레스트, 에이다 부스트, k-최근접 이웃 알고리즘 등이 있다.

#7. 모형학습

# 랜덤포레스트 분류모형
from sklearn.ensemble import RandomForestClassifier
model1 = RandomForestClassifier(max_depth=6, n_estimators=100)
model1.fit(X_train, y_train)
pred1 = model1.predict(X_test)

# 에이다 부스트 분류모형
from sklearn.ensemble import AdaBoostClassifier
model2 = AdaBoostClassifier()
model2.fit(X_train, y_train)
pred2 = model2.predict(X_test)
#8. 앙상블

# 보팅은 hard 투표기반으로 진행, clf에 할당
# 훈련용 데이터를 입력하여 clf 핏
# 테스트 데이터를 입력하여 pred3에 할당
from sklearn.ensemble import VotingClassifier
clf = VotingClassifier(estimators=[('rf', model1), ('ad', model2)],voting='hard')
clf.fit(X_train, y_train)
pred3 = clf.predict(X_test)

모형학습을 다 끝낸 뒤 모형평가를 통해 어떤 모형이 가장 정확도가 높았는지 평가를 해준다.

 

#9. 모형평가

from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
print('랜포 정확도' ,accuracy_score(y_test, pred1))
print('아이다 정확도', accuracy_score(y_test, pred2))
print('보팅 정확도', accuracy_score(y_test, pred3))

# 결과
랜포 정확도 1.0
아이다 정확도 0.9855072463768116
보팅 정확도 1.0
#10. 하이퍼파라미터 튜닝
# 그리드 서치를 위한 파라미터 범위지정, parameters 변수에 할당
# 기본적인 랜덤포레스트 모형 만들고, 그리드서치를 통해 최적의 파라미터 추정
# print함수를 통해 학습된 모형의 최적의 하이퍼파라미터를 best_params_함수로 출력

from sklearn.model_selection import GridSearchCV
parameters = {'n_estimators':[50, 100], 'max_depth':[4,6]}
model4 = RandomForestClassifier()
clf = GridSearchCV(estimator=model4, param_grid=parameters, cv=3)
clf.fit(X_train, y_train)
print('최적의 파라미터', clf.best_params_) # {'max_depth': 6, 'n_estimators': 100}

 

제출을 위해 파일을 저장한 뒤 read_csv를 통해 제대로 저장이 되었는지 확인해준다.

#11. 파일저장
# y_test의 index를 id로 pred3을 pred열로 하는 데이터프레임 만들고 csv로 저장
# index = False로 함, True시에 인덱스가 추가로 생성
pd.DataFrame({'id': y_test.index, 'pred': pred3}).to_csv('003000000.csv', index=False)
check = pd.read_csv('003000000.csv')
check.head()

# 결과
	id	pred
0	57	0
1	173	1
2	213	1
3	50	0
4	25	0