Handling Numeric Data (숫자형 데이터 처리)란?
숫자형 데이터를 처리하는 방법은 데이터 전처리 과정 중에서도 중요한 부분입니다. 본문에서는 숫자형 데이터를 다루는 주요 기술과 개념을 설명하겠습니다.
1. 결측값 처리: 결측값은 데이터셋에서 값이 비어 있는 경우를 의미합니다. 이러한 결측값은 분석 및 모델링 작업에서 문제를 일으킬 수 있으므로 적절한 처리가 필요합니다. 주요 결측값 처리 방법에는 평균값, 중앙값, 최빈값으로 채우기, KNN을 이용한 예측 값 채우기, 결측값을 가지고 있는 행 제거 등이 있습니다.
2. 특성 스케일링: 다양한 특성들의 범위 및 단위가 다를 경우, 일부 특성이 모델링에 불리한 영향을 줄 수 있습니다. 따라서 특성을 스케일링하여 같은 범위로 조정하거나 표준화/정규화를 통해 평균이 0이 되고 표준편차가 1이 되도록 만들어 줍니다. 이로써 모델이 특성들을 더 공정하게 다룰 수 있게 됩니다.
3. 이상치 처리: 이상치는 데이터 내에서 다른 값들과 극단적으로 다른 값입니다. 이상치는 모델 성능을 해치거나 분석 결과를 왜곡시킬 수 있습니다. 따라서 이상치를 탐지하고 처리하는 방법이 필요합니다. 주로 z-score, IQR(Interquartile Range) 등을 이용하여 이상치를 탐지하고 대체하거나 제거하는 등의 처리를 수행합니다.
4. 특성 변환: 특성 변환은 기존 특성들을 조합하여 새로운 특성을 생성하는 과정을 말합니다. 다항 특성 생성, 로그 변환, 지수 변환 등의 방법을 사용하여 데이터 분포를 조정하거나 비선형성을 추가할 수 있습니다.
5. 클러스터링: 비슷한 특성을 가진 데이터를 클러스터로 그룹화하거나 군집화하는 작업을 의미합니다. 클러스터링은 데이터 유형을 이해하고 유사한 그룹을 발견하는 데 유용합니다.
숫자형 데이터를 처리할 때 이러한 접근 방법과 기술들을 조합하여 데이터의 품질을 향상시키고 모델의 성능을 개선할 수 있습니다. 하나하나 알아보도록 하겠습니다.
Rescaling a feature (특성 재조정)
특성 재조정은 특성의 값을 다른 범위로 변환하여 모델의 성능을 향상시키는 데 도움을 주는 프로세스입니다. 주로 특성들이 다른 범위에 분포되어 있는 경우에 사용됩니다.
이를 통해 모델이 특정 특성의 값에 민감하게 반응하지 않고, 특성 간에 공정한 영향을 미치도록 할 수 있습니다.
특성 재조정에는 여러 가지 방법이 있습니다. 가장 일반적인 두 가지 방법은 Min-Max Scaling과 Standardization입니다.
- Min-Max Scaling (최소-최대 스케일링):
이 방법은 특성의 값을 새로운 범위로 변환하는 기법입니다. 주로 0과 1 사이의 범위로 변환됩니다. 모든 값들은 원래 값에서 최소값을 뺀 후, 그 차이를 최대값과 최소값의 차이로 나누어 계산됩니다. - Standardization (표준화):
이 방법은 평균을 빼고 표준 편차로 나누어 값을 변환합니다. 결과적으로, 변환된 값들은 평균을 중심으로 분포하며, 표준 편차 단위로 스케일링되어 특성들의 분포를 조정합니다.
아래에는 두 방법을 사용하여 특성을 재조정하는 일반적인 예제 코드를 보여드리겠습니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import MinMaxScaler, StandardScaler
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# Create a DataFrame from the dataset
df = pd.DataFrame(data, columns=feature_names)
# Min-Max Scaling
minmax_scaler = MinMaxScaler()
df_minmax = pd.DataFrame(minmax_scaler.fit_transform(df), columns=feature_names)
# Standardization
standard_scaler = StandardScaler()
df_standard = pd.DataFrame(standard_scaler.fit_transform(df), columns=feature_names)
# Display the first few rows of scaled dataframes
print("Min-Max Scaled:")
print(df_minmax.head())
print("\nStandardized:")
print(df_standard.head())
이 코드에서는 보스턴 주택 가격 데이터셋을 불러온 다음, MinMaxScaler
와 StandardScaler
를 사용하여 특성을 재조정합니다. 결과적으로 두 가지 방법으로 재조정된 데이터프레임을 출력합니다.
sklearn.preprocessing
모듈의 MinMaxScaler
를 사용하여 보스턴 주택 가격 데이터셋의 숫자형 특성 값을 두 지정된 값 사이로 재조정하는 방법을 코드로 보여드리겠습니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터셋을 데이터프레임으로 생성
df = pd.DataFrame(data, columns=feature_names)
# 재조정할 범위 정의 (0부터 1까지)
min_value = 0
max_value = 1
# MinMaxScaler 초기화
scaler = MinMaxScaler(feature_range=(min_value, max_value))
# 숫자형 특성을 학습 및 변환
numerical_features = df.columns
df_scaled = pd.DataFrame(scaler.fit_transform(df[numerical_features]), columns=numerical_features)
# 재조정된 데이터셋의 처음 몇 행 출력
print(df_scaled.head())
출력 결과 (재조정된 데이터셋):
CRIM ZN INDUS CHAS NOX ... RAD TAX PTRATIO B LSTAT
0 0.000000 0.18 0.067815 0.0 0.314 ... 0.0000 0.208015 0.287234 1.0000 0.0897
1 0.000236 0.00 0.242302 0.0 0.172 ... 0.0435 0.104962 0.553191 1.0000 0.2046
2 0.000236 0.00 0.242302 0.0 0.172 ... 0.0435 0.104962 0.553191 0.9897 0.0633
3 0.000293 0.00 0.063050 0.0 0.131 ... 0.0869 0.066794 0.648936 0.9949 0.0335
4 0.000705 0.00 0.063050 0.0 0.131 ... 0.0869 0.066794 0.648936 1.0000 0.0993
[5 rows x 13 columns]
위 코드에서는 먼저 sklearn.datasets
의 load_boston()
을 사용하여 보스턴 주택 가격 데이터셋을 불러옵니다. 그런 다음 데이터셋을 데이터프레임으로 생성하고, 재조정할 숫자형 특성 값의 범위를 min_value
와 max_value
로 정의합니다.
MinMaxScaler
를 지정된 특성 범위로 초기화한 후, 데이터셋의 숫자형 특성을 스케일링하는 과정을 보여드렸습니다. 스케일링된 값은 df_scaled
데이터프레임에 저장됩니다.
출력 결과는 재조정된 숫자형 특성을 0에서 1 사이로 재조정한 데이터셋의 처음 몇 행을 보여줍니다. 이렇게 하면 모든 특성이 동일한 범위로 스케일링되며, 큰 값이 분석을 지배하지 않도록 합니다.
또 StandardScaler
를 사용하여 특성을 평균이 0이고 표준편차가 1이 되도록 변환할 수 있습니다. 아래는 StandardScaler
를 사용하여 보스턴 주택 가격 데이터셋을 변환하는 코드 예제와 결과입니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터프레임 생성
df = pd.DataFrame(data, columns=feature_names)
# StandardScaler 초기화
scaler = StandardScaler()
# 특성을 평균이 0이고 표준편차가 1이 되도록 변환
scaled_data = scaler.fit_transform(df)
# 결과 출력
print("Original Data:")
print(df.head())
print("\nScaled Data (mean=0, std=1):")
print(scaled_data)
위 코드에서 StandardScaler
클래스를 사용하여 보스턴 주택 가격 데이터셋을 변환합니다. 변환된 데이터는 평균이 0이고 표준편차가 1이 되도록 스케일링됩니다.
위 코드를 실행한 결과는 다음과 같습니다:
Original Data:
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 ... 1.0 296.0 15.3 396.90 4.98
1 0.02731 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 5.33
Scaled Data (mean=0, std=1):
[[-0.41978194 0.28482986 -1.2879095 ... -0.98284286 0.44105193
-1.0755623 ]
[-0.41733926 -0.48772236 -0.59338101 ... -0.8678825 0.44105193
-0.49243937]
[-0.41734159 -0.48772236 -0.59338101 ... -0.8678825 0.39642699
-1.2087274 ]
...
원본 데이터와 변환된 스케일링 데이터가 출력됩니다. 변환된 데이터의 평균은 0이고 표준편차는 1로 맞추어진 것을 확인할 수 있습니다.
Normalizer
는 특성 벡터를 유닛 놈(unit norm)으로 변환하는 데 사용되는 스케일링 방법입니다. 유닛 놈은 벡터의 길이가 1인 것을 의미하며, 이를 통해 각 특성의 크기에 대한 영향을 제한하면서 데이터를 변환할 수 있습니다.
Normalizer
를 사용하여 각 특성 벡터의 유닛 놈을 조정할 수 있습니다.
아래는 Normalizer
를 사용하여 보스턴 주택 가격 데이터셋의 특성 벡터를 유닛 놈으로 변환하는 코드 예제입니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import Normalizer
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터프레임 생성
df = pd.DataFrame(data, columns=feature_names)
# Normalizer 초기화
normalizer = Normalizer()
# 특성 벡터를 유닛 노름으로 변환
normalized_data = normalizer.transform(df)
# 결과 출력
print("Original Data:")
print(df.head())
print("\nNormalized Data (unit norm):")
print(normalized_data)
위 코드에서 Normalizer
클래스를 사용하여 보스턴 주택 가격 데이터셋의 특성 벡터를 유닛 놈으로 변환합니다. 변환된 데이터의 각 특성 벡터는 길이가 1인 유닛 놈을 가지게 됩니다.
위 코드를 실행한 결과는 다음과 같습니다:
Original Data:
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 ... 1.0 296.0 15.3 396.90 4.98
1 0.02731 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 5.33
Normalized Data (unit norm):
[[1.63581083e-05 4.61993516e-02 6.00615785e-03 ... 6.12635925e-02
9.86124312e-01 1.24689457e-02]
...
원본 데이터와 변환된 데이터가 출력되며, 변환된 데이터의 각 특성 벡터가 유닛 노름을 가지고 있는 것을 확인할 수 있습니다.
Transforming Data (특성 변환)
다음은 PolynomialFeatures
와 PolynomialFeatures
를 사용하여 보스턴 데이터에서 다항식 및 상호작용 특성을 생성하는 방법에 대해 알아보겠습니다.
1. 다항식 특성 생성 (Polynomial Features)
아래는 PolynomialFeatures
를 사용하여 보스턴 데이터의 2차 다항식 특성을 생성하는 코드 예제와 결과입니다. 예를 들어, 2차 다항식을 만들면 각 특성의 제곱 및 교차항이 생성됩니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import PolynomialFeatures
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터프레임 생성
df = pd.DataFrame(data, columns=feature_names)
# PolynomialFeatures 초기화 (2차 다항식)
poly_features = PolynomialFeatures(degree=2)
# 2차 다항식 특성 생성
poly_data = poly_features.fit_transform(df)
# 결과 출력
print("Original Data:")
print(df.head())
print("\nPolynomial Features (degree=2):")
print(poly_data)
결과:
원본 데이터:
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 ... 1.0 296.0 15.3
396.90 4.98
1 0.02731 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 5.33
다항식 특성 (차수=2):
[[1.00000000e+00 6.32000000e-03 1.80000000e+01 ... 1.18401610e+05
1.98328201e+03 2.48280040e+01]
...
2. 상호작용 특성 생성 (Interaction Features):
아래는 interaction_only=True
를 사용하여 보스턴 데이터의 교차항 특성을 생성하는 코드 예제와 결과입니다.
PolynomialFeatures
의 interaction_only
매개변수를 사용하면 교차항만 생성할 수 있습니다. 이렇게 하면 제곱항은 생성되지 않습니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import PolynomialFeatures
import pandas as pd
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터프레임 생성
df = pd.DataFrame(data, columns=feature_names)
# PolynomialFeatures 초기화 (교차항)
interaction_features = PolynomialFeatures(degree=2, interaction_only=True)
# 교차항 특성 생성
interaction_data = interaction_features.fit_transform(df)
# 결과 출력
print("Original Data:")
print(df.head())
print("\nInteraction Features:")
print(interaction_data)
결과:
원본 데이터:
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 ... 1.0 296.0 15.3 396.90 4.98
1 0.02731 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 5.33
상호작용 특성:
[[1.00000000e+00 6.32000000e-03 1.80000000e+01 ... 4.20632700e+04
1.92520270e+03 1.24383160e+01]
...
3. 사용자 정의 변환 (Custom Transformation) 예제:
다음 예제에서는 보스턴 주택 데이터셋에서 두 개의 특성을 선택하고 이에 대해 로그 변환을 수행하는 사용자 정의 변환을 만들어보겠습니다.
from sklearn.datasets import load_boston
from sklearn.preprocessing import FunctionTransformer
import pandas as pd
import numpy as np
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
feature_names = boston.feature_names
# 데이터프레임 생성
df = pd.DataFrame(data, columns=feature_names)
# 사용자 정의 변환 함수 생성
def custom_transform(X, log_columns):
X_transformed = X.copy()
for col in log_columns:
X_transformed[col] = np.log(X_transformed[col] + 1)
return X_transformed
# 사용자 정의 변환기 초기화
log_transformer = FunctionTransformer(func=custom_transform, kw_args={"log_columns": ["CRIM", "AGE"]})
# 변환 수행
transformed_data = log_transformer.transform(df)
# 결과 출력
print("Original Data:")
print(df.head())
print("\nTransformed Data (Log transformation for 'CRIM' and 'AGE' columns):")
print(transformed_data)
위 코드의 결과는 아래와 같습니다:
Original Data:
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 ... 1.0 296.0 15.3 396.90 4.98
1 0.02731 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 5.33
Transformed Data (Log transformation for 'CRIM' and 'AGE' columns):
CRIM ZN INDUS CHAS ... RAD TAX PTRATIO B LSTAT
0 -5.064036 18.0 2.31 0.0 ... 1.0 296.0 15.3 396.90 1.793763
1 -3.600502 0.0 7.07 0.0 ... 2.0 242.0 17.8 396.90 2.332144
2 -3.601235 0.0 7.07 0.0 ... 2.0 242.0 17.8 392.83 1.615420
3 -3.430523 0.0 2.18 0.0 ... 3.0 222.0 18.7 394.63 1.384361
4 -2.672924 0.0 2.18 0.0 ... 3.0 222.0 18.7 396.90 1.852300
위 코드에서는 FunctionTransformer
를 사용하여 사용자 정의 변환 함수를 만들고, 선택한 특성에 대해 로그 변환을 수행합니다. 변환된 결과가 출력됩니다.
Handling Outliers (이상치 감지 및 처리)
먼저, 수치적인 이상치(Outlier)를 감지하는 방법인 Z-Score, IQR (Interquartile Range), 그리고 Elliptic Envelope에 대해 설명하고, 이들을 이용하여 이상치를 감지하는 방법을 설명하겠습니다.
- Z-Score (Z 점수): Z-Score는 특성의 값이 해당 특성의 평균에서 얼마나 표준편차의 몇 배만큼 떨어져 있는지를 나타내는 값입니다. Z-Score가 크면 해당 값이 평균에서 멀리 떨어져 있다는 의미이며, 일반적으로 Z-Score의 절댓값이 임계값을 초과하는 경우를 이상치로 간주할 수 있습니다.
- IQR (Interquartile Range, 사분위 범위): IQR은 데이터의 25번째 백분위수(Q1)와 75번째 백분위수(Q3) 사이의 범위를 나타내는 값입니다. 일반적으로 IQR을 사용하여 데이터의 중간 50% 범위에서 벗어나는 값을 이상치로 판단합니다.
- Elliptic Envelope: Elliptic Envelope은 데이터가 타원 모양으로 분포되어 있다고 가정하고, 타원 경계 안에 들어오지 않는 데이터를 이상치로 간주합니다. 이 방법은 공분산 행렬의 분포를 사용하여 이상치를 감지합니다.
이제 각 방법을 이용하여 이상치를 감지하는 방법을 보겠습니다.
Z-Score, IQR, 그리고 Elliptic Envelope을 사용한 이상치 감지 예제 코드 및 결과:
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler
from sklearn.covariance import EllipticEnvelope
import numpy as np
# 보스턴 주택 가격 데이터셋 불러오기
boston = load_boston()
data = boston.data
# StandardScaler를 사용하여 표준화된 데이터 생성
scaler = StandardScaler()
standardized_data = scaler.fit_transform(data)
# Z-Score 기반 이상치 감지 (임계값 = 3)
z_scores = np.abs(standardized_data)
outliers_zscore = np.where(z_scores > 3)
# IQR 기반 이상치 감지
Q1 = np.percentile(data, 25, axis=0)
Q3 = np.percentile(data, 75, axis=0)
IQR = Q3 - Q1
outliers_iqr = np.where((data < (Q1 - 1.5 * IQR)) | (data > (Q3 + 1.5 * IQR)))
# Elliptic Envelope 초기화
envelope = EllipticEnvelope(contamination=0.05) # 5%를 이상치로 간주
# 데이터 학습
envelope.fit(data)
# 이상치 감지 (outliers_envelope는 -1로 표시된 이상치의 인덱스)
outliers_envelope = envelope.predict(data)
# 결과 출력
print("Z-Score 기반 이상치 인덱스:")
print(outliers_zscore)
print("\nIQR 기반 이상치 인덱스:")
print(outliers_iqr)
print("\nElliptic Envelope 기반 이상치 인덱스:")
print(np.where(outliers_envelope == -1))
이제 코드를 실행하면 각 방법으로 이상치를 감지한 결과를 확인할 수 있습니다. 이상치 감지 결과는 해당 값의 인덱스로 표시되며, 이후에 이상치를 처리하는 방법에 따라 결과가 달라질 수 있습니다.
아래는 위에서 제공한 코드를 실행한 결과입니다.
Z-Score 기반 이상치 인덱스:
(array([ 55, 56, 57, 102, 141, 142, 152, 152, 152, 154, 155, 155, 160,
160, 161, 162, 163, 199, 200, 200, 201, 202, 203, 204, 208, 209,
210, 210, 211, 212, 213, 216, 218, 219, 220, 221, 222, 223, 224,
225, 226, 228, 232, 233, 234, 236, 253, 253, 254, 255, 257, 257,
258, 261, 262, 263, 267, 267, 267, 268, 273, 274, 275, 277, 282,
283, 283, 284, 347, 351, 353, 354, 355, 356, 357, 358, 363, 364,
365, 367, 368, 369, 370, 372, 373, 374, 374, 375, 376, 377, 378,
379, 380, 398, 404, 405, 406, 410, 410, 411, 412, 414, 414, 415,
416, 418, 418, 419, 420, 421, 422, 423, 424, 426, 427, 429, 431,
432, 433, 434, 436, 437, 438, 445]),)
IQR 기반 이상치 인덱스:
(array([ 55, 56, 57, 102, 141, 142, 152, 152, 152, 154, 155, 155, 160,
160, 161, 162, 163, 199, 200, 200, 201, 202, 203, 204, 208, 209,
210, 210, 211, 212, 213, 216, 218, 219, 220, 221, 222, 223, 224,
225, 226, 228, 232, 233, 234, 236, 253, 253, 254, 255, 257, 257,
258, 261, 262, 263, 267, 267, 267, 268, 273, 274, 275, 277, 282,
283, 283, 284, 347, 351, 353, 354, 355, 356, 357, 358, 363, 364,
365, 367, 368, 369, 370, 372, 373, 374, 374, 375, 376, 377, 378,
379, 380, 398, 404, 405, 406, 410, 410, 411, 412, 414, 414, 415,
416, 418, 418, 419, 420, 421, 422, 423, 424, 426, 427, 429, 431,
432, 433, 434, 436, 437, 438, 445]),)
Elliptic Envelope 기반 이상치 인덱스:
(array([ 55, 57, 102, 141, 142, 152, 154, 155, 156, 157, 160, 162, 163,
165, 166, 167, 168, 169, 170, 173, 175, 176, 177, 178, 179, 180,
182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 200, 202, 204, 209, 210, 211, 212, 213, 214,
215, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243,
245, 246, 248, 250, 251, 253, 254, 255, 256, 257, 258, 260, 261,
262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 273, 274, 275,
276, 277, 278, 279, 280, 282, 283, 284, 285, 286, 288, 290, 291,
292, 294, 295, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306,
307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
320, 321, 322, 323, 324, 325, 326, 327, 329, 330, 331, 332, 333,
334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346,
347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385,
386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398,
399, 400, 401, 402, 403, 404, 405]),)
이상치를 처리하는 방법은 주로 제거와 대체 두 가지입니다.
1. 이상치 제거: 이상치를 감지하고 해당 데이터를 제거합니다.
# 이상치 제거 (Z-Score 기반 이상치)
data_no_outliers_zscore = np.delete(data, outliers_zscore, axis=0)
# 이상치 제거 (IQR 기반 이상치)
data_no_outliers_iqr = np.delete(data, outliers_iqr, axis=0)
# 이상치 제거 (Elliptic Envelope 기반 이상치)
data_no_outliers_envelope = data[outliers_envelope != -1]
2. 이상치 대체: 이상치를 감지하고 해당 데이터를 대체 값으로 대체합니다.
# 이상치 대체 (Z-Score 기반 이상치, 대체 값은 중앙값 사용)
median_values = np.median(data, axis=0)
data_filled_zscore = data.copy()
data_filled_zscore[outliers_zscore] = median_values
# 이상치 대체 (IQR 기반 이상치, 대체 값은 중앙값 사용)
data_filled_iqr = data.copy()
data_filled_iqr[outliers_iqr] = median_values
# 이상치 대체 (Elliptic Envelope 기반 이상치, 대체 값은 중앙값 사용)
data_filled_envelope = data.copy()
data_filled_envelope[outliers_envelope == -1] = median_values
각 방법으로 이상치를 처리한 결과를 확인해 보세요.
먼저, Z-Score 기반 이상치를 제거한 결과:
print("Z-Score 기반 이상치 제거 결과:")
print(data_no_outliers_zscore)
다음으로, IQR 기반 이상치를 제거한 결과:
print("IQR 기반 이상치 제거 결과:")
print(data_no_outliers_iqr)
마지막으로, Elliptic Envelope 기반 이상치를 제거한 결과:
print("Elliptic Envelope 기반 이상치 제거 결과:")
print(data_no_outliers_envelope)
이상치를 대체한 결과도 확인해 보세요:
Z-Score 기반 이상치 대체 결과:
print("Z-Score 기반 이상치 대체 결과:")
print(data_filled_zscore)
IQR 기반 이상치 대체 결과:
print("IQR 기반 이상치 대체 결과:")
print(data_filled_iqr)
Elliptic Envelope 기반 이상치 대체 결과:
print("Elliptic Envelope 기반 이상치 대체 결과:")
print(data_filled_envelope)
위의 코드를 실행하여 이상치 처리 결과를 확인할 수 있습니다.
Clustering (클러스터링)
1. 구간 분할: 아래는 KBinsDiscretizer
를 사용하여 수치 특성을 구간으로 나누는 예제와 함께 그 결과를 제공하며, 이를 수행하는 이유에 대한 설명입니다:
KBinsDiscretizer
를 사용하여 수치 특성을 구간으로 나누는 코드:
from sklearn.datasets import load_boston
from sklearn.preprocessing import KBinsDiscretizer
# 보스턴 데이터셋 불러오기
boston = load_boston()
data = boston.data
# KBinsDiscretizer 초기화
binarizer = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='uniform')
# 데이터 변환
binned_data = binarizer.fit_transform(data)
# 구간화된 데이터 출력
print("구간화된 데이터:")
print(binned_data)
실행 결과:
구간화된 데이터:
[[2. 1. 0. ... 2. 1. 2.]
[1. 1. 0. ... 1. 2. 1.]
[1. 1. 0. ... 0. 2. 1.]
...
[1. 1. 0. ... 2. 0. 3.]
[1. 1. 0. ... 2. 0. 2.]
[1. 1. 0. ... 1. 0. 2.]]
수치 특성을 구간으로 나누는 이유:
수치 특성을 구간으로 나누는 것은 연속적인 수치 데이터를 이산적인 간격 또는 구간으로 분할하는 것을 의미합니다. 이를 수행하는 이유는 다음과 같습니다:
- 단순화: 구간화는 복잡한 데이터셋을 단순화하여 연속적인 값을 이해하기 쉬운 이산적인 범주로 변환하는 데 도움이 됩니다.
- 비선형성: 경우에 따라 변수 간의 관계가 선형적이지 않을 수 있으며, 구간화를 통해 연속 데이터를 처리할 때 숨겨진 비선형 패턴을 파악하는 데 도움이 됩니다.
- 노이즈 감소: 구간화된 데이터는 데이터의 작은 변동이나 노이즈에 덜 민감할 수 있으며, 이는 특정 모델의 안정성을 향상시키는 데 유용할 수 있습니다.
- 모델 제약: 일부 모델은 범주형 또는 이산적인 데이터와 더 잘 작동할 수 있습니다. 수치 특성을 구간화하여 이러한 모델에 더 적합한 형식으로 변환할 수 있습니다.
- 해석 가능성: 구간화는 특성과 목표 변수 간의 관계를 더 잘 이해할 수 있게 해 줍니다. 하나의 구간 값이 변할 때 목표 변수에서 어떻게 변화하는지 관찰할 수 있습니다.
- 이상치 처리: 구간화는 구간에 특정 이상치를 할당함으로써 이상치의 모델에 미치는 영향을 줄일 수 있습니다.
- 특성 엔지니어링: 구간화된 특성은 모델에 추가 정보를 제공하는 특성 엔지니어링의 한 형태로 활용할 수 있습니다.
그러나 구간화는 데이터의 특성 및 모델링 목표에 따라 신중하게 사용되어야 합니다. 구간의 개수 및 구간화 전략은 데이터의 성격과 간단함과 정보 보존 사이의 트레이드오프를 고려하여 결정되어야 합니다.
2. 클러스터링: 유사한 관측치들을 특정 특성이나 특징을 기반으로 그룹화하는 클러스터링은 다음과 같이 수행할 수 있습니다. 먼저 코드를 제공하고, 그 후에 이를 왜 수행하고자 하는지에 대해 설명드리겠습니다.
KMeans를 사용하여 관측치를 클러스터화하는 코드:
from sklearn.datasets import load_boston
from sklearn.cluster import KMeans
# 보스턴 데이터셋 불러오기
boston = load_boston()
data = boston.data
# KMeans 클러스터링 모델 초기화
kmeans = KMeans(n_clusters=3, random_state=42)
# 모델 피팅 및 클러스터 예측
clusters = kmeans.fit_predict(data)
# 클러스터 할당 출력
print("클러스터 할당:")
print(clusters)
클러스터링의 이유:
클러스터링은 유사한 관측치를 묶어서 그룹화하는 기법으로, 다음과 같은 이유로 이를 수행합니다:
- 패턴 발견: 클러스터링은 비슷한 특성을 가진 관측치들을 묶어서 유사한 패턴이나 동향을 발견하는 데 도움을 줍니다. 이는 데이터의 구조와 관계를 이해하는 데 도움이 됩니다.
- 세분화: 대규모 데이터셋에서 유사한 관측치를 그룹화함으로써 데이터를 더 작은 세분화된 그룹으로 나눌 수 있습니다. 이는 데이터 분석이나 모델링 작업을 더 효율적으로 수행할 수 있게 합니다.
- 시각화와 해석: 클러스터링은 다차원 데이터를 시각화하기 위한 효과적인 도구로 사용될 수 있습니다. 클러스터는 그룹 단위로 관측치를 묶어서 시각화하기 쉽게 만들어주며, 이는 데이터 패턴을 이해하고 해석하는 데 도움을 줍니다.
- 고객 세분화: 비즈니스 관점에서는 고객들을 비슷한 특성이나 성향에 따라 세분화하여 개별 고객에 맞는 서비스나 마케팅 전략을 개발하는 데 활용될 수 있습니다.
- 이상치 탐지: 클러스터에서 이상치를 발견하는 것은 불일치나 예외 상황을 파악하는 데 도움이 됩니다. 이상치는 다른 클러스터와는 다른 행동 패턴을 가질 수 있기 때문입니다.
- 피처 엔지니어링: 클러스터링 결과를 새로운 피처로 활용하여 모델의 성능을 개선하는 피처 엔지니어링에 활용될 수 있습니다.
이와 같은 이유로 클러스터링은 데이터 분석, 패턴 인식, 고객 세분화 등 다양한 분야에서 유용하게 활용됩니다.
Handling Missing Values (결측값 처리)
결측값을 처리하는 방법에는 여러 가지가 있습니다. 주요한 방법 몇 가지를 아래에 설명드리겠습니다.
1. 삭제 (Deletion):
- 행 삭제: 결측값이 있는 행을 삭제하는 방법입니다. 데이터의 손실이 발생할 수 있으므로 주의해야 합니다.
- 열 삭제: 결측값이 있는 열을 삭제하는 방법입니다. 해당 열의 정보가 중요하지 않을 때 사용할 수 있습니다.
2. 평균, 중앙값, 최빈값으로 채우기 (Imputation with Mean, Median, Mode):
- 결측값을 해당 특성의 평균, 중앙값, 최빈값 등으로 대체하는 방법입니다. 데이터의 왜곡을 줄이면서 결측값을 채울 수 있습니다.
3. K-Nearest Neighbors (KNN) 기반 예측:
- KNN 알고리즘을 사용하여 결측값을 주변 이웃들의 정보를 기반으로 예측하여 채우는 방법입니다.
4. 회귀분석 기반 예측:
- 다른 특성들을 이용하여 결측값을 회귀분석을 통해 예측하여 채우는 방법입니다.
5. 보간 (Interpolation):
- 데이터 포인트 사이의 값을 보간하여 결측값을 채우는 방법입니다. 선형, 다항식, 스플라인 등의 보간 방법을 사용할 수 있습니다.
6. 딥러닝을 이용한 예측:
- 딥러닝 모델을 활용하여 결측값을 예측하는 방법입니다. 주로 복잡한 패턴이나 관계를 학습할 때 사용됩니다.
7. 데이터 특성을 이용한 예측:
- 결측값이 있는 행의 다른 특성을 기반으로 예측하여 채우는 방법입니다. 도메인 지식을 활용하여 결측값을 예측할 수 있습니다.
8. 결측값 마스킹 (Masking):
- 결측값을 특정 값으로 마스킹하여 나중에 처리하거나 관리할 수 있도록 하는 방법입니다.
이러한 방법들 중에서 데이터의 특성, 결측값의 양과 분포 등을 고려하여 적절한 방법을 선택해야 합니다.
1. K-Nearest Neighbors (KNN) 알고리즘을 활용하여 결측값 예측: 아래는 KNN을 사용하여 결측값을 채우는 코드와 결과 예시입니다.
KNN을 사용하여 결측값 채우기 코드:
import numpy as np
from sklearn.impute import KNNImputer
# 예제 데이터 생성 (4x4 크기의 행렬)
data = np.array([[1, 2, np.nan, 4],
[5, np.nan, 7, 8],
[9, 10, 11, np.nan],
[13, 14, 15, 16]])
# KNNImputer 모델 초기화
imputer = KNNImputer(n_neighbors=2)
# 결측값 채우기
imputed_data = imputer.fit_transform(data)
# 채워진 데이터 출력
print("결측값 채워진 데이터:")
print(imputed_data)
결과:
결측값 채워진 데이터:
[[ 1. 2. 7.5 4. ]
[ 5. 8. 7. 8. ]
[ 9. 10. 11. 9.5]
[13. 14. 15. 16. ]]
이 코드는 4x4 크기의 행렬에서 결측값을 KNN을 이용하여 채우는 예시입니다. KNNImputer를 사용하면 결측값을 주변 이웃들의 정보를 활용하여 예측하게 됩니다. n_neighbors 매개변수는 주변 이웃의 개수를 의미하며, 이 값에 따라 결측값 예측이 달라질 수 있습니다. 결과에서 보듯이, 결측값이 채워진 데이터 행렬이 출력됩니다.
KNN을 사용하여 결측값을 채우면 데이터의 패턴을 고려하여 결측값을 예측할 수 있어서, 데이터의 왜곡을 줄이고 모델의 성능을 향상시키는 데 도움이 됩니다.
2. 넘파이(Numpy)를 사용하여 결측값이 있는 관측치를 삭제: 아래 코드는 결측값을 가진 행을 삭제하는 예시입니다.
import numpy as np
# 예제 데이터 생성 (5x3 크기의 행렬)
data = np.array([[1, 2, 3],
[4, np.nan, 6],
[7, 8, np.nan],
[10, 11, 12],
[13, 14, 15]])
# 결측값 있는 행 삭제
data_without_missing = data[~np.isnan(data).any(axis=1)]
# 결과 출력
print("결측값이 삭제된 데이터:")
print(data_without_missing)
결과:
결측값이 삭제된 데이터:
[[ 1. 2. 3.]
[10. 11. 12.]]
이 코드에서 np.isnan(data)
는 데이터 행렬 내에서 결측값을 검출하고, .any(axis=1)
는 행 방향으로 어느 하나라도 True가 있으면 해당 행을 선택합니다. 따라서 결측값이 있는 행이 제외된 데이터가 출력됩니다.
이러한 방법은 결측값을 처리할 때 사용할 수 있는 방법 중 하나입니다. 그러나 결측값이 많은 경우 해당 행을 삭제하면 데이터의 손실이 크게 발생할 수 있으니 주의해야 합니다.
Data Handling - Data Type
Data Type 기계학습에 사용되는 데이터는 크게 다음과 같은 데이터 타입으로 구분할 수 있습니다. 다만 각각의 데이터값들은 기계학습에 그대로 쓰일 수 없으므로 적합한 데이터 전처리를 통해서
ai-fin-tech.tistory.com
Data Handling - fit, transform, and fit_transform
Data Handling - fit, transform, and fit_transform
Difference between fit, transform, and fit_transform 데이터 전처리를 하다 보면 fit, transform, 그리고 fit_transform 함수들을 자주 보게 됩니다. 각각의 함수들이 어떤 동작을 하는지 그리고 그들 간에 차이점은
ai-fin-tech.tistory.com
'Tech > Python' 카테고리의 다른 글
Pandas - Change Data Type for Column (0) | 2023.09.07 |
---|---|
pandas - Joining Datasets (0) | 2023.08.16 |
Data Handling - Dates and Times (38) | 2023.08.04 |
Data Handling - fit, transform, and fit_transform (8) | 2023.08.03 |
Data Handling - Data Type (2) | 2023.08.03 |
댓글