주제
1. Classification 모델 종류
2. Classification 모델 성능 평가
3. scikit-learn의 데이터 전처리 기능
4. 숙제
1. Classification 모델 종류
- 데이터를 다야한 클래스로 분류하는 데 사용
- 종류 :
- 이진 분류(Binary Classification) : 두 개의 클래스로 분류
- 다중 클래스 분류(Multiclass Classification) : 3개 이상의 클래스로 분류
- 다중 레이블 분류(Multilabel Classification) : 한 레코드가 여러 클래스에 할당될 수 있음
- 알고리즘의 종류 :
- Logistic Regression : 이진 분류 문제에 사용
- Decision Tree : 직관적이고 시각화가 쉬움
- Random Forests
- Support Vector Machine : 복잡한 분류 문제에 효과적
- Deep Learning : 고급 분류 문제에 사용(이미지 및 음성 인식 등)
1.1 Logisitic Regression vs. Softmax Regression
| Linear Regression | Logisitic Regression | Softmax Regression |
| regression | binary classification | multi-label classification |
| 공부 시간에 따른 시험 점수 예측 | 공부 시간에 따른 시험 합격 예측 | 공부시간에 따른 학점 예측 |
1.2 Support Vector Machine
- feature space를 변환하여 분류 작업 수행
1.3 Decision Tree
- 회귀 문제에도 사용 가능
- 피쳐의 중요도가 나오고 동작 방식을 상대적으로 이해하고 설명이 가능함
2. Classification 모델 성능 평가
2.1 Confusion Matrix
- Precision = TP / (TP + FP) → 양성으로 예측된 것중 실제로 양성인 것
- Recall = TP / (TP + FN) → 실제 양성 중 얼마나 양성으로 예측되었는가
- F1 score = 2 * (precision * recall) / (precision + recall) → precision과 recall의 조화평균
- Accuracy = (TP + TN) / (TP + TN + FP + FN)
- True Positive(TP) : 스팸을 스팸이라 판정하는 경우
- False Positive : 정상리뷰를 스팸이라 판정하는 경우
- 모든 리뷰를 스팸이라고 판정하면 TPR은 100%지만 FPR도 100%
- 모든 리뷰를 정상이라고 판정하면 FPR은 0%지만 TPR도 0%
- Binary classifier는 확률을 반환
- 어떤 threshold(임계치)를 사용할지 결정하는게 ROC
2.2 ROC 커브
- Receiver Operating Characteristic : Binary classifier의 정확도를 보기 위한 용도
- True Positive Rate을 y축, False Positive Rate을 x축으로 그린 그래프
- 이 그래프를 통해 TPR은 높게, FPR은 낮게 만드는 최적의 위치를 찾음
- 이 커브의 밑 면적을 계산한 것이 AUC
- AUC는 0 ~ 1 사이의 값을 가지며 1과 가까울수록 모델이 정확함을 의미
- AUC값을 보고 이진 분류의 경우에는 threshold를 결정함
3. scikit-learn의 데이터 전처리 기능
- 큰 흐름 :
- 머신 러닝 알고리즘과 모델 성과 지표 결정
- 데이터셋 로딩
- 데이터셋을 훈련/테스트 세트로 분리
- 훈련 데이터 전처리
- 훈련 데이터로 모델 빌딩
- 테스트 데이터 전처리
- 레이블 정보 제외 테스트 데이터를 모델에 입력으로 지정
- 결과물과 정답을 비교하여 성과 계산
3.1 피쳐 추출과 변환
- 피쳐값들을 훈련에 적합한 형태로 바꾸는 것(Data Transformations)
- 데이터 전처리
- 비어있는 필드값 채우기(Imputation of missing values)
- Imputer를 이용하여 기본값을 정해서 결측치 채우기
- sklearn.preprocessing 패키지 안에 2개의 Imputer가 존재
- SimpleImputer : 간단한 통계를 지정하여 누락된 값을 대체
- IterativeImputer : 결측값이 있는 각 피쳐를 다른 피쳐들의 함수로 지정
import numpy as np
from sklearn.impute import SimpleImputer
# Example dataset with missing values
data = np.array([
[1, np.nan, 3],
[4, 3, np.nan],
[np.nan, 6, 9],
[8, 5, 2]
])
imputer = SimpleImputer(missing_values=np.nan, strategy='mean')
imputed_data = imputer.fit_transform(data)
print("Original Data:")
print(data)
print("\nImputed Data:")
print(imputed_data)

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
iterative_imputer = IterativeImputer(max_iter=10, random_state=0)
imputed_data = iterative_imputer.fit_transform(data)
print("Original Data:")
print(data)
print("\nImputed Data:")
print(imputed_data)

- 카테고리를 숫자로 변환
- sklearn.preprocessing 패키지 안에 여러 인코더가 존재함
- OneHotEncoder : 서로 관계 없는 카테고리들을 인코딩하는 경우
- LabelEncoder : 레이블 필드를 인코딩하는 경우
- OrdinalEncoder : 순서가 있는 카테고리들을 인코딩하는 경우
- OneHotEncoder vs. OrdinalEncoder
- sklearn.preprocessing 패키지 안에 여러 인코더가 존재함
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import OneHotEncoder
data = [['seoul'], ['tokyo'], ['beijing']]
encoder = OrdinalEncoder()
result = encoder.fit_transform(data)
encoder.categories_
result

enc = OneHotEncoder(sparse=False)
enc.fit(data)
X_ohe = enc.transform(data)
X_ohe

from sklearn.preprocessing import LabelEncoder
y = ['recurrence-events', 'no-recurrence-events', 'recurrence-events']
label_encoder = LabelEncoder()
y_labeled = label_encoder.fit_transform(y)
print(y_labeled)

- 숫자 필드값의 범위 표준화
- sklearn.preprocessing 패키지 안에 여러 스케일러가 존재함
- StandardScaler : 각 값에서 평균을 빼고 표준편차로 나눔. 값의 분포를 정규분포를 따르도록 변환
- MinMaxScaler : 모든 값을 0과 1사이로 스케일. 각 값에서 최소값을 빼고(최대값 - 최소값)으로 나눔
- RobustScaler, MaxAbsScaler, etc...
- sklearn.preprocessing 패키지 안에 여러 스케일러가 존재함
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
import numpy as np
X_train = np.array([[ 1., -1., 2.],
[ 2., 0., 0.],
[ 0., 1., -1.]])
scaler = StandardScaler().fit(X_train)
X_scaled = scaler.transform(X_train)
print(X_scaled)

scaler = MinMaxScaler().fit(X_train)
X_scaled = scaler.transform(X_train)
print(X_scaled)

3.2 파이프라인 사용해보기
- 파이프라인으로 표준화와 알고리즘 학습까지 한번에 묶어 실시
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = make_classification(random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
pipe = make_pipeline(StandardScaler(), LogisticRegression())
pipe.fit(X_train, y_train)
pipe.score(X_test, y_test)
3.3 Classification 리포트 생성
- 각종 성능 평가 지표를 한번에 볼 수 있는 리포트 생성
from sklearn.metrics import classification_report
classificationReport = classification_report(y_test, predicted)
print(classificationReport)

4. 숙제
- Age 필드의 빈 값을 SingleImputer를 이용하여 평균으로 채우기
- Embarked 필드 :
- 빈 값을 가장 흔한 값으로 채우기
- OneHotEncoder를 사용하여 변환 후 학습 필드로 추가하여 모델링 진행해보기
- 최종 classification report 실행 후 화면 제출
4.1 Age 필드 채우기
- 결측치를 채우기 전 데이터의 info

- Age는 714개의 데이터가 존재
- SimpleImputer를 사용하여 평균값으로 결측치 대체
# Age의 빈 값을 평균으로 채우기
imputer = SimpleImputer(strategy='mean')
train[['Age']] = imputer.fit_transform(train[['Age']])

4.2 Embarked 필드
- Embarked 필드도 마찬가디로 889개의 데이터가 존재(2개의 결측치 확인)
- SimpleImputer로 가장 흔한 값으로 채워넣기
# Embarked 필드의 결측치를 가장 흔한 값으로 채우기
imputer = SimpleImputer(strategy='most_frequent')
train[['Embarked']] = imputer.fit_transform(train[['Embarked']])
train.info()

- Embarked의 고유값은 총 3개(C, S, Q)로 승선지역의 이니셜을 나타냄
- OneHotEncoder를 사용하여 인코딩 진행
# Embarked 필드 인코딩하기
from sklearn.preprocessing import OneHotEncoder
embarked_col = train[['Embarked']]
encoder = OneHotEncoder(sparse_output=False)
embarked_encoded = encoder.fit_transform(embarked_col)
# 데이터 프레임으로 변환
embarked_df = pd.DataFrame(embarked_encoded)

- 원래 데이터에 결합하고 column명 변경
train_encoded = pd.concat([train, embarked_df], axis=1)
train_encoded.rename(columns={0: 'C', 1: 'Q', 2: 'S'}, inplace=True)
4.3 모델링
- 훈련 데이터 만들기
train = train_encoded.drop(
['PassengerId', 'Name', 'Ticket', 'Cabin', 'Sex', 'Embarked', 'Parch', 'SibSp'],
axis=1
)

- 훈련 세트 / 테스트 세트 나누기
# 훈련 데이터 만들기
X = train[["Pclass", "Gender", "Age", "C", "Q", "S"]]
y = train["Survived"]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.2)
- 스케일링 진행
# 스케일링
scaler = MinMaxScaler()
scaler.fit(X_train)
X_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
- 로지스틱 회귀 모델 만들기
# Logistic Regression 모델 만들기
lr = LogisticRegression(random_state=1)
log_reg = lr.fit(X_scaled, y_train)
- 검증
expected = y_test
predicted = log_reg.predict(X_test_scaled)
classificationReport = classification_report(expected, predicted, target_names=["Died", "Survived"])
print(classificationReport)

4.4 결과 해석
- Embarked 필드를 추가하지 않고 학습한 모델의 정확도는 81%였다.
- Embarked 필드를 추가한 후의 정확도는 82%로 큰 차이를 보이지 않았다.
- 이는 승객의 승선지역은 생존 여부에 큰 영향을 미치지 않은 것으로 보인다.
느낀점
타이타닉 데이터를 처음 접했을 때는 머신러닝을 몰라서 단순하게 성별과 나이, 등급 정도로만 사용하여 단순 예측을 했었는데(정확도가 약 75% 정도였던 것으로 기억), 머신 러닝 알고리즘을 사용하여 데이터 스케일링도 하고 학습시켜보니 정확도가 올라가는게 신기하다. 숙제를 하면서도 크게 어렵지 않게 재밌게 했다. 알고리즘을 바꾸면 더 높은 정확도가 나오지 않을까...? 시간나면 해봐야겠다. 아무튼 머신 러닝 수업 시작 전에는 마냥 무서웠는데 막상 해보니 재미가 더 큰 것 같다. 더 깊게 공부해보고 싶다는 생각도 든다.
'Data Science > TIL (Today I Learned)' 카테고리의 다른 글
| 프로그래머스 데이터분석 데브코스 1기 - 55일차 (0) | 2024.02.09 |
|---|---|
| 프로그래머스 데이터분석 데브코스 1기 - 54일차 (0) | 2024.02.08 |
| 프로그래머스 데이터분석 데브코스 1기 - 52일차 (1) | 2024.02.06 |
| 프로그래머스 데이터분석 데브코스 1기 - 51일차 (0) | 2024.02.05 |
| 프로그래머스 데이터분석 데브코스 1기 - 50일차 (0) | 2024.02.02 |
