데이터 전처리
데이터 분석을 할 때, 서로 다른 단위를 가지고 있는 값들을 다루려면 표준화 또는 정규화 과정을 거쳐야 한다. 예를 들어 무게 50kg ~ 80kg의 데이터와 키 160cm ~ 190cm의 데이터를 다룰 때 단위가 다름에도 숫자의 절댓값을 가지고 분석할 때 키 데이터에 가중치가 상대적으로 높게 들어간다. 이를 해결하기 위하여 두 데이터의 평균을 0, 표준편차를 1로 만드는 것이 표준화라고 하고, 최댓값을 1로 최솟값을 0으로 만드는 것이 정규화라고 한다.
그럼 지난번에 했던 도미와 빙어의 무게와 길이 데이터를 각각 표준화와 정규화를 한 후에 KNN 모델을 통한 예측, 검증을 해 보겠다. 먼저 파이썬으로 해보고 다음 R로 했을 때 각각 어떤 장/단점이 있는지 살펴보자.
그리고 무게 25, 길이 150이 어떤 값인지 알고자 한다.
길이와 무게를 모두 평균을 0, 표준 편차를 1로 만들어 x, y 축으로 두고 그래프를 다시 그려보는 것이다.
길이와 무게를 하나의 array로 만드는 것에서부터 시작
df=[[l,w] for l,w in zip(length,weight)] #두열로 리스트 만들기
df=np.array(df) #리스트를 array로 바꾸기
왼쪽 열이 길이, 오늘 쪽 열이 무게이다.
각각의 열의 평균과 표준편차를 구하자. 파이썬은 두열을 한꺼번에 아래와 같이 구할 수 있다.
mean=np.mean(train_x, axis=0) #axis=0 열 별로 계산
[ 27.29722222 454.09722222]
std=np.std(train_x, axis=0) #axis=0 열 별로 계산
[ 9.98244253 323.29893931]
그럼 표준화 공식을 통해 새로운 train 값을 만들어보자 (test 값도 동일)
train_scaled=(train_x-mean)/std
그리고 새로 변환된 변수의 첫 번째 열을 x 축으로 (길이), 두 번째 열을 y축으로 (무게) 그래프를 그려보면,
new=([25,150]-mean)/std
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.title("scaled")
plt.show()
x축, y축 각각 평균이 0이고, 표준편차가 1로 데이터를 변환한 후 그래프를 그린 것이다. 이를 확인하기 위하여 간단하게 box plot을 그려보았다.
R에서 평균과 표준편차를 구하는 함수는 mean, sd이다.
파이썬처럼 열 별로 각각 평균과 표준편차를 구해보자. 이때 사용하 것이 apply (df, 2, 함수명)
여기서 2는 열 별로, 1은 행별로 계산하는 것인데, 파이썬의 axis=0 은 열, axis=1은 행별로 계산하는 것과 같다.
그럼 표준화 변수를 만들어보자. R은 파이썬처럼 위에서 만든 평균과 표준편차 변수를 이용하여 각 열 별로 계산이 되지 않는 걸 발견하였다. 그래서 열 별로 따로 지정해서 만들어 주어야 했다.
그런데 R은 표준화를 시킬 수 있는 특별한 함수가 있다. scale() 함수이다. 이것은 열 별로 따로 지정해주지 않아도 되었다.
정규화는 모든 데이터를 0~1 사이로 만들어주는 것이다. max와 min을 먼저 변수로 만든 후 새로운 정규화 변수를 만든다. 모든 값들이 0과 1 사이로 잘 변환된 것을 알 수 있었다.
R에서 정규화를 할 때, 표준화처럼 특별한 함수는 없다. 따라서 정규화 함수를 만든 후 빈 2열의 matrix에 이 함수를 적용시켜 1열은 길이, 2열은 무게에 대한 정규화를 진행하고, boxplot으로 그려보았다. 빈 matrix를 만들지 않고 진행할 경우, 에러가 났다.
그럼 지난번에 했던 것처럼 이 표준화와 정규화된 변수들을 이용하여 KNN으로 학습을 시킨 후 특정 값 (길이, 무게) = (25, 150)이 도미인지 빙어인지 알아맞추어 보도록 하겠다.
빙어를 0으로 도미를 1로 Target 변수를 만든 후, 표준화, 정규화된 데이터 세트를 통해 train, test 세트로 나누어보자. 49행을 34개와 15개로 나누되, 표준화 변수와 정규화 변수를 각각 만들어 보았다.
그러면 표준화를 한 상태에서 train, test, 알고자 하는 점(new)을 그래프로 그려보자. (길이, 무게) = (25, 150) 은 아래 그래프를 보면 도미 그룹에 속한 것일 수 있음을 알 수 있다.
다음으로 KNN으로 train 데이터를 학습시킨 후, test 데이터가 잘 맞는지 score를 구해 보자. 매우 잘 학습된 모델임을 알 수 있다.
그러면 new 값이 도미인지 빙어인지 알아보자. (빙어 : 0, 도미 : 1)
도미로 잘 예측하였음을 알 수 있다.
똑같은 방법으로 정규화된 변수로 학습시킨 데이터 셋으로 해 보자. 표준화 때와 마찬가지고 new2 값이 도미 쪽에 그려짐을 알 수 있다.
그럼 이것도 KNN으로 학습시킨 후 알아맞혀 보자. 표준화 때보다 score가 낮아지긴 했으나 new2 위치가 도미라는 것을 정확히 예측할 수 있었다.
한 발짝 더 나아가 보자.
new와 new2는 KNN 모델에서, 최근접 5점을 통해 도미인지 빙어인지 알아맞힌다고 했을 때, 어떤 점들을 보고 도미인 줄 알았을까?
distances, indexes를 통해 5개의 점과 new, new2사이와의 거리를 알아내었다.
R은 파이썬과 다르게, Target을 datafram으로 뭉쳐놓고, train, test로 나눈 후, 학습시킨다.
그럼 표준화, 정규화된 이 데이터 세트를 7:3으로 나누어보자.
c(25, 150) 값도 표준화, 정규화를 해 보자. 파이썬과 다르게 R은 열 별로 계산해주어야 했다.
그럼 train 값을 KNN으로 학습시켜 test를 검증하고 얼마나 잘 맞는지 살펴보자. 표준화 및 정규화 모델을 각각 학습시켜, test 데이터 셋을 검증했을 때, 모두 잘 맞았다. R은 파이썬의 score 함수가 없기 때문에 table() 함수를 써서 맞은 비율을 구했다.
다음으로 R에서도 표준화 변환 후 그래프로 train, test, new를 그려보자
아래는 정규화 변환 후 그래프
그럼 마지막으로 (길이, 무게)=(50,150)인 녹색점이 도미인지 빙어인지 알아맞혀 보자.
표준화, 정규화 두 모델 모두 도미로 잘 예측하였다.
다만 R에서는 파이썬에서 했던 것처럼 인접 5개의 점의 위치를 찾는 방법을 찾지 못했다.
[표준화,정규화 파이썬 코드]
https://colab.research.google.com/drive/1MeiwgX-lAw0kRGbFDcp-CACwmN8jzxzA?usp=sharing
[표준화,정규화 R 코드]
https://colab.research.google.com/drive/1gSN9ufhEcHT1s1oXn7BAzZ660SXYs74X?usp=sharing