원래 전공이 데이터 분석인데..
블로그에는 주로 새로 알게된 것, 공부하고 싶은 것만 적다보니
어쩌다보니 데이터 분석에 관련된 글을 이제서야 쓰게 되었다..!
항상 사용하는것만 사용하고 그러다 보니 새로 알게 되는게 별로 없었고
프로젝트도 분석 업무 담당이 아니었어서 더 그랬던거같다.
오랜만에 이번에 데이터 분석? 데이터 처리? 업무를 맡게된 김에
내가 어떤과정을 거쳐서 분석했는지? 적어보려고한다.
적당히 필터링 한 코드를 적어보려고한다. 이 기록이 다른분들에게 도움이 되었으면 좋겠다.
1. 개요
이번 프로젝트는 결과적으로 Anomaly detection를 하는 과제다.
보통 Anomaly detection 같은 경우에는 비지도 학습을 하는 경우가 대부분인데
현업 데이터 기반으로 이제 막 시작하는 단계이다 보니
데이터만 있을 뿐 어떤 값이 이상치인지 기준도 없고 해서 정상, 이상치에 대한 label이 없는 데이터였다.
그래서 비지도 학습을 여러개 해봐도 그래서 성능이 어떤지 파악하기가 어려운 편이었다.
그래서 그나마 신뢰도 있는 통계적 기법을 이용하여 1차적으로 labeling을 한 후
이 label데이터를 활용해 ML을 해보기로 결정하였다.
근데 이렇게 된 이상 label이 있다면 지도학습도 가능하니 일단 지도학습으로 진행해보는게 어떻겠냐고 하셔서 그렇게 해보겠다고 해서 진행하게 되었다. 그리고 AutoML에 관심이 있으셔서 그거로 시도해볼 수 있겠냐 하셔서 그렇게 하기로 한 상황이다.
2. 준비
[데이터]
Data1 : 통계적 기법으로 labeling 작업을 한데이터
Data2 : 관측된 값들이 있는 원본데이터
Data2 에 Data1의 label을 붙여서 사용할 것이다.
[모델]
python의 H2o 라이브러리를 사용해서 AutoML을 돌릴 것이다.
3. 코드
데이터 준비
import pandas as pd
import argparse
# python 실행 시 파라미터 같이 받기
parser = argparse.ArgumentParser(description="H2o Classifier Run Test")
# 위치 인자 추가
# 다른 인자 생략
parser.add_argument('sampling', type=str, help='No sampling: None, underSampling: u, overSampling: o')
# 인자 파싱
args = parser.parse_args()
print("input args: ", args)
# 라벨데이터 준비
data1 = pd.read_csv("data1.csv")
# 관측(원본)데이터 준비
data2 = pd.read_csv("data2.csv")
# 라벨링 된 데이터 추가
data2['label'] = data1['label'].values
# 학습에 사용할 df
data_df = data2[[분석에 사용할 X Features, 'label']]
# 날짜정보 포함한 df
data_df_tm = data2[['Time', 분석에 사용할 X Feature, 'label']]
# drop Na
data_df = data_df.dropna()
data_df_tm = data_df_tm.dropna()
[코드 설명]
1. parser : python 실행시 사용자에게 파라미터를 입력받는다. 여기서는 사용자가 Sampling 사용 여부에 따라서 파라미터를 입력하게 한다.
ex- python test.py None
2. data1, data2 : csv를 불러온다
3. data_df : 학습에 사용하기 위해 data1에 있는 label 컬럼을 붙여준다.
4. data_df_tm : 나중에 시각화에 필요한 시간 컬럼을 남겨둔 df를 미리 만들어준다.
5. dropna() : 결측치를 삭제한다. 관측데이터이기 때문에 관측되지 않은 값을 임의로 넣는것은 부적절 한 것 같아 삭제했다.
train-test split, sampling 진행
X = data_df.drop('label', axis=1) # X Fetures
y = data_df['label'] # target(label)
# train-test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
# 샘플링 여부 결정
from imblearn.under_sampling import RandomUnderSampler
from imblearn.over_sampling import RandomOverSampler
folderpath = ''
# underSampling
if args.sampling =='u':
# under(down) sampling --> train에 대해서만
# 데이터 감소
folderpath = './h2o_cls_sampling-u/'
X_train_, y_train = RandomUnderSampler(random_state=42).fit_resample(X_train, y_train)
# overSampling
elif args.sampling =='o':
# over(up) sampling --> train에 대해서만
# 데이터 증가
folderpath = './h2o_cls_sampling-o/'
X_train, y_train = RandomOverSampler(random_state=42).fit_resample(X_train, y_train)
# no Resampling
elif args.sampling =='None':
folderpath = './h2o_cls_sampling-None/'
pass
# 결과물 저장용 경로 생성
# make folder to save data
if not os.path.exists(folderpath):
os.makedirs(folderpath)
os.makedirs(folderpath + "models") # save all models
os.makedirs(folderpath + "total_results") # save test data results
os.makedirs(folderpath + "valid_results") # save total data results
print(f"Make folder '{folderpath}' Success.")
else:
print(f"Make folder '{folderpath}' is already exists.")
# 0, 1 비율 확인
print("Splited target(label) distribution")
print("Train ")
train_distribution = y_train.value_counts()
print(train_distribution)
print("Test ")
test_distribution = y_test.value_counts()
print(test_distribution)
[코드 설명]
1. X, y : 독립변수와 종속변수를 분리해준다.
2. train_test_split : train_test = 8:2로 분리한다. 이때 stratify = y 를 이용하여 label컬럼의 class의 비율을 유지하도록 split한다. (class 치우침 방지)
3. sampling : 사용자 입력값에 따라 sampling을 해주고 path를 정해준다.
4. mkdir : path 경로에 폴더를 생성한다. models에는 모델을, total_results에는 전체데이터의 예측결과를, valid_results에는 test 데이터의 예측 결과를 저장할 예정이다.
5. distribution : 쪼개진 train, test셋에서 Class 비율을 유지하는지 확인한다.
표준화, 학습 준비
from sklearn.preprocessing import StandardScaler
# StandardScaling
scaler = StandardScaler()
transformed_X_train = scaler.fit_transform(X_train) #train 데이터 기준으로 표준화
# for test
transformed_X_test = scaler.transform(X_test)
transformed_X_total = scaler.transform(X)
# to df
X_train_df = pd.DataFrame(transformed_X_train)
X_test_df = pd.DataFrame(transformed_X_test)
X_total_df = pd.DataFrame(transformed_X_total)
# check shape
print("Splited dataset Shape")
print("X_Train Shape : ", X_train_df.shape)
print("X_Test Shape : ", X_test_df.shape)
print("X_Total Shape : ", X_total_df.shape)
print("y_Train Shape : ", y_train.shape)
print("y_Test Shape : ", y_test.shape)
print("y_Total Shape : ", y.shape)
# 표준화 된 X에 표준화시키지 않은 y값을 추가함
X_train_df['label'] = y_train.values
X_test_df['label'] = y_test.values
X_total_df['label'] = y.values
[코드 설명]
fit_transform : Train데이터 기준으로 scaler fit 시키고 변환.
y는 원하는 목표 데이터이기 때문에 변환 시켜주면 안된다.
transform : fit 된 scaler로 변환
shape : 학습에 사용하기 위해 df로 변환하고 데이터 shape확인
y.values : X와 y를 붙여 하나의 df로 만듦
Automl 실행
# Run Automl
import h2o
from h2o.automl import H2OAutoML
h2o.init()# Start h2o server
train_h2o = h2o.H2OFrame(X_train_df) # train_data는 pandas DataFrame
test_h2o = h2o.H2OFrame(X_test_df) # test_data는 pandas DataFrame
total_h2o = h2o.H2OFrame(X_total_df) # 표준화된 total + y
target_column = 'label' # target
# change y to object type
train_h2o['label'] = train_h2o['label'].asfactor()
test_h2o['label'] = test_h2o['label'].asfactor()
total_h2o['label'] = total_h2o['label'].asfactor()
train for 1 hour
aml = H2OAutoML(max_models=5, max_runtime_secs=3000, seed=42)
aml.train(y=target_column, training_frame=train_h2o) # train
lb = aml.leaderboard
print(lb)
[코드설명]
h2o.init() : h2o서버를 시작
H2OFrame : h2o모델을 돌릴 수 있도록 변환
asfactor() : 분류 모델이기 때문에 0, 1을 object 형식으로? 변환
H2OAutoML : AutoML실행.
max_models : 최대 모델 개수
max_runtime_secs : 최대 실행 시간
leaderboard : 성능 좋은 모델 순으로 정렬
4. 주의사항
내가 코드 작업을 하면서 좀 헷갈렸던 부분과 다시한번 명확하게 알게 된 점들을 적어보았다.
1. StandardScaler, MinMaxScaler 등 스케일링은 X Features에만 적용한다.
- 변수들의 범위를 비슷하게 맞춰주는 것이기 때문에, 목표로 하는 Target인 y에는 적용하지 않는 것이 일반적이다.
2. scaler에서의 fit_transform은 Train 데이터로 한다.
scaler = StandardScaler()
scaler.fit(train_data)
transformed_data = scaler.transform(train_data)
scaler = StandardScaler()
transformed_data = scaler.fit_transform(train_data)
- 위 두 코드는 똑같다. fit 하고 transform = fit_transform
- scaling 기준을 Train으로 하고 fit 해준 뒤 fit 된 scaler를 이용하여 transform해줘야 한다.
- Train과 Test의 scaler는 동일해야한다. Train 데이터로 fit 된 scaler를 이용하여 Test 데이터를 transform 해 주어야한다.
3. Resampling은 Train-Test split 후 Train에만 적용한다
- valid를 위한 Test 데이터셋은 실제 데이터와 같은 취급이므로 불균형인 상태를 유지하고 이를 이용하여 검증해야한다.
글이 너무 길어져 한번 끊고 다음 게시물에 이어 쓰도록 하겠다.
이후에는 AutoML로 만들어진 모델 저장, 검증 및 예측, Confusion Matrix 출력하는 과정에 대한 내용을 담을 예정이다.