Home Project

Data Analyst's Home Project

[Legacy] Data/[Legacy] Machine Learning

feature engineering 특성공학(원핫인코딩, get_dummies, RFE)

Haeon 2019. 2. 13. 17:46
728x90


데이터의 종류에는 연속형 특성, 범주형 특성, 이산형 특성이 있다. 연속형 특성의 예로는 주가변동, 몸무게 변화 등이 있고, 범주형 특성의 예로는 성별, 인종, 혈액형 등이 있다. 범주형 특성 간은 연속된 값으로 나타나지는 않는다. 흑인과 동양인 사이에는 중간값이 없고 이 카테고리들 사이에는 순서가 없다.


특정 애플리케이션에 가장 적합한 데이터 표현을 찾는 것을 feature engineering이라고 한다.


타이타닉 데이터셋을 예로 들겠다.



1. 범주형 변수 (Categorical features)

연속형 feature : age, 

범주형 feature : Pclass, Name, Sex, Embarked


(1) 원 핫 인코딩 (가변수)


가변수는 범주형 변수를 0 또는 1 값을 가지는 새로운 feature로 바꾼 것이다. 0과 1로 표현된 변수는 선형 이진 분류 공식(그리고 scikit-learn에 있는 다른 모든 모델에) 적용할 수 있어서, 다음과 같이 개수에 상관 없이 범주마다 하나의 특성으로 표현한다.


Embarked 특성에 'S', 'Q', 'C'란 값이 있다. 이 네 가지 값을 인코딩하기 위해 세 개의 새로운 특성 'Embarked_S', 'Embarked_Q', 'Embarked_C'를 만든다. 어떤 사람의 Embarked 값에 해당하는 특성은 1이 되고 나머지 features는 0이 된다. 


pandas나 사이킷런을 이용하여 범주형 변수를 원-핫 인코딩으로 변환할 수 있다.


data_dummies = pd.get_dummies(data)

ex)

df = pd.get_dummies(data=df, columns=['Embarked'], prefix='Em')


get_dummies()는 객체타입(문자열)이나 범주형(categorical)을 가진 열을 자동으로 변환한다.

data_dummies의 values 속성을 이용해 DataFrame을 Numpy배열로 바꿀 수 있으며, 이렇게 바꾼 것을 머신러닝 모델에 학습시키면 된다.


* 참고!

pandas에서 열 인덱싱은 범위 끝도 포함한다(파이썬의 인덱싱과 달리).

data.loc[:, 'Ticket' : 'Embarked']   

-->  Ticket에서 Embarked열까지

이와 달리, Numpy의 슬라이싱은 마지막 범위를 포함하지 않는다.



*** 타이타닉 셋에서 'Name'컬럼의 경우

Mr, Mrs, Miss, Ms 등으로 분할하여 변경한 후, 사이킷런의 LabelEncoder로 인코딩해주면 편함.

LabelEncoder로 인코딩하면, 기존 컬럼에 변환된 value로 변화할 수 있음.

ex)

from sklearn.preprocessing import LabelEncoder

encoder = LabelEncoder()

train['Name'] = encoder.fit_transform(train['Name'])

test['Name'] = encoder.transform(test['Name'])





(2) 숫자로 표현된 범주형 특성


범주형 변수가 문자열로 되어있다면 변수가 범주형이란 것을 확실히 알 수 있다.

그러나, 저장 공간 절약 등의 이유로 범주형 변수가 숫자로 되어있는 경우가 많다. 특성의 값이 숫자라고 해서 연속형 특성으로 다뤄야하는게 아니다. 숫자로 된 특성이 연속적인지 또는 이산적인지(그리고 원-핫 인코딩 된 것인지)는 항상 명확하지는 않다. 인코딩 된 값 사이에 어떤 순서도 없으면, 이 특성은 <이산적>이라고 생각해야 한다.


pandas의 get_dummies()는 숫자 특성은 모두 연속형이라고 생각해서 -> 가변수를 만들지 않는다.

(가변수란, 범주형 변수를 0또는 1값을 가진 하나 이상의 새로운 특성으로 바꾼 것)

대신 어떤 열이 연속형인지 범주형인지를 지정할 수 있는 scikit-learn의 OneHotEncoder를 사용할 수 있고, DataFrame에 있는 숫자로 된 열을 문자열로 바꿀수도 있다.



<사이킷런의 OneHotEncoder>

OneHotEncoder는 숫자로 된 범주형 값을 원-핫 벡터로 바꿔준다. (현재는 숫자로된 범주형 변수에만 적용가능)


from sklearn.preprocessing import OneHotEncoder

encoder = OneHotEncoder(sparse=False)

encoder.fit(data)  # data에 나타난 유일한 값을 찾는다.

X_binned = encoder.transform(data)  # 원-핫-인코딩으로 변환



OneHotEncoder결과는 메모리 절약을 위해 스파스 행렬(Sparse matrix) 형식으로 출력된다.

일반적인 배열로 바꾸려면 toarray 메서드 사용.






2. 특성 자동선택


feature가 추가되면 모델은 더 복잡해지고 과대적합 될 가능성이 높아진다.

따라서, 가장 유용한 특성만 선택하고 나머지는 무시해서 특성의 수를 줄이는 것이 좋다.

어떤 특성이 좋은지 어떻게 알 수 있을까?

- 모델기반 선택, 반복적 선택  :  셋 다 모두 지도학습이므로 target이 필요하다. 또한, 데이터를 훈련 세트와 테스트 세트로 분할한 다음 훈련 데이터만 특성 선택에 사용해야 한다.


(1) 모델기반 feature 선택

지도학습 모델을 통해 특성의 중요도를 평가하고 그 중 가장 중요한 특성들만 선택한다.

특성 선택에 사용되는 지도학습 모델은 최종적으로 학습에 사용할 지도학습 모델과 같지 않아도 된다.

결정 트리이를 기반으로 한 모델은 feature_importances_속성을 제공한다. 

(선형모델도 가능)

모델기반 특성선택은 사이킷런의 SelectFromModel을 통해 구현할 수 있다.


SelectFromModel은 feature의 importance가 지정한 임계치보다 큰 모든 특성을 선택한다.

(관련 매개변수를 threshold라고 하는데, default는 'mean'이다.)

타이타닉 데이터셋을 통해 확인해보겠다. 문자로 구성된 컬럼은 편의를 위해 모두 버린 상태로 진행한다.




randomforest 모델로 특성의 중요도를 평가했습니다.

test데이터에 대해선 fit하지 않습니다. 

최종 성능평가는 DecisionTree로 해보겠습니다.

성능이 별로 좋지 않은데, 그 이유는 타이타닉 데이터셋에서 유의미한 feature들을 편의상 drop했기 때문이다.

실제 타이타닉 셋에서 'Embarked' 와 'Sex' 컬럼은 굉장히 중요한 데이터이다. 이를 빼고 진행했으므로 정확도가 떨어진다. 일반적으로는 특성선택을 하는 것이 하지 않고 학습시키는 것보다 성능이 조금 더 좋다고 한다.



(2) 반복적 특성선택

feature 수가 가기 다른 일련의 모델이 만들어진다. 이에 대한 두 가지 strategy는

① 특성을 하나도 선택하지 않은 상태로 시작하여 어떤 종료 조건에 도달할 때까지 하나씩 추가

② 모든 특성을 가지고 시작하여 어떤 종료 조건이 될 때까지 특성을 하나씩 제거하는 방법


RFE (Recursive feature elimination) - 재귀적 특성 제거

모든 특성으로 시작하여 모델을 만들고, feature importances가 가장 낮은 특성을 제거하는 두 번째 방식이다.

제거한 feature는 제외하고 나머지 feature 전체로 새로운 모델을 만든다. 지정한 특성개수가 남을 때까지 이 과정을 반복한다. 모델 기반 특성선택에서 특성 중요도를 평가할 지도학습 모델을 정했던 것처럼 여기에서도 모델을 지정해야 한다.

RFE에서 중요한 매개변수는 n_features_to_select 이다. 이는 특성개수를 지정하는 매개변수이다.

사이킷런의 유방암 데이터셋으로 구현해본다.




 (참고: introduction to machine learning with python)




반응형
LIST