데이터 정제

데이터셋은 완벽하지 않다. 어떤 값이 비어있을 수도 있고, 빈 값이 너무 많은 특성이 있을 수도 있다. 이러한 경우에 사용할 수 있는 방법은 크게 세 가지가 있다.

  1. 해당 데이터 제거
  2. 전체 특성 삭제
  3. 누락된 값을 어떤 값(평균, 중간 값, 0 등)으로 대체

코드는 다음과 같다.

housing.dropna(subset=['total_bedrooms'], inplace=True)     # 값이 없는 데이터 제거
housing.drop("total_bedrooms", axis=1, inplace=True)        # 특성 삭제

median = housing['total_bedrooms'].median()
housing['total_bedrooms'].fillna(median, inplace=True)      # 중간값으로 채우기


사이킷런의 설계 철학

사이킷런 API의 대표적인 설계 철학은 다음과 같다.

  • 추정기(Estimator): 데이터셋을 기반으로 일련의 모델 파라미터를 예측하는 객체. 추정 자체는 fit()에 의해 수행된다.
  • 변환기(Transformer): 데이터셋을 변환하는 추정기. transform()이 수행한다. fit()transform()을 연달아 수행하는 fit_transform()도 있다.
  • 예측기(Predictor): 일부 추정기는 주어진 데이터셋에 대해 예측을 만들 수 있다. predict() 매서드는 새로운 데이터셋을 받아 이에 상응하는 예측값을 반환한다.
  • 조합성: 기존의 구성 요소를 최대한 활용한다. 여러 변환기를 연결하고 마지막에 추정기를 배치한 Pineline 추정기를 만들 수 있다.


범주형 특성 다루기

원-핫 인코딩을 사용하면 범주형 특성을 다룰 수 있다.


특성 스케일링

특성마다 스케일이 다르므로 스케일링을 통해 특성들의 범위를 맞추어 주어야 한다.

  1. Min-max 스케일링
from sklearn.preprocessing import MinMaxScaler
min_max_scaler = MinMaxScaler(feature_range=(-1, 1))
housing_num_min_max_scaled = min_max_scaler.fit_transform(housing_num)
  1. 표준화(Standardization)
from sklearn.preprocessing import StandardScaler
std_scaler = StandardScaler()
housing_num_std_scaled = std_scaler.fit_transform(housing_num)


데이터 분포 변환하기

특성 분포의 꼬리가 두꺼울 때(eg. 멱법칙 분포), 분포가 대칭적으로 되도록 변환해주어야 한다.


  1. 제곱근 사용
  2. 로그 사용
  3. 버킷다이징(bucketizing): 분포를 동일한 크기의 버킷으로 자르고 특성 값을 해당하는 버킷의 값으로 바꾼다.
  4. 방사 기저 함수(Radial Basis Function, RBF): 정점(모드)이 두 개 이상 나타나는 멀티모달 분포에서 사용하는 방식. 데이터와 모드 사이의 유사도를 표현한다.




사용자 정의 변환기

사이킷런에서 유용한 변환기를 많이 제공하지만 자신만의 변환기를 만들 수도 있다.


변환 파이프라인

파이프라인을 구현하는 데 사용하는 함수들은 다음과 같다.

함수 설명
Pipeline() 기본적인 파이프라인 제작.
make_pipeline() 변환기의 이름을 짓는 것이 귀찮을 때 사용.
ColumnTransformer() 하나의 변환기로 모든 열을 처리할 때 사용.

자세한 사용 방법과 예시는 코드를 참고하도록 하자.


본 예시에서의 파이프라인

본 예시에서의 파이프라인은 다음과 같은 작업을 수행한다.

  1. 누락된 값을 대체한다. 숫자형은 중간값, 범주형은 가장 많이 등장하는 값으로 대체한다.
  2. 범주형 특성을 원-핫 인코딩한다.
  3. 비율 특성인 ‘bedrooms_ratio’, ‘rooms_per_house’, ‘people_per_house’를 계산해서 추가한다.
  4. 클러스터 유사도 특성을 추가한다.
  5. 꼬리가 두꺼운 분포를 띠는 특성을 로그값으로 바꾼다.
  6. 모든 수치 특성을 표준화한다.

완성된 코드는 다음과 같다.

def column_ratio(X):
    return X[:, [0]] / X[:, [1]]

def ratio_name(function_transformer, feature_names_in):
    return ['ratio']

def ratio_pipeline():
    return make_pipeline(
        SimpleImputer(strategy='median'),
        FunctionTransformer(column_ratio, feature_names_out=ratio_name),
        StandardScaler()
    )

log_pipeline = make_pipeline(
    SimpleImputer(strategy='median'),
    FunctionTransformer(np.log, feature_names_out='one-to-one'),
    StandardScaler()
)

cluster_simil = ClusterSimilarity(n_clusters=10, gamma=1, random_state=42)
default_num_pipeline = make_pipeline(SimpleImputer(strategy='median'),
                                     StandardScaler())

preprocessing = ColumnTransformer([
    ('bedrooms', ratio_pipeline(), ['total_bedrooms', 'total_rooms']),
    ('room_per_house', ratio_pipeline(), ['total_rooms', 'households']),
    ('people_per_house', ratio_pipeline(), ['population', 'households']),
    ('log', log_pipeline, ['total_bedrooms', 'total_rooms', 'population', 'households', 'median_income']),
    ('geo', cluster_simil, ['latitude', 'longitude']),
    ('cat', cat_pipeline, make_column_selector(dtype_include=object))
],
                                  remainder=default_num_pipeline)
     

코드 보러가기



별도의 출처 표시가 있는 이미지를 제외한 모든 이미지는 강의자료에서 발췌하였음을 밝힙니다.

댓글남기기