[ArcFault] Project step02: Data Analysis
in Side Project on Arc Fault
Arc-Fault
연구과제를 위해 개발한 코드입니다.
Introduction
저번 포스트에선 데이터 수집 단계에 대해 알아보았습니다.
이번 포스팅은 수집한 데이터를 이용해 분석 후 분류모델 생성까지 해보겠습니다.
전체 코드는 제 Github에 업로드 되어 있습니다.
Correlation analysis
먼저 데이터를 load 해줍니다.
# 데이터 load
arc_df = pd.read_csv('Arc_data.csv')
arc_df.head(10)
데이터 내 결측치 여부를 확인해줍니다.
# 데이터 내 NA 값 여부 확인
arc_df.isnull().any() # 만약 존재한다면 0으로 대체 혹은, 해당 열을 제외하고 진행
이제 본격적으로 상관분석을 해보겠습니다. 먼저 독립변수만 따로 추출하도록 하겠습니다.
# 독립변수만 따로 추출
features = ['Max', 'Mean', 'Std', 'Full_diff', 'FFT_Mag1', 'FFT_Hz1', 'FFT_Mag2', 'FFT_Hz2',
'STFT_Mag1', 'STFT_Hz1', 'STFT_Mag2', 'STFT_Hz2', 'STFT_diff']
arc_corr = arc_df[features]
그리고 corr()
함수를 통해 상관계수를 출력해보겠습니다.
# 상관계수 출력(method : 'Pearson')
arc_corr.corr()
출력값들을 보시면 대부분 변수들끼리 높은 상관성을 띄고 있는 것을 알 수 있습니다. 이는 나중에 다중공선성 문제를 일으키므로 VIF(Variance Inflation Factors, 분산팽창요인) 계수를 활용해 변수 선택법을 진행해보겠습니다.
Feature Select
VIF 제거 순서
- VIF 계수가 높은 feature 제거(단, 유사한 feature의 경우 둘 중 1개만 제거)
- 제거 후 VIF 계수 재출력
- (1,2)의 과정 반복
from statsmodels.stats.outliers_influence import variance_inflation_factor
# 피처마다의 VIF 계수를 출력합니다.
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(arc_corr.values, i) for i in range(arc_corr.shape[1])]
vif["features"] = arc_corr.columns
vif
VIF 계수가 높은 변수를 제거해주고, 다시 계수를 출력해보겠습니다.
# VIF 계수 높은 feature 제거
arc_corr = arc_corr.drop(['Std', 'FFT_Mag2', 'FFT_Hz2', 'STFT_Mag2', 'STFT_Hz2', 'STFT_Hz1'], axis = 1)
vif = pd.DataFrame()
vif['VIF Factor'] = [variance_inflation_factor(arc_corr.values, i) for i in range(arc_corr.shape[1])]
vif['features'] = arc_corr.columns
vif
충분히 많은 변수를 제거해주었음에도 불구하고, 여전히 다중공선성이 나타나는 것을 볼 수 있습니다. 따라서 변수 선택법이 아닌 다른 방법을 모색해야합니다.
Feature Extraction
차원 축소 기법인 PCA를 사용해줍니다. PCA 알고리즘은 기존의 변수들을 linear combination하여 새로운 변수를 만들어 내는 기법입니다.
먼저 MinMaxScaler()
로 정규화를 시켜주겠습니다.
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
arc_scale = pd.DataFrame(scaler.fit_transform(arc_corr), columns=arc_corr.columns)
그런 다음 PCA 알고리즘을 적용시키겠습니다. n_components = 2
는 주성분 개수가 2라는 것을 의미합니다.
from sklearn.decomposition import PCA
pca = PCA(n_components = 2) # 주성분 개수: 2
pca.fit(arc_scale)
arc_pca = pca.transform(arc_scale)
print(arc_pca.shape)
explained_variance_ratio_
는 pca의 각 주성분이 축소 전 데이터의 설명력을 의미합니다. 즉 1개의 각 주성분이 함축하고 있는 데이터를 의미합니다. 이를 cumsum()
하여 주성분 개수마다 축소 전 데이터의 어느 정도를 설명할 수 있는지(얼마나 덜 손실되었는지)를 알 수 있습니다.
# PCA 주성분분석
pd.Series(np.cumsum(pca.explained_variance_ratio_))
출력 결과
0 0.86267
1 0.92197
출력 결과를 보아 첫 번째 주성분은 원 데이터의 86%를 설명할 수 있으며, 두 개의 주성분을 가졌을 땐 92%의 설명력을 가진다고 할 수 있습니다.
그 후 두 개의 주성분을 사용하여 차원 축소된 데이터와 라벨을 합쳐 데이터프레임을 생성해줍니다.
Imbalanced Classes
실제 아크 상태와 정상 상태의 클래스 분포 비율은 정상 상태가 압도적으로 많습니다. 즉 클래스 분포가 불균형적입니다.
예를 들어 설명해보겠습니다. 암 환자를 분석한다고 했을 경우 암에 걸린 환자와 암에 걸리지 않은 환자의 클래스 분포 비율은 당연 암에 걸리지 않은 환자의 비율이 훨씬 많을 것 입니다. 따라서 이러한 클래스의 불균형을 해소해주어야 합니다.
먼저 target variable 분포를 확인해보겠습니다.
from collections import Counter
Counter(arc_pca.label)
출력 결과
Counter({0: 20, 1: 40})
현재 적은 양의 데이터로 진행하기 때문에 이 정도의 불균형은 크게 문제가 되지 않으나, 실제 데이터 수집을 하고 나서는 불균형하기 때문에 이를 SMOTE 기법을 이용하여 Oversampling 해주겠습니다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.1, random_state = 0)
# 기존의 X_train, y_train, X_test, y_test의 형태확인
print("Number transactions X_train dataset: ", X_train.shape)
print("Number transactions y_train dataset: ", y_train.shape)
print("Number transactions X_test dataset: ", X_test.shape)
print("Number transactions y_test dataset: ", y_test.shape)
형태를 확인했으니 이제 Oversampling 해주겠습니다.
from imblearn.over_sampling import SMOTE
print("Before OverSampling, counts of label '1': {}".format(sum(y_train == 1)))
print("Before OverSampling, counts of label '0': {}".format(sum(y_train == 0)))
sm = SMOTE(random_state = 42, sampling_strategy = 'auto') # SMOTE 알고리즘, 비율 증가
X_train_res, y_train_res = sm.fit_sample(X_train, y_train.ravel()) # Over Sampling 진행
print("After OverSampling, counts of label '1': {}".format(sum(y_train_res == 1)))
print("After OverSampling, counts of label '0': {}".format(sum(y_train_res == 0)))
Oversampling 적용 후 label ‘1’과 ‘0’의 개수가 같아진 것을 확인 할 수 있습니다.
train set의 형태가 어떻게 바뀌었는지 확인해보겠습니다.
print("Before OverSampling, the shape of X_train: {}".format(X_train.shape)) # SMOTE 적용 이전 데이터 형태
print("Before OverSampling, the shape of y_train: {}".format(y_train.shape)) # SMOTE 적용 이전 데이터 형태
print("After OverSampling, the shape of X_train: {}".format(X_train_res.shape)) # SMOTE 적용 결과 확인
print("After OverSampling, the shape of y_train: {}".format(y_train_res.shape)) # SMOTE 적용 결과 확인
SVM(Support Vector Machine)
SVM(Support Vector Machine)이란 주어진 데이터가 어느 카테고리에 속할지 판단하는 이진 선형 분류 모델입니다.
먼저 features와 target 변수를 설정해줍니다.
features = X_train_res
target = y_train_res
다음으로 SVM 모델을 생성 후 학습을 시켜보겠습니다.
from sklearn.svm import SVC
from sklearn import svm, metrics
import numpy as np
import matplotlib.pyplot as plt
svc = SVC(kernel = 'linear', class_weight = 'balanced', C = 1.0, random_state = 0)
model = svc.fit(features, target) # SVM 모델 학습
다음은 혼동 행렬을 출력해보겠습니다.
from sklearn.metrics import confusion_matrix
y_pred = svc.predict(features)
confusion_matrix(target, y_pred)
kernel SVM 적합 및 비교
다음으로 kernel 별 적합한 SVM 모델을 찾아보겠습니다.
LinearSVC
,radial basis function
,polynomial kernel
이 있습니다.
우선 시각화 함수를 생성해보겠습니다.
def make_meshgrid(x, y, h = .02):
x_min, x_max = x.min()-1, x.max() + 1
y_min, y_max = y.min()-1, y.max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
return xx, yy
def plot_contours(ax, clf, xx, yy, **params):
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
out = ax.contourf(xx, yy, Z, **params)
return out
다음으로 모델을 정의하고 학습을 시켜줍니다.
C = 1.0 # Regularization parameter
models = (svm.SVC(kernel = 'linear', C=C),
svm.LinearSVC(C=C, max_iter = 10000),
svm.SVC(kernel = 'rbf', gamma = 0.7, C=C),
svm.SVC(kernel = 'poly', degree = 3, gamma = 'auto', C=C))
models = (clf.fit(X, y) for clf in models)
이제 kernel 별 어떻게 분류가 되는지 시각화하여 나타내보겠습니다.
titles = ('SVC with linear kernel',
'LinearSVC (linear kernel)',
'SVC with RBF kernel',
'SVC with polynomial (degree 3) kernel')
fig, sub = plt.subplots(2,2)
plt.subplots_adjust(wspace = 0.4, hspace = 0.4)
X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)
for clf, title, ax in zip(models, titles, sub.flatten()):
plot_contours(ax, clf, xx, yy, cmap = plt.cm.coolwarm, alpha = 0.8)
ax.scatter(X0, X1, c = y, cmap=plt.cm.coolwarm, s = 20, edgecolors = 'k')
ax.set_xlim(xx.min(), xx.max())
#ax_set_ylim(yy.min(), yy.max())
ax.set_xlabel('Sepal length')
ax.set_ylabel('Sepal width')
ax.set_yticks(())
ax.set_xticks(())
ax.set_title(title)
plt.show()
시각화 결과를 보면 데이터 개수가 적어 대부분 잘 분류되는 것을 확인할 수 있습니다. 그리고 아크 상태(Arc1, Arc2)와 normal 상태가 잘 분류되는 것을 볼 수 있습니다.
GridSearch
다음으로 Hyperparameter optimizationd의 방법 중 하나인 GridSearch를 통해 최적의 파라미터 값을 탐색해보겠습니다.
먼저 그리스 서치 매개변수를 설정해준 후, 그리드 서치를 수행하고 테스트 데이터의 accuracy를 확인해보겠습니다.
from sklearn import svm, metrics, model_selection
from sklearn.model_selection import GridSearchCV
print("학습 데이터의 수 =", len(target))
# 그리드 서치 매개변수 설정
params = [
{"C" : [1, 10, 100, 1000], "kernel" : ["linear"]},
{"C" : [1, 10, 100, 1000], "kernel" : ["rbf"], "gamma":[0.001, 0.0001]}
]
# 그리드 서치 수행
clf = GridSearchCV(svm.SVC(), params, n_jobs = -1)
clf.fit(features, target)
print("학습기 =", clf.best_estimator_)
# 테스트 데이터 확인하기
pre = clf.predict(X_test)
ac_score = metrics.accuracy_score(pre, y_test)
print("정답률 =", ac_score)
출력 결과로 학습 데이터의 수, 모델의 accuracy, 학습기에는 가장 최적의 파라미터 값이 나옵니다.
모델 성능도 한 번 살펴보겠습니다.
svc = SVC(kernel = 'linear', class_weight = 'balanced', C = 1.0, random_state = 0)
model = svc.fit(features, target)
pre = clf.predict(X_test)
ac_score = metrics.accuracy_score(y_test, pre)
cl_report = metrics.classification_report(y_test, pre)
print("정답률 = ",ac_score)
print("리포트 =\n", cl_report)
Class를 예측하고자 하는 경우엔 shape을 맞춰 값을 할당한 후 predict해주면 됩니다.
new_observation = [[1, -0.2]]
svc.predict(new_observation)
이상으로 Arc-Fault 데이터 분석 후 분류 모델 생성까지 마쳤습니다.
다음으로 시계열 데이터를 통해 arc 상태를 탐지해보는 시간을 가져보겠습니다.
감사합니다 :)
Reference
- https://bkshin.tistory.com/entry/DATA-20-%EB%8B%A4%EC%A4%91%EA%B3%B5%EC%84%A0%EC%84%B1%EA%B3%BC-VIF
- https://specialscene.tistory.com/11