본문 바로가기
Study/Machine learning,NLP

머신러닝(8)-실습(2)

by 왕방개 2024. 3. 7.

범주형 데이터 이진 분류

 

1)개요

=>

https://www.kaggle.com/competitions/cat-in-the-dat

 

Categorical Feature Encoding Challenge | Kaggle

 

www.kaggle.com

=>경진대회 이름: 범주형 데이터 이진 분류

=>문제 유형:이진 분류

=>미션은 Target에 속할 확률

=>평가 지표: ROC-AUC

=>데이터

-인위적으로 만든 데이터

-피처와 타겟에 대한 의미를 알 수 없음

-제공되는 데이터는 전부 범주형

bin_:이진 범주

nom_:명목형 범주

ord_:순서형 범주

day와 month은 날짜 피쳐

 

2)데이터 읽어오기

import pandas as pd 
#데이터 읽어봤더니 각 행을 구분하는 id 속성이 존재
#DataFrame을 만들 때 각 행을 구분하는 컬럼이 존재할 경우 index로 설정하는 것이 좋음
train=pd.read_csv('./catdat/train.csv',index_col='id')
test=pd.read_csv('./catdat/test.csv',index_col='id')
submission=pd.read_csv('./catdat/sample_submission.csv',index_col='id')

print(train.info())

=>info 를 확인해보니 id 컬럼 존재 이를 index로 설정

=>train 데이터의 열이 test 데이터의 열보다 1개가 더 많습니다.

 

3)데이터의 탐색적 분석(EDA)

=>타겟의 분포를 확인: 로그 변환을 수행할 지 여부와 층화추출 같은 샘플링을 적용해야하는지 여부

print(train['target'].value_counts())

-층화 추출 을 고려할 정도는 아님 4,5배 이상 되는거 아니면 굳이 안해도됨.

데이터 개수가 많다면 확연히 deeplearning이 우수한 성능을 보임.

 

=>feature를 확인하는 함수 생성

#피처의 정보를 출력해주는 함수
#범주형에서 중요한 정보는 결측값 개수, 고유값 개수

def resumetable(df):
    print('데이터 프레임 구조:',df.shape)

    #각 피처의 자료형 출력
    summary = pd.DataFrame(df.dtypes,columns=['데이터타입'])
    summary = summary.reset_index()
    summary = summary.rename(columns={'index':'피처'})
    summary['결측값 개수']=df.isnull().sum().values
    summary['고유값 개수']=df.nunique().values
    summary['첫번째 값'] = df.loc[0].values
    summary['두번째 값'] = df.loc[1].values

    return summary

resumetable(train)

 

=>순서형 데이터 고유값을 확인

#순서형 feature 에 고유값을 확인

for i in range(3):
    feature = "ord_"+str(i)
    print(f"{feature}고윳값:{train[feature].unique()}")

 

#순서형 feature 에 고유값을 확인

for i in range(3,6):
    feature = "ord_"+str(i)
    print(f"{feature}고윳값:{train[feature].unique()}")

# day 와 month 의 고유값 확인
print('day의 고유값:',train['day'].unique())
print('month의 고유값:',train['month'].unique())

 

=>타겟값(0 과 1)의 분포 시각화

import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline

#타겟 분포 확인
mpl.rc('font', size=15) # 폰트 크기 설정
plt.figure(figsize=(7, 6)) # Figure 크기 설정

ax = sns.countplot(x='target', data=train)
ax.set(title='Target Distribution');

 

=>이진 피처와 타겟의 분포확인

#이진 피쳐(bin_0~bin_4)와 타겟의 분포를 확인
ax = sns.countplot(x='bin_4',hue='target', data=train)

 

범주 값에 따라 타겟의 분포가 유의미하게 차이가 나므로 이진 피처는 분류에 전부 사용

 

 

=>명목형 피처(nom_)와 타겟 확인

#명목형 피처와 타겟을 확인
sns.countplot(x='nom_0',hue='target',data=train)
sns.countplot(x='nom_1',hue='target',data=train)
sns.countplot(x='nom_2',hue='target',data=train)
sns.countplot(x='nom_3',hue='target',data=train)
sns.countplot(x='nom_4',hue='target',data=train)

각 피처들의 값에 따라 유의미한 변화가 감지됨

 

=>순서형 피처(ord_)와 타겟의 분포 확인

 

sns.countplot(x='ord_0',hue='target',data=train)
sns.countplot(x='ord_1',hue='target',data=train)
sns.countplot(x='ord_2',hue='target',data=train)
sns.countplot(x='ord_3',hue='target',data=train)

 

=>순서가 의미를 갖는 범주형 데이터의 순서 설정

#순서가 의미를 갖는 범주형 데이터 순서 설정

from pandas.api.types import CategoricalDtype

ord_1_value = ['Novice','Contributor','Expert','Master','Grandmaster']
ord_2_value = ['Freezing','Cold','Warm','Hot','BoilingHot','Lava Hot']

#범주형 데이터를 하나의 데이터 타입으로 생성
ord_1_dtype = CategoricalDtype(categories =ord_1_value,ordered=True)
ord_2_dtype = CategoricalDtype(categories =ord_2_value,ordered=True)

#반영 - 라벨인코딩할때도 중요함
train['ord_1'] = train['ord_1'].astype(ord_1_dtype)
train['ord_2'] = train['ord_2'].astype(ord_2_dtype)
sns.countplot(x='ord_2',hue='target',data=train)

=>위와 다르게 순서가 정렬되서 나옴

 

=>탐색 결과

-결측치는 없음

-모든 feature 가 target 과 유의미한 차이를 가지므로 제거할 피처를 찾지 못함

 

4)기본모델을 가지고 분류

=>탐색을 마치고 데이터를 다시 불러와야함

import pandas as pd 
#데이터 읽어봤더니 각 행을 구분하는 id 속성이 존재
#DataFrame을 만들 때 각 행을 구분하는 컬럼이 존재할 경우 index로 설정하는 것이 좋음
train=pd.read_csv('./catdat/train.csv',index_col='id')
test=pd.read_csv('./catdat/test.csv',index_col='id')
submission=pd.read_csv('./catdat/sample_submission.csv',index_col='id')

print(train.info())

 

=>데이터 병합

# 훈련데이터와 test 데이터 합쳐서 동일한 구조를 만들기

all_data = pd.concat([train,test])
all_data = all_data.drop(['target'],axis=1)
all_data

 데이터가 전부 범주형이고 문자열 등이 혼합되어 있어서 원 -핫 인코딩을 수행해서 숫자를 변환

 

=>원-핫 인코딩

#sklearn.preprocessing.OneHotEncoder 나 pandas.get_dummies 를 사용

from sklearn.preprocessing import OneHotEncoder

encoder =OneHotEncoder()
all_data_encoded = encoder.fit_transform(all_data)
all_data_encoded

 

=>훈련데이터 와 테스트 데이터를 생성

#훈련데이터와 테스트데이터 생성

num_train  = len(train)
X_train = all_data_encoded[:num_train]
#답안 생성을 위한 데이터 - 새로운 데이터
X_test = all_data_encoded[num_train:]
y = train['target']

from sklearn.model_selection import train_test_split

X_train,X_valid,y_test,y_valid = train_test_split(X_train,y,test_size=0.3,stratify=y,
                                                 random_state=42)

 

=>회귀 모델을 만들어서 후련하고 RoC AUC score 출력

 

#훈련데이터와 테스트데이터 생성

num_train  = len(train)
X_train = all_data_encoded[:num_train]
#답안 생성을 위한 데이터 - 새로운 데이터
X_test = all_data_encoded[num_train:]
y = train['target']

from sklearn.model_selection import train_test_split

X_train,X_valid,y_train,y_valid = train_test_split(X_train,y,test_size=0.3,stratify=y,
                                                 random_state=42)
                                                 
from sklearn.linear_model import LogisticRegression

logistic_model = LogisticRegression(max_iter=1000,random_state=42)
logistic_model.fit(X_train,y_train)

#ROC AUC 출력

y_valid_preds= logistic_model.predict_proba(X_valid)[:,1]

from sklearn.metrics import roc_auc_score

roc_auc = roc_auc_score(y_valid,y_valid_preds)
print(roc_auc)

=>답안 생성

y_preds = logistic_model.predict_proba(X_test)[:,1]

submission['target']=y_preds
submission.to_csv('submission.csv')

=>결론

-성능이 좋은 모델은 아님

 

5)인코딩 방식을 변경하고 스케일링을 수행하고 하이퍼 파라미터 튜닝

=>피처 변경

#이진 피처 중 값이 0 과 1이 아닌 피처의 값을 0과 1로 수정

all_data['bin_3']=all_data['bin_3'].map({'F':0,'T':1})
all_data['bin_4']=all_data['bin_4'].map({'N':0,'Y':1})
#순서형 피처 데이터 변경

ord1dict = {'Novice':0,'Contributor':1,'Expert':2,'Master':3,'Grandmaster':4}
ord2dict = {'Freezing':0,'Cold':1,'Warm':2,'Hot':3,'Boiling Hot':4,'Lava Hot':5}

all_data['ord_1'] = all_data['ord_1'].map(ord1dict)
all_data['ord_2'] = all_data['ord_2'].map(ord2dict)
#순서형 faeture 는 one-hot encoding 이 아닌 label encoder

from sklearn.preprocessing import OrdinalEncoder
encoder = OrdinalEncoder()
ord_345 = ['ord_3','ord_4','ord_5']


all_data[ord_345] = encoder.fit_transform(all_data[ord_345])
#명목형 목록은 이전처럼 원핫 인코딩

nom_features =['nom_'+str(i) for i in range(10)]

onehot_encoder = OneHotEncoder()
encoded_nom_matrix = onehot_encoder.fit_transform(all_data[nom_features])


#명목형 피처는 제거
all_data = all_data.drop(nom_features,axis =1)
date_features  = ['day', 'month'] # 날짜 피처

# 원-핫 인코딩 적용
encoded_date_matrix = onehot_encoder.fit_transform(all_data[date_features])

all_data = all_data.drop(date_features, axis=1) # 기존 날짜 피처 삭제

encoded_date_matrix
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler

ord_features = ['ord_' + str(i) for i in range(6)] # 순서형 피처
# min-max 정규화
all_data[ord_features] = MinMaxScaler().fit_transform(all_data[ord_features])

#all_data[ord_features] = StandardScaler().fit_transform(all_data[ord_features])

from scipy import sparse

# 인코딩 및 스케일링된 피처 합치기
#원핫 인코딩 한 결과가 sparse matrix 라서 희소 행렬을 합치는 API를 사용
all_data_sprs = sparse.hstack([sparse.csr_matrix(all_data),
                               encoded_nom_matrix,
                               encoded_date_matrix],
                              format='csr')

all_data_sprs

 

=>현재 작업

-이진 피처는 숫자 0 과 1 로 생성

- 명목 피처는 원핫인코딩

- 순서형 피처는 순서를 만들어서 번호를 부여하거나 일련번호 형태로 인코딩한 후 스케일링 작업을 수행

 

=>데이터 분할

#ROC - AUC 점수를 확인하기 위해서 훈련 데이터를 다시 모델 훈련시킬 때 사용할 데이터와
#평가를 할 때 사용할 데이터로 분할

X_train, X_valid,y_train,y_valid = train_test_split(X_train,y,
                                                   test_size=0.3,
                                                   random_state=42)

 

=>하이퍼 파라미터 튜닝을 수행해서 최적의 모델 생성

from sklearn.model_selection import GridSearchCV

logistic_model = LogisticRegression()

lr_params = {'C':[0.1 , 0.125, 0.2],
            'max_iter':[800,900,1000],
            'random_state':[42]}

gridsearch_logistic_model = GridSearchCV(estimator = logistic_model,
                                        param_grid = lr_params,
                                        scoring='roc_auc',
                                         cv=5)

gridsearch_logistic_model.fit(X_train,y_train)
y_valid_preds = gridsearch_logistic_model.predict_proba(X_valid)[:,1]
roc_auc=roc_auc_score(y_valid,y_valid_preds)
print(roc_auc)

아까보다 좋은 성능을 보임

 

6)모든 데이터를 가지고 훈련

 

# 훈련 데이터의 개수

num_train = len(train)

#훈련에 사용할 데이터
X_train = all_data_sprs[:num_train]

#답안 제출용 데이터
X_test = all_data_sprs[num_train:]

#훈련에 사용될 데이터
y=train['target']
from sklearn.model_selection import GridSearchCV

logistic_model = LogisticRegression()

lr_params = {'C':[0.1 , 0.125, 0.2],
            'max_iter':[700,800,900,1000],
            'random_state':[42]}

gridsearch_logistic_model = GridSearchCV(estimator = logistic_model,
                                        param_grid = lr_params,
                                        scoring='roc_auc',
                                         cv=5)

gridsearch_logistic_model.fit(X_train,y)
print('최적 하이퍼 파라미터:', gridsearch_logistic_model.best_params_)

submission['target'] = y_preds
submission.to_csv('submission.csv')

 

'Study > Machine learning,NLP' 카테고리의 다른 글

머신러닝(10)-군집  (0) 2024.03.11
머신 러닝(9)-차원 축소  (0) 2024.03.07
머신러닝(7)-실습1  (1) 2024.03.06
머신러닝(6)-Ensemble  (0) 2024.03.05
머신러닝(5) - Regression(2)  (0) 2024.03.05