NA, NaN, None, null 로 표현한다. (언어마다 차이가 있다.)결측치를 처리하기 전에 "이 값이 기록되지 않아서 누락된 것인가, 아니면 존재하지 않아서 누락된 것인가?" 를 확인해야 한다.
존재하지 않아서 누락된 값이라면 이것은 어떤 값일까 추측할 필요 없이 결측치로 유지하면 되지만
값이 기록되지 않아서(수집하지 못해서) 누락된 경우는 해당 열과 행의 다른 값을 기반으로 값이 무엇이었을지 추측해 볼 수 있다
결측치가 수집하지 못해 누락된 경우 그 값일 가능성이 가장 높은 값으로 대체할 수 있다.
대체할 값으로 일정한 값을 사용하는 경우와 분석을 통해 찾는 방법이 있다.
- 실수형 데이터로 구성된 Feature는 수치형 값이다.
- 문자열 데이터로 구성된 Feature는 단순 문자열값이거나 범주형 값이다.
- 정수형 데이터로 구성된 Feature는 범주형이거나 연속형 값이다.
- 몇개의 고유값으로 구성되었는지를 봐야 한다. 또는 평균의 의미롤 확인해 본다. 평균이 그 feature를 표현하는 값이면 수치형 아니면 범주형.

cols = ['age', 'workclass','fnlwgt','education', 'education-num', 'marital-status', 'occupation','relationship', 'race', 'gender','capital-gain','capital-loss', 'hours-per-week','native-country', 'income']import pandas as pd adult_df = pd.read_csv( "data/adult.data", header=None, names=cols, skipinitialspace=True, # CSV 파일을 읽을 때 각 셀의 시작부분에 있는 공백을 무시하도록 하는 매개변수 na_values="?" ) adult_df.shape()(32561, 15)
# 결측치 제거 adult_df.dropna(inplace=True) # 결측치가 있는 행들을 모두 제거. adult_df.shape()(30162, 15)
encoding_columns 컬럼들은 Label Encoding 처리,
not_encoding_columns 컬럼들의 값들은 그대로 유지.
encoding_columns의 값들은 LabelEncoding 된 값으로 not_encoding_columns의 값들은 원래값 그대로 구성된 DataFrame을 생성해서 반환한다.
주의: LabelEncoding은 Feature(컬럼) 별로 처리해야 한다. 한번에 여러컬럼을 하나의 LabelEncoder로 처리할 수 없다.
encoding_columns = ['workclass','education','marital-status', 'occupation','relationship','race','gender','native-country', 'income'] not_encoding_columns = ['age','fnlwgt', 'education-num','capital-gain','capital-loss','hours-per-week']df = adult_df.copy() ## encoding_columns들을 label encoding ## scikit learn의 LabelEncoder는 컬럼 단위로 처리 from sklearn.preprocessing import LabelEncoder le_dict = {} # 각 열에 대한 LabelEncoder 객체를 저장. for col in encoding_columns : le = LabelEncoder() df[col] = le.fit_transform(df[col]) # col열의 데이터를 레이블인코딩하고 다시 할당. le_dict[col] = le adult_df.head()
df.head()
# adult dataset의 income 추론 모델링 # 데이터 분할. ## X, y 나누기 ## train/validation/test set 나누기 y = df['columns'].values # .values: 해당 열의 값을 numpy 배열로 변환. X = df.drop(columns="income").values y.shape(), X.shape()((30162,), (30162, 14))
# hold out 방식으로 데이터셋 나누기 from sklearn.model_selection import train_test_split # 전체 데이터셋을 train/test set으로 나눔. X_tmp, X_test, y_tmp, y_test = train_test_split(X, y, test_size=0.25, stratify=y, random_stat=0) # 남은 train set을 train/validation set으로 나눔. X_train, X_val, y_train, y_val = train_test_split(X_tmp, y_tmp, test_size=0.25, stratify=y_tmp, ranomd_state=0) X_train.shape, X_test.shape, X_val.shape((16965, 14), (7541, 14), (5656, 14))
from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score ### 모델링 max_depth_list = [3, 4, 5, 6, 7, 8, 9, 10, 11,12] train_acc_list = [] val_acc_list = [] for max_depth in max_depth_list : model = DecisionTreeclassifier(max_depth=max_depth, random_state=0) model.fit(X_train, y_train) # 검증 pred_train = model.predict(X_train) pred_val = model.predict(X_val) train_acc = accuracy_score(y_train, pred_train) val_acc = accuracy_score(y_val, pred_val) print(f"max_depth: {max_depth}, validation 정확도: {val_acc}") train_acc_list.append(train_acc) val_acc_list.append(val_acc)max_depth: 3 validation 정확도: 0.8306223479490806
max_depth: 4 validation 정확도: 0.8373408769448374
max_depth: 5 validation 정확도: 0.8408769448373409
max_depth: 6 validation 정확도: 0.8373408769448374
max_depth: 7 validation 정확도: 0.844059405940594
max_depth: 8 validation 정확도: 0.8460042432814711
max_depth: 9 validation 정확도: 0.8481258840169731
max_depth: 10 validation 정확도: 0.8451202263083452
max_depth: 11 validation 정확도: 0.8468882602545968
max_depth: 12 validation 정확도: 0.8474186704384724# train/validation set 에서 DecisionTreeClassifier model의 정확도 plot import matplotlib.pyplot as plot # x축: max_depth_list, y축: train_acc_list/val_acc_list plt.plot(max_depth_list, train_acc_list, label="train set accuracy") plt.plot(max_depth_list, val_acc_list, label="validation set accuracy") plt.legend() plt.show()
#### 최종평가 best_model = DecisionTreeClassifer(max_depth=9, random_state=0) best_model.fit(X_train, y_train) pred_test = best_model.predict(X_test) test_acc = accuracy_score(y_test, pred_test) print("최종 정확도 평가:", test_acc)최종 정확도 평가결과: 0.8380851345975335
OneHotEncoder객체 생성시 sparse 매개변수의 값을 False로 설정하지 않으면 scipy의 csr_matrix(희소행렬 객체)로 반환.
희소행렬은 대부분 0으로 구성된 행렬과 계산이나 메모리 효율을 이용해 0이 아닌 값의 index만 관리한다.
csr_matrix.toarray()로 ndarray로 바꿀수 있다.
희소 행렬 vs 밀집 배열
1. 희소 행렬(Sparse Matrix):
- 희소 행렬은 대부분의 원소가 0인 행렬을 의미한다. 즉, 데이터의 대다수가 0인 경우. 예를 들어, 텍스트 문서의 단어-문서 행렬이나 사용자-아이템 평점 행렬 등이 대표적인 희소 행렬이다.
- 희소 행렬은 0이 아닌 원소의 위치와 값을 저장하므로, 메모리 효율적으로 데이터를 저장한다. 따라서, 희소한 데이터에 적합한 데이터 구조이다.
2. 밀집 배열(Dense Array):
- 밀집 배열은 대부분의 원소가 0이 아닌 값을 가지는 배열을 의미한다. 즉, 대부분의 원소가 0이 아닌 경우. 예를 들어, 이미지 데이터나 신경망에서의 중간 출력값 등이 밀집 배열의 예시이다.
- 밀집 배열은 모든 원소의 값을 저장하므로, 메모리를 더 많이 사용한다. 그러나 계산 및 연산에 있어 효율적이다.
cols = ['age', 'workclass','fnlwgt','education', 'education-num', 'marital-status', 'occupation','relationship', 'race', 'gender','capital-gain','capital-loss', 'hours-per-week','native-country', 'income'] use_cols = ['age', 'workclass','education', 'occupation', 'gender', 'hours-per-week', 'income']df2 = adult_df[use_cols].reset_index(drop=True) df2
# 필요한 feature들만 추출 category_colnames = ['workclass','education', 'occupation', 'gender'] continuous_colnames = ['age', 'hours-per-week'] target = 'income'# X, y (target-income)를 분리 # y는 LabelEncoding target_value = df2[target] data = df2.drop(columns=target)y_le = LabelEncoder() y2 = y_le.fit_transform(target_value) y2array([0, 0, 0, ..., 0, 0, 1])
# onehot encoding 처리 # category_colnames 컬럼들을 원핫인코딩 from sklearn.preprocessing import OneHotEncoder ohe = OneHotEncoder() category_ohe = ohe.fit_transform(data[category_colnames]) category_ohe.shape(30162, 39)
### category_ohe => 범주형 컬럼들의 값만 변환한 결과 ##### category_ohe + 수치형(연속형) 컬럼들을 붙여준다. # DF + DF(합치기) -> pd.concat() # ndarray + ndarray (합치기) -> np.concatenate() import numpy as np X2 = np.concatenate([category_ohe.toarray(), data[continuous_colnames].values], axis=1) X2.shape()(30162, 41)
# 모델 학습 from sklearn.model_selection import train_test_split # test set 분리 X_tmp2, X_test2, y_tmp2, y_test2 = train_test_split(X2, y2, stratify=y2, test_size=0.25, random_state=0) # train, validation set 분리 X_train2, X_val2, y_train2, y_val2 = train_test_split(X_tmp2, y_tmp2, stratify=y_tmp2, test_size=0.25, random_state=0) X_train2.shape, X_val2.shape, X_test2.shape((16965, 41), (5656, 41), (7541, 41))
# 모델 생성 from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score max_depth_list2 = range(3, 11) train_acc_list2 = [] val_acc_list2 = [] for max_depth2 in max_depth_list2 : model2 = DecisionTreeClassifier(max_depth=max_depth2, random_state=0) model2.fit(X_train2, y_train2) pred_train2 = model2.predict(X_train2) pred_val2 = model2.predict(X_val2) train_acc2 = accuracy_score(y_train2, pred_train2) val_acc2 = accuracy_score(y_val2, pred_val2) print(f"max_depth: {max_depth2}, val 정확도: {val_acc2}") train_acc_list2.append(train_acc2) val_acc_list2.append(val_acc2)max_depth: 3 val 정확도: 0.7715700141442716
max_depth: 4 val 정확도: 0.7865983026874116
max_depth: 5 val 정확도: 0.7874823196605375
max_depth: 6 val 정확도: 0.7904879773691655
max_depth: 7 val 정확도: 0.7966760961810466
max_depth: 8 val 정확도: 0.7942008486562943
max_depth: 9 val 정확도: 0.7943776520509194
max_depth: 10 val 정확도: 0.7841230551626591import matplotlib.pyplot as plt plt.plot(max_depth_list2, train_acc_list2, label="train_acc") plt.plot(max_depth_list2, val_acc_list2, label="val_acc") plt.legend() plt.show()
best_model2 = DecisionTreeClassifier(max_depth=7, random_state=0) best_model2.fit(X_train, y_train) pred_test2 = best_model2.predict(X_test2) test_acc2 = accuracy_score(y_test2, pred_test2) print("Test set 최종 정확도 평가:", test_acc2)Test set 최종 정확도 평가: 0.8055960747911417
수치형 데이터를 전처리할 때 주로 사용되는 방법으로 StandardScaler와 MinMaxScaler가 있습니다. 이 두 스케일러를 사용하는 이유는 다음과 같습니다:
따라서, StandardScaler와 MinMaxScaler는 데이터의 분포를 조정하여 모델 학습을 효율적으로 만드는 데 사용됩니다. 데이터의 특성과 모델의 요구에 따라 선택할 수 있습니다.
from sklearn.datasets import load_breast_cancer dataset = load_breast_cancer() X, y = dataset.data, dataset.targetimport pandas as pd import numpy as np # DataFrame으로 데이터 확인 df = pd.DataFrame(X, columns=dataset.feature_names) df['target'] = np.where(y==0, dataset.target_names[0], dataset.target_names[1]) # y==0인 경우, dataset.target_names[0]인 'malignant(악성)'을 선택하고 0이 아닌 경우, dataset.target_namese[1]인 'benign(양성)'을 선택 df.head()
from sklearn.model_selection import train_test_split X_tmp, X_test, y_tmp, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0) X_train, X_val, y_train, y_val = train_test_split(X_tmp, y_tmp, test_size=0.2, stratify=y_tmp, random_state=0) X_train.shape, X_val.shape, X_test.shape((364, 30), (91, 30), (114, 30))
from sklearn.preprocessing import StandardScaler, MinMaxScaler # 객체 생성 scaler1 = StandardScaler() # fitting - 수치형 features 들을 변환 scaler1.fit(X_train) # train set 으로 학습 ## 변환 X_train_scaled1 = scaler1.transform(X_train) # train set 변환 X_val_scaled1 = scaler1.transform(X_val) # validation set 변환 X_test_scaled1 = scaler1.transform(X_test) # test set 변환.scaler2 = MinMaxScaler() # trainset으로 학습 scaler2.fit(X_train, y_train) # 변환 X_train_scaled2 = scaler2.transform(X_train) X_val_scaled2 = scaler2.transform(X_val) X_test_scaled2 = scaler2.transform(X_test)Modeling
from sklearn.svm import SVC from sklearn.metrics import accuracy_scorescaling하지 않은 데이터셋 이용
# 하이퍼파라미터 C, gamma # svm = SVC(C=0.1, gamma=0.1, random_state=0) svm = SVc(random_state=0) # 학습 svm.fit(X_train, y_train) # 검증/평가 print("Train set:", accuarcy_score(y_train, svm.predict(X_train))) print("Valid set:", accuracy_score(y_val, svm.predict(X_val))) print("Test set:", accuracy_score(y_test, svm.predict(X_test)))Train set: 0.9203296703296703
Valid set: 0.9120879120879121
Test set: 0.9122807017543859
standardscaler 데이터셋 이용
# 하이퍼파라미터 C, gamma # svm = SVC(C=0.1, gamma=0.1, random_state=0) svm1 = SVC(random_state=0) # 학습 svm1.fit(X_train_scaled1, y_train) # 검증/평가 print("Train set: ", accuracy_score(y_train, svm1.predict(X_train_scaled1))) print("Valid set:", accuracy_score(y_val, svm1.predict(X_val_scaled1))) print("Test set:", accuracy_score(y_test, svm1.predict(X_test_scaled1)))Train set: 0.9917582417582418
Valid set: 0.989010989010989
Test set: 0.9473684210526315
MinMaxScaler 데이터셋 이용
# 하이퍼파라미터 C, gamma # svm = SVC(C=0.1, gamma=0.1, random_state=0) svm = SVC(random_state=0) # 학습 svm.fit(X_train_scaled2, y_train) # 검증/평가 print("Train set: ", accuracy_score(y_train, svm.predict(X_train_scaled1))) print("Valid set:", accuracy_score(y_val, svm.predict(X_val_scaled2))) print("Test set:", accuracy_score(y_test, svm.predict(X_test_scaled2)))Train set: 0.37362637362637363
Valid set: 0.989010989010989
Test set: 0.9473684210526315
모델 저장 -> pickle
전처리 객체, 모델 객체
import os import pickle os.makedirs('saved_models', exist_ok=True) # StandardScaler, svm 모델 저장 with open("saved_models/wisconsin_scaler.pkl", "wb") as fw1: pickle.dump(scaler1, fw1) with open("saved_models/wisconsin_svm.pkl", "wb") as fw2: pickle.dump(svm1, fw2) with open("saved_models/wisconsin_scaler.pkl", "rb") as fr1: saved_scaler = pickle.load(fr1) with open("saved_models/wisconsin_svm.pkl", "rb") as fr2: saved_model = pickle.load(fr2) # 전처리 X_test_scaled = saved_scaler.transform(X_test) pred_test = saved_model.predict(X_test_scaled) accuracy_score(y_test, pred_test)0.9473684210526315