회사에서는 ML을 이제 직접 도입해서 프로덕트 레벨에서 태워보자 이런 단계이지만,
말이 ML이고 머신러닝이지 쉬운게 아니다.
책에서야 뭐 간단하게 훑는 정도지만, 현업에서는 그냥 회사 두개가 협동하든, 대학원이랑 산하협력을 하든.. 쉬운게 아니당..
지금 회사에서는 더 복잡하고 힘든걸 작업하고 리서치하고있지만,
혼공머신 이 책이든 다른 책들이든 다 하나하나 집고 가려고한다.
이유는? 내가 기본이 맨날 부족하다고 느끼니까.
책 볼 시간도 없었나,, 한참 밀렸으니 속도 내보자.
생선놈들의 길이와 무게 리스트를 먼저 다시 확인해보자.
fish_length = [25.4, 26.3, 26.5, 29.0, 29.0, 29.7, 29.7, 30.0, 30.0, 30.7, 31.0, 31.0,
31.5, 32.0, 32.0, 32.0, 33.0, 33.0, 33.5, 33.5, 34.0, 34.0, 34.5, 35.0,
35.0, 35.0, 35.0, 36.0, 36.0, 37.0, 38.5, 38.5, 39.5, 41.0, 41.0, 9.8,
10.5, 10.6, 11.0, 11.2, 11.3, 11.8, 11.8, 12.0, 12.2, 12.4, 13.0, 14.3, 15.0]
fish_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 450.0, 500.0, 475.0, 500.0,
500.0, 340.0, 600.0, 600.0, 700.0, 700.0, 610.0, 650.0, 575.0, 685.0, 620.0, 680.0,
700.0, 725.0, 720.0, 714.0, 850.0, 1000.0, 920.0, 955.0, 925.0, 975.0, 950.0, 6.7,
7.5, 7.0, 9.7, 9.8, 8.7, 10.0, 9.9, 9.8, 12.2, 13.4, 12.2, 19.7, 19.9]
위의 해당 리스트를 보면
길이와 무게로 나뉘어져 있는데, 이를 행렬형태로 변경이 필요하다.
한마리를 조회했을때 길이와 무게가 같이 나오게 하려는 목적으로.
그럴때 이 책에서 사용하는 것이 column_stack() 함수.
fish_data = np.column_stack((fish_length, fish_weight))
print(fish_data[:5])
깔끔하게 두개의 열로 절리가 되었다.
다음으로 이 49의 물고기 데이터를 통해 타깃 데이터를 만들어 줘야한다는데,
1, 0을 통해 구분을 할때
손쉽게 concatenate() 함수를 사용해서 타깃 데이터를 만들 수 있다.
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
print(fish_target)
두개의 함수를 통해서 손쉽게? 넘파이 배열의 인덱스를 직접 섞어서 훈련과 테스트 셋으로 나눈건데,,,
이것보다 더 좋은 방식이 sklearn에 있다.
train_test_split()함수를 통해서 리스트나 배열을 비율에 맞게 바로 훈련,테스트 세트로 나누어준다.
나누고싶은 리스트나 배열을 함수에 바로 넣어주고 random_state 매개변수를 통해 랜덤시드를 자체적으로도 지정이 가능하다.
또한 샘플림 편향을 조절해주기 위해서 stratify 매개변수를 통해서 클래스 비율도 조정이 가능하다.
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(
fish_data, fish_target, stratify = fish_target, random_state= 42
)
#임의로 랜덤시드 42를 지정해줌
print(test_target)
원래부터 도미가 더 많았기 때문에, 빙어의 갯수가 정확히 1:1이 될 수는 없다. 그래도 이정도면 괜찮은 비율이니?
책에서 말하는 모든 데이터는 준비 완료가 되었다.
다시 테스트 하기
지난 포스트처럼 k-최근접 이웃을 통해서 스코어를 봐보면..
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
print(kn.predict([[25,150]]))
0.
이라는 스코어가 나온다..
그림을 통해 다시 확인해보면..!
%matplotlib inline #plt.show()를 했는데 이미지가 나오지 않는다면, import절 앞에 해당 구문을 써주면 해결이됨
import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25,150, marker ='^') #도미데이터에 표시를 해주기
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()
오른쪽에 조금 더 가까울 수 있는데, 빙어에 가깝다고 판단을 한것이다.
k-최근접 이웃의 개념을 다시 보면, 주변의 샘플중에서 다수인 클래스를 예측으로 활용하기 때문에 이런 결과가 나온 것으로 보인다.
그럼 저 도미데이터 (세모)에 근첩한 친구들이 뭔지 확인해보는 코드를 작성해보자.
# 거리를 측정하는 indexes를 지정하고
distance, indexes = kn.kneighbors([[25,150]])
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker = '^')
plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D')
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()
n_neighbors의 기본값이 5개이기 때문에 가까웠던 빙어쪽의 4개 샘플를 따라 간것이다..??
이상하지 이상하다..
print(distances)
[[ 92.00086956 130.48375378 130.73859415 138.32150953 138.39320793]]
이런식으로 길이가 나오는데, 실제 측정값의 범위보다 더 적게 나와보인다..
x축의 범위를 y축과 동일하게 나타낸다면 어떻게 나올까?
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker = '^')
plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D')
plt.xlim((0, 1000)) #x축의 범위를 설정해버림
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()
자 다시 보면, 데이터가 모두 수직형태로 나타난다.
즉 생선의 길이는 가까운 이웃(k-최근접)을 사용하는데 크게 영향을 미치지 못하고, 오직 무게(y축)만을 고려해서 예측하게 된것이다..
쉽게말해 두 특성의 스케일이 달랐기 때문이다.
이런 스케일 조정을 해주고 하는 작업을 데이터 전처리 라고 생각하면 된다.
가장 쉬운 방식중에는 표준점수(standard score)를 사용 할 수있는데, 손쉽게 평균을 뺀 후 표준편차로 나누어주면 나온다.
mean = np.mean(train_input, axis = 0)
std = np.std(train_input, axis = 0)
#axis=0인 이유는 특성마다 값의 스케일이 다르기 때문에 평균과 표준 편차는 각 특성별로 계산해야함 -> 행을 따라 각 열의 통계값을 계산하게됨
print(mean, std)
각 train_input에 표준점수를 적용해주고 ,
새롭게 데이터를 넣을 친구에게도 적용한 뒤 다시 그림을 그려보면
#그리고 손쉽게 모든 행에서 계산이 가능함 -> 이런걸 브로드캐스팅이라고도 함
train_scaled = (train_input - mean)/std
new =([25, 150]-mean)/std
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='D')
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()
x축, y축을 보면 조정이 된것을 알 수 있다.
다시한번 평가?를 해보면..!
#훈련을 다시 시키고
kn.fit(train_scaled, train_target)
# 마찬가지로 테스트 세트도 훈련 세트의 평균과 표준편차로 변환해야함
test_scaled = (test_input-mean)/std
print(kn.score(test_scaled, test_target))
print(kn.predict([new]))
1.0
[1.]
스캐일 조정을 하고 나니까 new를 넣어도 맞추는 것을 볼 수 있다.
마지막으로 다시 new데이터와 가까운 5개의 산점도를 표현해보면,
distances, indexes = kn.kneighbors([new])
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.scatter(train_scaled[indexes,0], train_scaled[indexes,1], marker='D')
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()
가까운 데이터들을 잘 따라가는 걸 볼 수 있댱..!
스케일 조정하는거 명심하쟈.
ㅠㅠ
'Machine Learning > ML - 혼공머신' 카테고리의 다른 글
[혼공머신] K-최근접 이웃 회귀 (2) | 2022.11.02 |
---|---|
[혼공머신] 훈련 세트와 테스트 세트 (2) | 2022.09.14 |
[혼공머신] 마켓과 머신러닝 (K-최근접 이웃 알고리즘, KNeighborsClassifier) (0) | 2022.06.06 |
[혼공머신]인공지능과 머신러닝, 딥러닝 (0) | 2022.05.28 |