Post

[사전학습] 3.4 데이터 변환 - 특징 생성

3. 데이터 전처리 이해와 실무

3.1 데이터 변환 : 특징 생성

특징 생성 (Feature Creation)

  • 원본 데이터의 조합/변환 등을 기반하여 새로운 특징들을 구축 및 생성하는 방법
    => 원본 데이터로 특징을 새롭게 생성하여 분석 과정 내 성능과 효율성 확보하고자 함

    목적 및 필요성

  • 품질 확보 : 가공을 거치지 않은 Raw 데이터 활용 기반의 모델링은 품질 확보 어려움
  • 최적화된 형태 변환 : 효과적인 Feature를 확보하는 것이 데이터 분석 내 가장 중요한 과정임

    특징 생성 방안

    1. 범주 인코딩
  • 크게 Nominal(순서가 없는)과 Ordinal(순서가 있는) 형식으로 나뉘는 범주형 변수
  • 숫자가 아닌 범주 변수 값을 숫자로 표현하고 모델링에 적용하기 위한 과정
    1. 결합 및 분해
  • 데이터 셋의 변수들의 조합을 기반으로 새로운 특징을 구축하는 방법
  • 변수 간의 연산 혹은 분해를 통해 새로운 특징을 구축하고 입력 변수로 모델링에 적용
    1. 차원 축소
  • 원본 데이터로부터 새로운 특징의 집합을 생성하는 것
  • 고차원 원시 데이터 셋을 저차원으로 차원 축소하도록 새로운 특징을 생성하는 방식

    1. 범주 인코딩

    범주형 데이터의 알고리즘 적용을 위한 수치형 변환

    One-hot Encoding
  • 순서의 의미를 지니지 않은 범주형 변수를 처리하는 대표적 방법
  • k개의 범주를 지닌 범주형 변수를 k개의 변수로 변환

    2-1. 결합 기반 특징 생성

    변수 간의 결합을 통해 새로운 의미를 지닌 특징을 생성

  • Add / Divide / Subtract / Multiply

    2-2. 분해 기반 특징 생성

    변수의 분해를 통해 새로운 의미를 지닌 특징을 생성

  • 특정 변수 활용 기반의 새로운 의미를 파악할 수 있는 특징을 생성하는 방법
  • 도메인 지식 및 일반적 개념 기반으로 생성 가능 ex) 시간 -> 시간대, 요일 등..

    3. 차원 축소 목적 특징 생성

    3-1. 변수들이 지닌 정보를 최대한 확보하는 저차원 데이터로 생성

    PCA(Principal Component Analysis)
  • 서로 연관된 변수들이 관측되었을 때, 원본 데이터 분산 기반의 특징을 생성
  • 주성분 간의 서로 독립을 이루도록 구성 (상관관계가 없도록 구성) 3-2. 군집 분석 기반의 고차원 데이터를 하나의 특징으로 차원 축소
    Featurization via Clustering
  • 고차원 데이터를 군집 분석을 기반으로 특징의 개수를 하나의 특징(군집 결과)으로 축소
  • 이렇게 획득한 군집 결과 특징을 분류/회귀 등 문제 해결을 위한 입력 변수로 할용(Stacking 방법)
  • 즉, 원본 데이터 내 여러 개의 특징을 하나의 특징으로 축소하여 모델 연산 비용 감소 추구

실습

샘플 데이터 필요

1
2
import numpy as np
import pandas as pd
1
2
data = pd.read_csv("./data/encoding_sample_data.csv", encoding='cp949')
data.head()
1
data['city'].value_counts()

1. OneHot Encoding

1
2
3
4
5
6
# city라는 범주형 변수 one_hot Encoding
# Pandas의 get_dummies 함수를 활용 쉽게 구혀 ㄴ가능

encoding_data = data.copy()
encoding_data = pd.get_dummies(encoding_data, columns=['city'])
encoding_data.head()

2. 결합 및 분해 기반 특징 생성

1
2
3
# 시간대 별 파악 목적
creation_data = data.copy()
creation_data.info()
1
2
3
# date 컬럼을 datetime 형식으로 변환
creation_data['date'] = pd.to_datetime(creation_data['date'])
creation_data.head()
1
creation_data.info()
1
2
3
4
5
6
creation_data['year'] = creation_data['date'].dt.year #연도
creation_data['month'] = creation_data['date'].dt.month #월
creation_data['day'] = creation_data['date'].dt.day #일
creation_data['hour'] = creation_data['date'].dt.hour #시간
creation_data['dayofweek'] = creation_data['date'].dt.dayofweek #요일 (월 = 0)
creation_data.head()
1
2
3
4
# AM PM
creation_data['ampm'] = 'AM'
creation_data.loc[creation_data['hour'] > 12, 'ampm'] = 'PM'
creation_data

3. 차원 축소 기반 특징 생성 (1) : PCA (주성분 분석)

  • 여러 개의 변수를 지닌 고차원 데이터를 저차원으로 변환하도록 주성분들을 생성하는 알고리즘
  • 원 변수들이 지닌 정보를 최대한 확보하는 저차원 데이터로 생성하는 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cancer = pd.read_csv('./data/wdbc.data', header=None)

# 데이터 컬럼명 지정
cancer.columns = [
    "id", "diagnosis", "radius_mean", "texture_mean", "perimeter_mean", "area_mean", "smoothness_mean", "compactness_mean", 
    "concavity_mean", "concave_points_mean", "symmetry_mean", "fractal_dimension_mean", "radius_se", "texture_se",
    "perimeter_se", "texture_worst", "smoothness_se", "compactness_se", "concavity_se", "concave_points_se", "symmetry_se",
    "fractal_dimension_se", "radius_worst", "texture_worst", "perimeter_worst", "area_worst", "smoothness_worst", "compactness_worst", 
    "concavity_worst", "concave_points_worst", "symmetry_worst", "fractal_dimension_worst"
]

# ID를 Index화
cancer = cancer.set_index('id')
cancer
diagnosisradius_meantexture_meanperimeter_meanarea_meansmoothness_meancompactness_meanconcavity_meanconcave_points_meansymmetry_mean...radius_worsttexture_worstperimeter_worstarea_worstsmoothness_worstcompactness_worstconcavity_worstconcave_points_worstsymmetry_worstfractal_dimension_worst
id
842302M17.9910.38122.801001.00.118400.277600.300100.147100.2419...25.38017.33184.602019.00.162200.665600.71190.26540.46010.11890
842517M20.5717.77132.901326.00.084740.078640.086900.070170.1812...24.99023.41158.801956.00.123800.186600.24160.18600.27500.08902
84300903M19.6921.25130.001203.00.109600.159900.197400.127900.2069...23.57025.53152.501709.00.144400.424500.45040.24300.36130.08758
84348301M11.4220.3877.58386.10.142500.283900.241400.105200.2597...14.91026.5098.87567.70.209800.866300.68690.25750.66380.17300
84358402M20.2914.34135.101297.00.100300.132800.198000.104300.1809...22.54016.67152.201575.00.137400.205000.40000.16250.23640.07678
..................................................................
926424M21.5622.39142.001479.00.111000.115900.243900.138900.1726...25.45026.40166.102027.00.141000.211300.41070.22160.20600.07115
926682M20.1328.25131.201261.00.097800.103400.144000.097910.1752...23.69038.25155.001731.00.116600.192200.32150.16280.25720.06637
926954M16.6028.08108.30858.10.084550.102300.092510.053020.1590...18.98034.12126.701124.00.113900.309400.34030.14180.22180.07820
927241M20.6029.33140.101265.00.117800.277000.351400.152000.2397...25.74039.42184.601821.00.165000.868100.93870.26500.40870.12400
92751B7.7624.5447.92181.00.052630.043620.000000.000000.1587...9.45630.3759.16268.60.089960.064440.00000.00000.28710.07039

569 rows × 31 columns

1
2
3
4
5
6
# input 및 Target 구분
input_df = cancer.drop(['diagnosis'], axis=1)
print(np.shape(input_df))

target_df = cancer[['diagnosis']]
print(np.shape(target_df))
1
2
(569, 30)
(569, 1)
1
2
3
4
5
6
7
8
9
# 30개의 독립변수로 이루어진 데이터를 주성분 분석
# 주성분 분석 수행 이전, 각 변수의 스케일이 서로 다르기 때문에 표준화 수행
from sklearn.preprocessing import StandardScaler
std_scaler = StandardScaler()

std_scaler.fit(input_df)
input_scaled = std_scaler.transform(input_df)

input_scaled
1
2
3
4
5
6
7
8
9
10
11
12
13
array([[ 1.09706398, -2.07333501,  1.26993369, ...,  2.29607613,
         2.75062224,  1.93701461],
       [ 1.82982061, -0.35363241,  1.68595471, ...,  1.0870843 ,
        -0.24388967,  0.28118999],
       [ 1.57988811,  0.45618695,  1.56650313, ...,  1.95500035,
         1.152255  ,  0.20139121],
       ...,
       [ 0.70228425,  2.0455738 ,  0.67267578, ...,  0.41406869,
        -1.10454895, -0.31840916],
       [ 1.83834103,  2.33645719,  1.98252415, ...,  2.28998549,
         1.91908301,  2.21963528],
       [-1.80840125,  1.22179204, -1.81438851, ..., -1.74506282,
        -0.04813821, -0.75120669]])
1
2
3
4
5
6
7
8
9
# 주성분 분석 수행
from sklearn.decomposition import PCA

# 두 개 주성분만 유지시키도록 수행
# 30개 변수의 데이터를 2개의 주성분으로 남도록 변환
pca = PCA(n_components=2)
pca.fit(input_scaled)
X_pca = pca.transform(input_scaled)
X_pca
1
2
3
4
5
6
7
array([[ 9.19283683,  1.94858307],
       [ 2.3878018 , -3.76817174],
       [ 5.73389628, -1.0751738 ],
       ...,
       [ 1.25617928, -1.90229671],
       [10.37479406,  1.67201011],
       [-5.4752433 , -0.67063679]])
1
2
3
# PCA 수행된 input 데이터 확인
X_pca_df = pd.DataFrame(X_pca, columns=['pc1', 'pc2'])
X_pca_df
pc1pc2
09.1928371.948583
12.387802-3.768172
25.733896-1.075174
37.12295310.275589
43.935302-1.948072
.........
5646.439315-3.576817
5653.793382-3.584048
5661.256179-1.902297
56710.3747941.672010
568-5.475243-0.670637

569 rows × 2 columns

  • 30개의 변수를 지닌 데이터가 2개의 특징들로 압축되었음
1
2
import matplotlib.pyplot as plt
import seaborn as sns
1
2
# 산점도로 2개의 주성분을 시각화
ax = sns.scatterplot(x='pc1', y='pc2', data=X_pca_df)

png

1
2
3
4
5
# Target과 확인을 위해 주성분 분석을 수행한 Input 데이터와 기존 Target 데이터를 Merge
target_df = target_df.reset_index()
pca_df = pd.merge(X_pca_df, target_df, left_index=True, right_index=True, how='inner')
pca_df = pca_df[['pc1', 'pc2', 'diagnosis']]
pca_df
pc1pc2diagnosis
09.1928371.948583M
12.387802-3.768172M
25.733896-1.075174M
37.12295310.275589M
43.935302-1.948072M
............
5646.439315-3.576817M
5653.793382-3.584048M
5661.256179-1.902297M
56710.3747941.672010M
568-5.475243-0.670637B

569 rows × 3 columns

1
2
# 클래스를 색깔로 구분하여 처음 두개의 주성분으로 Target과 비교
ax = sns.scatterplot(x='pc1', y='pc2', hue='diagnosis', data=pca_df, palette=['green', 'red'])

png

  • 실제 모델링에 적용하기 위해 효율적으로 활용 가능한 주성분 분석
  • 특히, record 및 컬럼이 많은 경우 모델링 연산비용이 많이 들게 되므로 효율적인 차원 축소 기반의 특징을 생성하는 것이 분석 과정 내 필요한 과정

  • 주성분을 선택하는 다른 방안
  • 유지시킬 주성분 개수가 아닌 분산의 설명가능 수준을 비율로 선택 가능
    • pca = PCA(n_components=0.8):
    • 주성분의 수는 전체 분산의 최소 80% 수준에서 자동으로 선택
  • 이를 통해 수치를 변경하면서 추출되는 주성분의 수 확인 가능하며, 이는 분산에 기초한 주성분 개수를 선택하는 부분에서 얼마나 많은 주성분을 사용할 것인지 확인해야 할 때 사용 가능
1
2
3
4
5
6
# 전체 분산의 최소 80% 수준에서 설명하는 수준의 주성분 확보
pca = PCA(n_components=0.8)
pca.fit(input_scaled)
X_pca = pca.transform(input_scaled)
X_pca_df = pd.DataFrame(X_pca)
X_pca_df
01234
09.1928371.948583-1.1231663.633731-1.195110
12.387802-3.768172-0.5292931.1182640.621775
25.733896-1.075174-0.5517480.912083-0.177086
37.12295310.275589-3.2327900.152547-2.960878
43.935302-1.9480721.3897672.9406390.546747
..................
5646.439315-3.5768172.4594871.177314-0.074824
5653.793382-3.5840482.088476-2.506028-0.510723
5661.256179-1.9022970.562731-2.0892271.809991
56710.3747941.672010-1.877029-2.356031-0.033742
568-5.475243-0.6706371.490443-2.299157-0.184703

569 rows × 5 columns

3. 차원 축소 기반 특징 생성 (2) : clustering (군집 분석)

  • 여러 개의 변수를 하나의 변수(군집결과)로 변환 차원 축소
1
from sklearn.cluster import KMeans
1
2
3
# 일부 변수만 선택 (30개 변수 중 15개의 변수만 임의로 선정)
subset_df = input_df.iloc[:, 0:15]
subset_df
radius_meantexture_meanperimeter_meanarea_meansmoothness_meancompactness_meanconcavity_meanconcave_points_meansymmetry_meanfractal_dimension_meanradius_setexture_seperimeter_setexture_worstsmoothness_se
id
84230217.9910.38122.801001.00.118400.277600.300100.147100.24190.078711.09500.90538.589153.400.006399
84251720.5717.77132.901326.00.084740.078640.086900.070170.18120.056670.54350.73393.39874.080.005225
8430090319.6921.25130.001203.00.109600.159900.197400.127900.20690.059990.74560.78694.58594.030.006150
8434830111.4220.3877.58386.10.142500.283900.241400.105200.25970.097440.49561.15603.44527.230.009110
8435840220.2914.34135.101297.00.100300.132800.198000.104300.18090.058830.75720.78135.43894.440.011490
................................................
92642421.5622.39142.001479.00.111000.115900.243900.138900.17260.056231.17601.25607.673158.700.010300
92668220.1328.25131.201261.00.097800.103400.144000.097910.17520.055330.76552.46305.20399.040.005769
92695416.6028.08108.30858.10.084550.102300.092510.053020.15900.056480.45641.07503.42548.550.005903
92724120.6029.33140.101265.00.117800.277000.351400.152000.23970.070160.72601.59505.77286.220.006522
927517.7624.5447.92181.00.052630.043620.000000.000000.15870.058840.38571.42802.54819.150.007189

569 rows × 15 columns

1
2
3
std_scaler.fit(subset_df)
subset_input_scaled = std_scaler.transform(subset_df)
subset_input_scaled
1
2
3
4
5
6
7
8
9
10
11
12
13
array([[ 1.09706398, -2.07333501,  1.26993369, ...,  2.83303087,
         2.48757756, -0.21400165],
       [ 1.82982061, -0.35363241,  1.68595471, ...,  0.26332697,
         0.74240195, -0.60535085],
       [ 1.57988811,  0.45618695,  1.56650313, ...,  0.8509283 ,
         1.18133606, -0.29700501],
       ...,
       [ 0.70228425,  2.0455738 ,  0.67267578, ...,  0.27669279,
         0.1806983 , -0.37934168],
       [ 1.83834103,  2.33645719,  1.98252415, ...,  1.43852964,
         1.0095027 , -0.17299998],
       [-1.80840125,  1.22179204, -1.81438851, ..., -0.15744905,
        -0.46615196,  0.04934236]])
1
2
3
4
# K-means 클러스터링 활용
# 군집 Label 수 설정
k = 5
model = KMeans(n_clusters=k, random_state=10)
1
2
3
model.fit(subset_input_scaled)

target_df['cluster'] = model.fit_predict(subset_input_scaled)
1
2
3
4
c:\Users\zxwlg\miniconda3\envs\dicom\lib\site-packages\sklearn\cluster\_kmeans.py:1334: UserWarning: KMeans is known to have a memory leak on Windows with MKL, when there are less chunks than available threads. You can avoid it by setting the environment variable OMP_NUM_THREADS=3.
  warnings.warn(
c:\Users\zxwlg\miniconda3\envs\dicom\lib\site-packages\sklearn\cluster\_kmeans.py:1334: UserWarning: KMeans is known to have a memory leak on Windows with MKL, when there are less chunks than available threads. You can avoid it by setting the environment variable OMP_NUM_THREADS=3.
  warnings.warn(
1
target_df
indexiddiagnosiscluster
00842302M0
11842517M2
2284300903M2
3384348301M4
4484358402M2
...............
564564926424M0
565565926682M2
566566926954M2
567567927241M0
56856892751B3

569 rows × 4 columns

1
pd.crosstab(target_df.diagnosis, target_df.cluster)
cluster01234
diagnosis
B0111022917
M365932652
  • 임의의 15개 변수만을 활용한 하나의 특징(군집 결과)이 Target 구분에 효과적일 것임을 예측 가능함
  • 이처럼 많은 변수를 하나의 특징으로 구성하고, 입력 데이터의 차원을 줄인다면 모델 연산 비용 절감에 효과적
This post is licensed under CC BY 4.0 by the author.

[사전학습] 3.3 데이터 변환 - 구간화 정규화

[사전학습] 3.5 데이터 축소 - 특징 선택