안녕하세요!

데이터 분류하기 2 본문

개발일지/ML(Machine Learning),DL(Deep Learning)

데이터 분류하기 2

shinyfood 2023. 12. 22. 08:44
728x90
반응형

https://shinyfood.tistory.com/85

 

머신러닝 training & test

훈련과 검증 테스트데이터 분류 - 정의된 변수 이름은 없음 - 훈련데이터 : 훈련(fit)에 사용되는 데이터 : (훈련 독립변수) train_input, train_x, X_train : (훈련 종속변수) train_target, train_y, y_train - 검증

shinyfood.tistory.com

해당글과 이어집니다.

 

print(fish_length, fish_weight)

[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] [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]

2차원 데이터 생성하기 // numpy에서 column_stack은 튜플로 묶어 넣어주면 zip처럼 리스트로 변환해준다.
fish_data = np.column_stack((fish_length, fish_weight))
fish_data


1차원 데이터 생성하기 // 튜플로 만들고 ones와 zeros를 사용하면 1이 35개 0이 14개 나온다. 그것을 concatenate 를 사용하면 합쳐진다.
fish_target = np.concatenate((np.ones(35),np.zeros(14)))
fish_target

 

(array([[  25.4,  242. ],        [  26.3,  290. ],        [  26.5,  340. ],        [  29. ,  363. ],
        [  29. ,  430. ],        [  29.7,  450. ],        [  29.7,  500. ],        [  30. ,  390. ],
        [  30. ,  450. ],        [  30.7,  500. ],        [  31. ,  475. ],        [  31. ,  500. ],
        [  31.5,  500. ],        [  32. ,  340. ],        [  32. ,  600. ],        [  32. ,  600. ],
        [  33. ,  700. ],        [  33. ,  700. ],        [  33.5,  610. ],        [  33.5,  650. ],
        [  34. ,  575. ],        [  34. ,  685. ],        [  34.5,  620. ],        [  35. ,  680. ],
        [  35. ,  700. ],        [  35. ,  725. ],        [  35. ,  720. ],        [  36. ,  714. ],
        [  36. ,  850. ],        [  37. , 1000. ],        [  38.5,  920. ],        [  38.5,  955. ],
        [  39.5,  925. ],        [  41. ,  975. ],        [  41. ,  950. ],        [   9.8,    6.7],
        [  10.5,    7.5],        [  10.6,    7. ],        [  11. ,    9.7],        [  11.2,    9.8],
        [  11.3,    8.7],        [  11.8,   10. ],        [  11.8,    9.9],        [  12. ,    9.8],
        [  12.2,   12.2],        [  12.4,   13.4],        [  13. ,   12.2],        [  14.3,   19.7],
        [  15. ,   19.9]]),
 array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]))

데이터 섞으면서 분류하기

 랜덤하게 섞으면서 두개(훈련 : 테스트)의 데이터로 분류해주는 train_test_split을 사용하자.
from sklearn.model_selection import train_test_split

 

train_input, test_input, train_target, test_target =train_test_split(fish_data, fish_target,
                                                     test_size=0.3, random_state=42,
                                                     stratify = fish_target)

print(f"{train_input.shape},{train_target.shape},{test_input.shape},{test_target.shape}")

(34, 2),(34,),(15, 2),(15,)

모델(클래스) 생성하기

kn = KNeighborsClassifier(n_neighbors=5)

 

모델 훈련 시키기

kn.fit(train_input, train_target)

 

훈련 정확도 확인하기
train_score = kn.score(train_input, train_target)

 

검증 정확도 확인하기
test_score = kn.score(test_input, test_target)

 

 과대적합 : 훈련 > 검증 또는 훈련이 1인 경우
 과소적합 : 훈련 < 검증  또는 검증이 1인 경우
 과소적합이 일어나는 모델은 사용할 수 없음.
 과대적합 중에 훈련 정확도가 1인 경우의 모델은 사용할 수 없음
 과대적합이 보통 0.1 이상의 차이를 보이면 정확도의 차이가 많이 난다고 의심해 볼수 있음.

 모델 선정 기준 : 과소적합이 일어나지 않으면서, 
               : 훈련 정확도가 1이 아니고,
               : 훈련과 검증의 차이가 0.1 이내인 경우
 선정된 모델을 "일반화 모델"이라고 칭합니다.
 다만, 추가로 선정 기준 중에 평가기준이 있음. 

가장 바람직한 결과는 훈련 > 검증 > 테스트
(훈련 > 검증 < 테스트인 경우도 있음.)

매우매우매우매우매우 중요하다.

 

이후 지난 글처럼 이웃의 숫자를 찾아준다.

### 1보다 작은 가장 좋은 정확도일 때의 이웃의 개수 찾기
### 모델 클래스 생성
kn = KNeighborsClassifier()

### 훈련시키기
kn.fit(train_input, train_target)

### 1보다 작은 가장 좋은 정확도일 때의 이웃의 개수 찾기
# - 반복문 사용 : 범위는 3~ 전체 데이터 개수

### 정확도가 가장 높을 때의 이웃 개수를 담을 변수
nCnt = 0
### 정확도가 가장 높을때의 값을 담을 변수
nScore = 0

for n in range(3, len(train_input), 2) :
    kn.n_neighbors = n
    score = kn.score(train_input, train_target)
    print(f"{n} / {score}")

    ### 1보다 작은 정확도인 경우..
    if score < 1 :
        ### nScore의 값이 score보다 작은 경우 담기
        if nScore < score :
            nScore = score
            nCnt = n

print(f"nCnt = {nCnt}, nScore={nScore}")

### 모델의 성능이 가장 좋은 시점의 이웃의 개수를 추출하기 위한
# 하이퍼파라메터 튜닝 결과, 이웃의 개수 19개를 사용했을 때,
# 가장 좋은 성능을 발휘하는것으로 확인됨.
3 / 1.0
5 / 1.0
7 / 1.0
9 / 1.0
11 / 1.0
13 / 1.0
15 / 1.0
17 / 1.0
19 / 1.0
21 / 0.7058823529411765
23 / 0.7058823529411765
25 / 0.7058823529411765
27 / 0.7058823529411765
29 / 0.7058823529411765
31 / 0.7058823529411765
33 / 0.7058823529411765
nCnt = 21, nScore=0.7058823529411765

 

 임의 데이터로 테스트
dist, indexes = kn.kneighbors([[25,150]])
indexes

array([[29, 16, 26,  0, 11,  9,  6, 21, 23, 19, 30, 14, 32,  8, 27, 12,
        10,  3, 17,  1,  4, 22,  2, 31, 15, 28, 24,  7,  5, 25, 20, 18,
        33]], dtype=int64)
plt.scatter(train_input[:,0], train_input[:, 1] , c="red", label="fish")
plt.scatter(25,150, marker="^", c="green", label="pred")
plt.scatter(train_input[indexes, 0], train_input[indexes, 1], c="blue", label="nei")

plt.xlabel("length")
plt.ylabel("weight")
plt.title("FISH", fontsize=20, fontweight=10)
plt.legend()
plt.show()

예측 결과는 빙어로 확인되었으나,
시각적으로 확인하였을 때는 도미에 더 가까운 것으로 확인됨.
실제 이웃을 확인한 결과 빙어쪽 이웃을 모두 사용하고 있음
 → 이런 현상이 발생한 원인 : 스케일(x축과 y축의 단위)이 다르기 때문에 나타나는 현상
 → "스케일이 다르다" 라고 표현합니다.

해소방법 : 데이터 정규화 전처리를 수행해야함.

사용된 이웃 확인하기

앞의 array는 거리값.
뒤의 array는 index
kn.kneighbors([[25,150]])

(array([[130.48375378, 130.73859415, 138.32150953, 138.39320793,
         140.80142045, 140.87753547, 141.96260071, 143.23581954,
         143.7232062 , 144.10388614, 190.12890364, 213.03755537,
         240.05207768, 280.02856997, 300.04166377, 325.0553799 ,
         350.03155572, 350.04641121, 350.06035194, 450.05444115,
         450.05444115, 460.07852591, 470.09600083, 500.07224478,
         550.05817874, 550.05817874, 550.09090158, 564.1072593 ,
         570.08771255, 575.08694995, 700.08642324, 775.13563329,
         825.15513693]]),
 array([[29, 16, 26,  0, 11,  9,  6, 21, 23, 19, 30, 14, 32,  8, 27, 12,
         10,  3, 17,  1,  4, 22,  2, 31, 15, 28, 24,  7,  5, 25, 20, 18,
         33]], dtype=int64))

정규화하기

앞서 스케일이 다른것을 확인했기 때문에 정규화를 진행하여 값을 맞춰준다

 

정규화 → 표준점수화
표준점수 = (각 데이터 - 데이터 전체 평균) / 데이터 전체 표준편차
표준점수 : 각 데이터가 원점(0)에서 표준편차 만큼 얼마나 떨어져 있는지를 나타내는 값

 

데이터 전체 표준편차 구하기
std = np.std(train_input, axis=0)
std

array([ 10.0816099 , 319.21122132])

 

정규화(표준점수) 처리하기
train_scaled = (train_input - mean) / std
train_scaled

array([[-1.4703534 , -1.35773091],
       [ 0.49361864,  0.48368306],
       [ 0.74159491,  0.54633749],
        ......
       [ 0.29523763, -0.17418855],
       [ 1.38633321,  1.65845379]])

 

plt.scatter(train_scaled[:,0], train_scaled[:, 1] , c="red", label="fish")
plt.scatter(25,150, marker="^", c="green", label="pred")
plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], c="blue", label="nei")

plt.xlabel("length")
plt.ylabel("weight")
plt.title("FISH", fontsize=20, fontweight=10)
plt.legend()
plt.show()

훈련 및 테스트 데이터만 정규화 된 모습.

예측값 스케일을 맞추자
new = ([25,150] - mean) / std
new

array([-0.20071491, -0.92604182])

std값이 어떻게되길래 저렇게 나오는지 잘 몰라서 찾아봤다.

plt.scatter(train_scaled[:,0], train_scaled[:, 1] , c="red", label="fish")
plt.scatter(new[0],new[1], marker="^", c="green", label="pred")
plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], c="blue", label="nei")

plt.xlabel("length")
plt.ylabel("weight")
plt.title("FISH", fontsize=20, fontweight=10)
plt.legend()
plt.show()

 

정규화가 진행된 이후에 그래프를 다시 그려보면

 

모델(클래스) 생성하기
kn = KNeighborsClassifier()

모델 훈련하기
kn.fit(train_scaled, train_target)

 

모델(클래스) 생성하기
kn = KNeighborsClassifier()


모델 훈련하기
kn.fit(train_scaled, train_target)

1.0

 

테스트 데이터로 검증하기(평균과 표준편차는 훈련에서 사용한 값을 그대로 사용한다.)
 - 검증 또는 테스트 데이터를 스케일링 정규화 처리
 - 이때는 훈련에서 사용한 mean과 std를 그대로 사용해야 함.
test_scaled = (test_input - mean) / std
test_score = kn.score(test_scaled, test_target)
test_score

1.0

 

예측하기 
 - 2차원으로 만들어줘야함.
kn.predict([new])

array([1.])

 

이웃 확인하고 시각화 하기
dist, indexes = kn.kneighbors([new])
indexes

array([[14, 32, 30,  8, 27]], dtype=int64)
plt.scatter(train_scaled[:,0], train_scaled[:, 1] , c="red", label="fish")
plt.scatter(new[0],new[1], marker="^", c="green", label="pred")
plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], c="blue", label="nei")

plt.xlabel("length")
plt.ylabel("weight")
plt.title("nei nei FISH", fontsize=20, fontweight=10)
plt.legend()
plt.show()

728x90
반응형