Python으로 머신러닝(ML) 분류모델에 들어갈 데이터를 전처리하는 방법을 알아보자.
※ 본 내용에서 사용하는 machine_failure.csv 파일은 별도로 다운로드 받아야 한다.
※ machine_failure.csv 다운받기 [클릭]
※ 상기 데이터는 UCI ML 저장소의 데이터를 가공한 데이터이다.
개요
실무에서 주어지는 데이터는 바로 머신러닝 모델에 넣기 곤란한 경우가 많다. 그리고 이러한 데이터를 머신러닝 모델에 넣기 위해서는 전처리가 필요하다. 이번 게시물에서는 머신러닝 분류모델에 들어갈 데이터를 전처리하는 방법을 알아본다.
본 전처리 예제는 다음의 게시물의 내용을 모두 이해하고난 후에 도전하기 바란다.
그리고 다음과 같은 내용을 다룬다.
대분류 | 소분류 | 여부 |
---|---|---|
데이터유형 | 단일 데이터 | O |
다중 데이터 | ||
일반 전처리 | 문자 데이터 핸들링 | |
숫자 데이터 핸들링 | ||
시간 데이터 핸들링 | ||
필터링 | ||
정렬 | ||
피보팅 | ||
그룹 연산 | ||
축 연산 | ||
특정 변수 제거 | ||
데이터 병합 | 조인 연산 | |
이어붙이기 | O | |
이상치 처리 | 극단치 확인 | O |
극단치 제거 | ||
극단치 대치 | ||
결측치 확인 | O | |
결측치 제거 | ||
결측치 대치 | ||
수치형 데이터 처리 | 단순 데이터 변환 | |
특수 지표 생성 | ||
구간화 | ||
표준화 | O | |
범주형 데이터 처리 | 단순 데이터 변환 | |
특수 지표 생성 | ||
레이블 인코딩 | ||
원핫 인코딩 | O | |
데이터 분할 | 단순 분할 | |
단순 표본추출 | ||
층화 표본추출 | O |
데이터 준비
공장의 센서 데이터를 사용하여 데이터 전처리를 실습하려고 하며 제공되는 데이터(ins_charges.csv)의 각 변수명과 설명은 다음과 같다.
변수명 | 설명 |
---|---|
id | 고유 식별자 |
type | 공정 유형 |
temp_air | 공기 온도 |
temp_process | 공정 온도 |
speed | 기계의 작동 속도 |
torque | 기계의 토크(회전력) |
tool_wear | 공구 마모 정도 (사용 시간) |
is_failure | 공정 실패 여부 (0: 정상, 1: 실패) |
이제 “machine_failure.csv” 데이터를 다운받아 불러온다.
※ machine_failure.csv 다운받기 [클릭]
1 | import pandas as pd |
id | type | temp_air | temp_process | speed | torque | tool_wear | is_failure | |
---|---|---|---|---|---|---|---|---|
0 | 14860 | M | 298.1 | 308.6 | 1551 | 42.8 | 0 | 0 |
1 | 47181 | L | 298.2 | 308.7 | 1408 | 46.3 | 3 | 0 |
전처리
이제 본격적인 전처리를 시작해보자. 전처리를 하기 위해 필요한 각종 라이브러리의 함수와 클래스를 호출하자.
1 | from sklearn.model_selection import train_test_split # 데이터셋 분할 |
결측치
우선 각 변수별 결측치를 확인한다.
1 | df.isna().sum() |
결측치가 없으므로 결측치 처리는 넘어가도록 한다.
극단치
각 변수별 극단치를 확인한다. 먼저 수치형 변수만 추출하여 최소, 평균, 최대값을 확인한다.
1 | df.select_dtypes(include = "number").agg(["min", "mean", "max"]) |
id | temp_air | temp_process | speed | torque | tool_wear | is_failure | |
---|---|---|---|---|---|---|---|
min | 14860.000000 | 295.300000 | 305.700000 | 1168.000000 | 3.800000 | 0.000000 | 0.00000 |
mean | 40704.791725 | 300.003556 | 310.004208 | 1538.865057 | 39.980535 | 107.929473 | 0.03306 |
max | 57174.000000 | 304.500000 | 313.800000 | 2886.000000 | 76.600000 | 253.000000 | 1.00000 |
최소값과 최대값을 보았을 때 평균 대비 아주 극단적으로 크거나 작은 값은 확인이 되지 않는다. 물론 이는 각 변수별로 상자수염그래프 같은 것들을 그려서 확인하는 것이 더 정확하겠지만, 여기서는 생략한다.
그리고 범주형 변수를 살펴본다. 범주형 변수의 경우 어떤 범주가 극단적으로 적은 비율로 있거나 많은 비율로 있으면 처리가 필요할 수 있겠다.
1 | df["type"].value_counts() |
“type”변수의 각 범주는 약 6:3:1의 비율로 구성되어 있으므로 극단적인 비율이라고 판단하기에는 어렵다. 그러므로 극단치 처리는 넘어가도록 한다.
데이터 분할
학습 데이터와 평가 데이터로 분할하기 위해 train_test_split()
함수를 사용한다. 그리고 stratify
옵션을 사용하여 층화표본추출을 실시하고 “type”변수의 비율을 유지하도록 한다.
1 | df_train, df_test = train_test_split(df, |
상기 층화표본추출이 제대로 이루어졌는지 코드를 통해 “type” 변수의 범주 구성비를 확인해보도록 하자. 우선 기존 “df” 객체의 경우는 다음과 같다.
1 | df["type"].value_counts(normalize = True) |
다음으로 “df_train”, “df_test” 객체의 경우는 다음과 같다.
1 | df_train["type"].value_counts(normalize = True) |
상기 결과를 봤을 때 “df_train”, “df_test” 객체의 “type” 변수의 범주 구성비가 “df” 객체와 거의 동일하게 유지되었음을 확인할 수 있다.
정규화
정규화를 실시하기 위해 StandardScaler()
클래스를 사용한다. 이때 식별자인 “id”변수, 범주형인 “type”변수, 종속변수로 사용될 수 있는 “is_failure” 변수는 제외하고 정규화를 실시한다.
1 | ls_drop_cols = ["id", "type", "is_failure"] |
상기 코드에서 제외하고자 하는 변수명을 여러번 써야하는 불편함을 줄이기 위해 “ls_drop_cols”라는 리스트 객체를 생성하여 사용하였다.
정규화 결과를 확인해보자.
1 | df_train_nor.head(2) |
temp_air | temp_process | speed | torque | tool_wear | |
---|---|---|---|---|---|
0 | 0.399154 | 1.352290 | -0.877336 | 0.926149 | 1.084815 |
1 | 0.001026 | -0.266219 | -0.482743 | 0.596147 | -0.889909 |
범주형 변수 처리
이번에는 범주형 변수를 One-Hot Encoding을 실시한다. 이때 “type” 변수만 One-Hot Encoding을 실시하고 “id” 변수는 식별자이므로 작업에서 제외한다.
1 | model_ohe = OneHotEncoder().fit(df_train[["type"]]) |
각 결과 객체를 확인해보자.
1 | df_train_ohe.head(2) |
type_H | type_L | type_M | |
---|---|---|---|
0 | 0.0 | 1.0 | 0.0 |
1 | 0.0 | 1.0 | 0.0 |
1 | df_test_ohe.head(2) |
type_H | type_L | type_M | |
---|---|---|---|
0 | 0.0 | 0.0 | 1.0 |
1 | 0.0 | 1.0 | 0.0 |
데이터 통합
앞에서 생성한 객체를 하나로 통합한다. 정규화된 수치형 변수 데이터, One-Hot Encoding된 범주형 변수 데이터, 그리고 종속변수와 식별자 데이터를 하나로 통합한다. 단, 종속변수와 식별자 데이터 “df_train” 데이터에서 가져오는데 해당 객체의 row index 때문에 데이터 병합 과정에서 문제가 생길 수 있어 .reset_index()
메서드를 사용하여 index를 초기화한다.
1 | df_train_bind = pd.concat([df_train[["id", "is_failure"]].reset_index(drop = True), |
병합 결과를 확인해보자.
1 | df_train_bind.head(2) |
id | is_failure | type_H | type_L | type_M | temp_air | temp_process | speed | torque | tool_wear | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 55100 | 0 | 0.0 | 1.0 | 0.0 | 0.399154 | 1.352290 | -0.877336 | 0.926149 | 1.084815 |
1 | 49876 | 0 | 0.0 | 1.0 | 0.0 | 0.001026 | -0.266219 | -0.482743 | 0.596147 | -0.889909 |
나중에 모델링을 실시할 때 학습 데이터와 평가 데이터를 구분할 수 있도록 “Xgrp” 변수를 생성하고 하나로 통합한다.
1 | df_train_bind["Xgrp"] = "train" |
id | is_failure | type_H | type_L | type_M | temp_air | temp_process | speed | torque | tool_wear | Xgrp | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 55100 | 0 | 0.0 | 1.0 | 0.0 | 0.399154 | 1.352290 | -0.877336 | 0.926149 | 1.084815 | train |
1 | 49876 | 0 | 0.0 | 1.0 | 0.0 | 0.001026 | -0.266219 | -0.482743 | 0.596147 | -0.889909 | train |
마무리
적당히 저장하면 끝!
1 | df_bind.to_csv("data/model_classification_machine_failure.csv", index = False) |