데이터 표현과 특성 공학

연속형 특성과 범주형 특성

앞에서는 데이터가 연속되는 연속형 특성을 다뤘다. 4장부터는 연속적이지 않는 이산형 특성에 대해서 배운다. 범주형 특성과 연속적인 특성의 차이는 출력이 아닌 입력에 대한 것이다. 범주형 특성은 이산적인 특성이다.

데이터를 어떻게 표현하는가가 머신러닝 모델의 성능에 영향을 주기 때문에 특정 애플리케이션에 가장 적합한 데이터 표현을 찾는 특성 공학(feature engineering)이 필요하다.

범주형 변수

범주형 특성은 어떤 범위가 아닌 고정된 목록 중 하나를 값으로 가지고 정량적이 아니고 정성적인 속성이다. 범주형 특성을 머신러닝 모델에 학습 시킬려고 할 때 특성을 바로 넣을 수 없고 데이터를 다른 방식으로 표현해야한다. 이럴 때 사용하는 방식이 One-Hot-encoding 방법이다.

One-Hot-Encoding

범주형 변수를 표현하는 데 가장 널리 쓰이는 방법이 One-Hot-Encoding이다.
One-hot-encoding은 one out of N encoding 또는 dummy variable로도 불린다.
dummy variable은 범주형 변수를 0 또는 1 값을 가진 하나 이상의 새로운 특성으로 바꾼 것이다. 0과 1로 표현된 범수는 선형 이진 분류 공식에 적용할 수 있어서, 다음과 같이 개수에 상관없이 범주마다 하나의 특성을 표현한 것이다.

머신러닝에서 사용하는 원-핫 인코딩은 통계학에서 사용하는 dummy coding과 비슷하지만 약간 다른 부분이 있다. 간편하게 하려고 각 범주를 각기 다른 이진 특성으로 바꿨다. 통계학에서는 k개의 값을 가진 범주형 특성을 k - 1개의 특성으로 변환하는 게 일반적이다. 이렇게 하면 마지막 범주는 모든 열이 0으로 표현된다. 이렇게 하는 이유는 분석의 편리성과 데이터 행렬의 랭크 부족 현상을 피하기 위해서이다.

  • 랭크 부족 현상
    • 네 개의 범주를 네 개의 특성으로 인코딩하면 맨 마지막 특성은 앞의 세 특성을 참조해서 예측할 수 있다. 이렇게 한 열이 다른 열에 의존적이거나 열의 값이 모두 0인 경우를 열 랭크 부족이라 하고 행렬 분해 방식에 따라 문제가 될 수 있다.

pandas에서는 get_dummies 함수를 사용해서 데이터를 쉽게 인코딩할 수 있다. get_dummies 함수는 객체 타입이나 범주형을 가진 열을 자동으로 변환해준다.

image

data_dummies의 values 속성을 이용해 DataFrame을 Numpy 배열로 바꿀 수 있고 이걸 이용해서 머신러닝 모델을 학습시키면 된다.

  • get_dummies를 이용할 때는 훈련 데이터와 테스트 데이터 포인트를 모두 포함하는 DataFrame을 사용해 get_dummies 함수를 호출하든지, 또는 각각 get_dummies를 호출한 후에 훈련 세트와 테스트 세트의 열 이름을 비교해서 같은 속성인지를 확인해야한다.

숫자로 표현된 범주형 특성

  • 범주형 특성은 종종 숫자로 인코딩된다. 특성의 값이 숫자라고 해서 연속형 특성으로 다뤄야 한다는 의미가 아니다. 숫자로 된 특성이 연속적인지 또는 이산적인지는 항상 명확하지가 않다. 인코딩된 값 사이에 어떤 순서도 없으면 이 특성은 이산적이라고 생각하면 된다.

  • get_dummies 함수는 숫자 특성은 모두 연속형이라고 생각해서 가변수를 만들지 않는다. get_dummies를 사용하면 문자열 특성만 인코딩되고 숫자 특성은 바뀌지 않는다. 숫자 특성도 가변수로 만들고 싶다면 columns 매개변수에 인코딩하고 싶은 열을 명시해야한다. 여기서 숫자를 문자열로 바꾸면 columns 매개변수를 지정하지 않아도 가변수 특성이 만들어진다. 또는 숫자형 특성이더라도 columns 매개변수에 지정하면 가변수가 만들어진다.

Scikit-learn으로 범주형 변수 다루기

scikit-learn에서 원-핫-인코딩은 OneHotEncoder 클래스에 구현되어 있다. OneHotEncoder는 모든 열에 인코딩을 수행한다.

image

sparse=False로 설정하면 OneHotEncode가 희소 행렬이 아니라 넘파이 배열을 반환합니다.
문자열 특성과 정수 특성이 모두 변환되었고 scikit-learn의 출력은 DataFrame이 아니기에 열 이름이 없다. 변환 특성에 해당하는 원본 범주형 변수 이름을 얻으려면 get_feature_names 메서드를 사용한다.

image
처음 세 개의 열은 첫 번째 원본 특성(x0)의 값 0, 1, 2에 해당한다. 마지막 세 개의 열은 두 번째 원본 특성(여기서는 x1)의 값 ‘상자’, ‘여우’, ‘양말’에 해당한다.

하지만 대부분의 애플리케이션에서 일부 특성은 범주형이고 일부는 연속형입니다. OneHotEncoder는 모든 특성을 범주형이라고 가정하기 때문에 바로 적용할 수 없다. 이를 위해서 ColumnTransformer 클래스가 필요하다. 이 클래스는 입력 데이터에 있는 마다 다른 변환을 적용할 수 있다.
연속형 특성과 범주형 특성은 매우 다른 종류의 전처리 과정이 필요하기에 이 클래스가 매우 유용하다.

image

위의 데이터셋에서는 범주형 변수에는 one-hot-encoding을 적용하는 것외에 age와 hours-per-week의 스케일 조정도 해야한다. 이를 위해서는 ColumnTransformer가 필요하다. 각열의 변환은 이름, 변환기 객체, 이 변환이 적용될 열을 지정한다. 열은 열 이름이나 정수 인덱스, 불리언 마스크로 선택할 수 있다. 해당 열에 변환이 적용된 후 반환 결과가 옆으로 나란히 합쳐진다. image

ColumnTransformer 또한 fit, transform 메서드를 사용할 수 있다.

make_column_transformer

ColumnTransformer는 이름을 일일이 지정해야줘야 하기에 번거롭다. 이를 위해서 클래스 이름을 기반으로 자동으로 각 단계에 이름을 붙여주는 makecolumn_transformer가 있다. make_column_transformer도 (변환기객체, 열_리스트)를 전달해주면 된다. image

columnTransformer와 다르게 이름이 없다. ColumnTransformer의 한 가지 단점은 scikit-learn 0.2 기준으로는 아직 변환된 출력 열에 대응하는 입력 열을 찾지 못 한다는 것이다.

구간 분할, 이산화, 선형 모델, 트리 모델

데이터를 가장 잘 표현하는 방법은 데이터가 가진 의미뿐 아니라 어떤 모델을 사용하는지에 따라 다르다.
가장 많이 사용하는 두 알고리즘인 선형 모델과 트리 기반 모델은 특성 표현 방식으로 인해 미치는 영향이 매우 다르다.

image

입력 특성이 하나인 wave 데이터셋을 사용해서 모델을 비교한 결과는 위와 같다. 선형 모델은 선형 관계로만 모델링하기에 특성이 하나일 땐 직성으로 나타난다. 결정 트리는 이 데이터로 훨씬 복잡한 데이터를 만들 수 있다. 하지만 이는 데이터의 표현 형태에 따라 굉장히 달라집니다. 연속형 데이터에 아주 강력한 선형 모델을 만드는 방법 하나는 한 특성을 여러 특성으로 나누는 구간 분할(Binding)이다.

위의 특성의 입력 값 범위가 나뉘어 여러 구간으로, 예를 들면 10개로 되어 있다고 생각해보자. 그럼 각 데이터 포인트가 어떤 구간에 속하는지로 나타낼 수 있다. 구간의 경계를 정의하는 데는 균일한 너비, 데이터의 분위를 사용할 수 있다. KBinsDiscretizer 클래스에는 이런 방법들이 구현되어 있다.

KBinsDiscretizer

image
KBinsDiscretizer는 한 번에 여러 개의 특성에 적용할 수 있다. binedges는 특성별로 경곗값이 저장되어 있다.

tranform 메서드를 사용하면 각 데이터 포인트를 해당되는 구간으로 인코딩할 수 있다. 기본적으로 KBinsDiscretizer는 구간에 원-핫-인코딩을 적용한다. 구간마다 하나의 새로운 특성이 생기므로 희소 행렬을 만든다. 10개의 구간을 지정했기에 변환된 데이터는 10차원이다.
image



image

희소 행렬을 밀집 배열로 변환하고 원본 데이터 포인트와 인코딩 결과를 비교해본 결과이다. -0.753은 네 번째 구간으로 들어갔다. 위의 방식을 이용해서 wave 데이터셋에 있는 연속형 특성을 각 데이터 포인트가 어느 구간에 속했는지 원 핫 인코딩한 범주형 특성으로 변환했다. encode = “ordinal’로 설정하면 one-hot-encoding 구간의 인덱스를 바로 계산할 수 있지만 유용하지않다. encode = ‘onehot-dense’로 지정해서 밀집 배열로 만들면 모든 특성을 바로 출력할 수 있다.

image image

원 핫 인코딩된 데이터로 선형 회귀 모델과 결정 트리 모델을 새로 만들면 위의 그래프처럼 나온다.
선형 회귀 모델과 결정 트리가 같은 예측을 만들어내서 파선과 실선이 완전히 겹쳐진 걸 볼 수 있다.
구간별로 두 개의 모델이 예측한 것은 상숫값이다. 각 구간 안에서는 특성의 값이 상수이기에 어떤 모델이든 그 구간의 포인트에 대해서는 같은 값을 예측할 것이다. 구간으로 나눈 특성을 사용하기 전과 비교해보면, 각 구간에서 다른 값을 가지고 있기에 선형 모델이 훨씬 유연해진 것을 볼 수 있다.
하지만 결정 트리는 덜 유연해졌다. tree 모델은 데이터를 자유롭게 나눠서 학습할 수 있기에 특성의 값을 구간으로 나누는 것이 아무런 득이 되지 않는다.다르게 생각하면 결정 트리는 데이터셋에서 예측을 위한 가장 좋은 구간을 학습한다고 생각할 수 있다.

일부 특성과 출력이 비선형 관계이지만, 용량이 매우 크고 고차원의 데이터셋이라 선형 모델을 사용해야 한다면 구간 분할이 모델 성능을 높이는데 좋은 방법이 된다.

상호작용과 다항식

특성을 풍부하게 나타내는 또 하나의 방법은 원본 데이터에 상호작용(interaction)과 다항식(polynomial)을 추가하는 것이다.

선형 모델은 wave 데이터셋의 각 구간에 대해 상숫값을 학습한다. 선형모델은 이런 절편 외에도 기울기도 학습할 수 있다. 선형 모델에 기울기를 추가하는 방법은 구간으로 분할된 데이터에 원래 특성(x 축)을 다시 추가하는 것이다.
image

위의 모델은 각 구간의 절편과 기울기를 학습한다. 학습된 기울기는 양수이고 모든 구간에 걸쳐 동일하다. 즉 x 축 특성이 하나이므로 기울기도 하나이다. 하지만 기울기가 모든 구간에서 같으니 별로 유익해 보이지 않는다. 오히려 각 구간에서 다른 기울기를 갖는 게 바람직해 보인다. 이를 위해서 데이터 포인트가 있는 구간과 x 축 사이의 상호작용 특성을 추가할 수 있다. 이 특성이 구간 특성과 원본 특성의 곱이다. image 데이터셋은 이제 데이터 포인트가 속한 구간과 이 구간에 원본 특성을 곱한 값을 더해 20개의 특성을 가진다. 이 곱셈 특성을 각 구간에 대한 x축 특성의 복사본이라고 생각할 수 있다. 즉 이 값은 구간 안에서는 원본 특성이고 다른 곳에서는 0이다. (X_binned는 데이터 포인트가 속한 구간의 원-핫-인코딩 이기에 x를 곱하면 해당 구간 이외에는 모두 0이 된다.) 이 데이터를 이용해서 만든 선형 모델의 결과는 아래와 같다.

image
이 모델에서는 각 구간에서 절편과 기울기가 모두 다르다.

구간 나누기는 연속형 특성을 확장하는 방법 중 하나이다. 원본 특성의 다항식을 추가할 수도 있다. image
다항식 특성을 선형 모델과 함께 사용하면 전형적인 다항 회귀 모델이 된다. 다항식 특성은 1차원 데이터셋에서도 매우 부드러운 곡선을 만든다. 하지만 고차원 다항식은 데이터가 부족한 영역에서 너무 민감하게 작동한다.(위의 그래프에서도 그래프의 시작점과 끝점에서 급격하게 내려가거나 상승하는 모습을 볼 수 있다.)

일변량 비선형 변환

log, exp, sin 같은 수학 함수를 적용하는 방법도 특성 변환에 유용하다. 트리 기반 모델은 특성의 순서에만 영향을 받지만 선형 모델과 신경망은 각 특성의 스케일과 분포에 밀접하게 연관되어 있다.
또한 특성과 타깃 값 사이에 비선형성이 있다면 선형 회귀에서는 모델을 만들기가 어렵다. 이때 log, exp 함수는 데이터 스케일을 변경해서 선형 모델과 신경망의 성능을 올리는데 도움을 준다. sin과 cos 함수주기적인 패턴이 들어 있는 데이터를 다룰 때 편리하다.

대부분의 모델은 각 특성이 정규분포와 비슷할 때 최고의 성능을 낸다. 즉 특성의 히스토그램이 종 모양과 비슷할 때이다. log와 exp는 종 모양을 만드는데 쉽고 효과적인 방법이다. 이런 변환이 도움이 되는 전형적인 경우는 정수 카운트 데이터를 다룰 때이다.

데이터셋과 모델의 조합에 최적인 변환 방법을 찾기란 예술에 가까운 일이다. 때때로 회귀에서는 타깃 변수 y를 변환하는 것이 좋을 때가 있다.

앞의 예서도 계속 보았듯이 구간 분할, 다항식, 상호작용은 데이터가 주어진 상황에서 모델의 성능에 큰 영향을 줄 수 있다. 특별히 선형 모델이나 나이브 베이즈 모델 같은 덜 복잡한 모델일 경우이다.
반면에 트리 기반 모델은 스스로 중요한 상호작용을 찾아낼 수 있고 대부분의 경우 데이터를 명시적으로 반환하지 않아도 된다. SVM, KNN, DNN 같은 모델은 구간 분할, 상호작용, 다항식으로 이득을 볼 수 있지만, 선형 모델보다는 영향이 그렇게 뚜렷하지않다.

특성 자동 선택

새로운 특성을 만드는 방법이 많기에 데이터의 차원이 원본 특성의 수 이상으로 증가하기 쉽다. 하지만 특성이 추가되면 모델이 복잡해지고 overfitting의 가능성이 높아진다. 보통은 새로운 특성을 추가할 때나 고차원 데이터셋을 사용할 때 가장 유용한 특성만 선택하고 나머지는 무시해서 특성의 수를 줄이는 것이 좋다.
어떤 특성이 좋은지 아는 방법에는 크게 일변량 통계, 모델 기반 선택, 반복적 선택이 있다. 이 세 가지 방식 모두 지도 학습이기에 target 값이 필요하고, 데이터를 훈련 세트와 테스트 세트로 나눈 다음 훈련 데이터만 특성 선택에 사용해야한다.

일변량 통계

일변량 통계에서는 개개의 특성과 타깃 사이에 중요한 통계적 관계가 있는지를 계산한다. 그다음 깊게 관련되어 있다고 판단되는 특성을 선택한다. 분류에서는 ANOVA(분산분석)이라고도 한다. 이 방법의 핵심 요소는 일변량, 즉 각 특성이 독립적으로 평가된다는 점이다. 그렇기에 다른 특성과 깊게 연관된 특성은 선택되지 않는다. 일변량 분석은 계산이 매우 빠르고 평가를 위해 모델을 만들 필요가 없다. 또한 이 방식은 특성을 선택한 후 적용하려는 모델에 상관없이 사용할 수 있다.

모델 기반 특성 선택

모델 기반 특성 선택은 지도 학습 머신러닝 모델을 사용하여 특성의 중요도를 평가해서 가장 중요한 특성들만 선택한다. 특성 선택에 사용하는 지도 학습 모델은 최종적으로 사용할 지도 학습 모델과 같은 필요는 없고 특성 선택을 위한 모델은 각 특성의 중요도를 측정하여 순서를 매길 수 있어야 한다.
결정 트리와 이를 기반으로 한 모델은 각 특성의 중요도가 담겨 있는 featureimportances 속성을 제공한다. 모델 기반 특성 선택은 한 번에 모든 특성을 고려하기에 상호작용 부분을 반영할 수 있습니다. 모델 기반의 특성 선택은 SelectFromModel로 구현되어 있다. SelectFromModel은 지도 학습 모델로 계산된 중요도가 지정한 임계치보다 큰 모든 특성을 선택한다.

반복적 특성 선택

일변량 분석에서는 모델을 사용하지 않았고, 모델 기반 선택에서는 하나의 모델을 사용해 특성을 선택합니다. 반복적 특성 선택에서는 특성의 수가 각기 다른 일변의 모델이 만들어진다. 기본적으로 두 가지 방법이 있다. 첫 번째는 특성을 하나도 선택하지 않은 상태로 시작해서 종료 조건에 도달할 때까지 하나씩 추가하는 방법. 두 번째는 모든 특성을 가지고 시작해서 어떤 종료 조건이 될 때까지 특성을 하나씩 제거하는 방법. 전진 선택법과 후진 선택법이다. 재귀적 특성 제거는 모든 특성으로 시작해서 모델을 만들고 특성 중요도가 가장 낮은 특성을 제거합니다. 그런 다음 제거한 특성을 빼고 나머지 특성 전체로 새로운 모델을 만든다. 이를 반복해서 미리 정의한 특성 개수가 남을 때까지 계속 반복한다. 이를 위해서는 모델 기반 선택에서처럼 특성 선택에 사용할 모델은 특성의 중요도를 결정하는 방법을 제공해야한다.

마무리

머신러닝 알고리즘에 어떤 입력값을 넣을지 확신이 안 선다면 특성 자동 선택이 도움이 된다. 또 예측 속도를 높이거나 해석하기 더 쉬운 모델을 만드는 데 필요한 만큼 특성의 수를 줄이는 데도 효과적이다.

전문가 지식 활용

시계열 예측을 할 때 랜덤 포레스트는 문제를 가진다. 시간을 예측한다고 했을 때 테스트 세트의 시간 값이 훈련 세트에 있는 특성 값의 범위 밖에 있을 때 문제가 발생한다. 즉 테스트 세트에 있는 데이터 포인트는 훈련 세트에 있는 모든 데이터보다 뒤의 시간이다. 트리 모델인 랜덤 포레스트는 훈련 세트에 있는 특성의 범위 밖으로 extrapolation(외삽)할 수 있는 능력이 없다. 결국 랜덤 포레스트는 테스트 세트와 가장 가까이 있는 마지막 훈련 세트 데이터의 타깃 값을 예측으로 사용하게 된다.

전문가의 지식을 활용해서 중요한 특성을 추가해서 만들어주면 예측할 수 있다!!!!