Study/class note

머신러닝 / 파이썬으로 knn모델 생성하기

chanzae 2022. 2. 3. 14:04

ㅇ복습

1. R 기본문법

2. 머신러닝을 배우기 위한 R의 필요한 기능들

3. KNN(유방암 환자의 양성 종양과 악성 종양을 분류)

 

KNN - 유클리드 거리계산 공식을 이용해서 자기와 가까운 이웃으로 분류하는 것

알고리즘이 이해하기 쉽고 구현하기가 편하다는 장점이 있다. 다만, k값을 모델 설계자가 직접 알아내야함.

 

R패키지중에 class라는 패키지 안에 knn함수를 다운 받아서 우리가 직접 knn을 만들지 않고 누군가 만들어준 함수를 가지고 유방암 데이터를 분류.

 

* 데이터 전처리 과정 설명

1. 결측치 제거하거나 다른 값으로 치환

2. 이상치를 제거하거나 다른 값으로 치환

3. 정규화 또는 표준화 작업을 수행

4. 훈련데이터와 테스트 데이터를 8:2로 분리

5. knn 모델 생성

result <- knn(train = wbcd_train, test=wbcd_test, cl = wbcd_train_label, k = i)

6. knn 모델 평가 (정확도)

 

 

43 파이썬으로 knn모델 생성하기

1. 데이터 로드

# python
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")
wbcd

> 판다스는 R과 다르게 stringsAsFactors = True로 지정하지 않아도 됨(문자형 데이터를 팩터로 바꾸지 않아도 됨)

 

2. 데이터 확인

wbcd.info()  # 컬럼명과 데이터 타입 확인
wbcd.shape  # 행과 열의 갯수 확인
wbcd.describe()  # R에서의 summary() 함수와 같은 결과를 출력

wbcd.info() > diagnosis만 object고 나머지 다른 컬럼들은 모두 숫자형(float or int)
wbcd.shape > 569행 x 32열
wbcd.describe() > 표준편차, 사분위수 범위, 최대/최소값, 건수, 평균 등의 정보를 제공함

 

3. 결측치 확인

wbcd.isnull().sum()

> 컬럼들의 결측치 갯수가 출력됨. 현재 wbcd데이터에는 결측치가 없음.

 

4. 이상치 확인

def outlier_value(x):
    for i in x.columns[x.dtypes == 'float64']:  # 숫자형 컬럼들의 데이터만 가져옴
        Q1 = x[i].quantile(0.25)  # 숫자형 컬럼에서 25%에 해당하는 지점을 Q1에 담음
        Q3 = x[i].quantile(0.75)  # 숫자형 컬럼에서 75%에 해당하는 지점을 Q3에 담음
        IQR = Q3 - Q1  # 사분위수 범위값을 구함
        print(i,x[i][ (x[i] > Q3 + IQR*5) | (x[i] < Q1 - IQR*5) ].count() ) # count로 이상치의 갯수만 확인하겠음
                # 범위의 너비는 1.5로 하면 너무 많은 이상치가 나와서 5로 넓힘. 사용자가 임의로 변경 가능
            
outlier_value(wbcd)

> 보통 IQR*1.5로 하지만 이 데이터에서 그렇게 설정할 경우 너무 많은 이상치가 나와버려서 임의로 변경함. 아주 심한 이상치들을 걸러내려면 5대신에 다른 더 큰 수 넣으면 됨.

> 바로 이상치를 제거하지 않아도 됨. 기계를 학습 시킨 후에 정확도를 평가했을 때 정확도가 너무 낮으면 그때 이상치를 제거하면 됨.

 

5. 문자형 데이터인지 숫자형 데이터인지 확인

wbcd.info()

> 정규화를 위해 확인해야함.

 

6. 데이터를 정규화

from sklearn.preprocessing import MinMaxScaler

wbcd2 = wbcd.iloc[:,2:] # 환자번호(id)와 정답(결과)컬럼인 diagnosis를 제외

scaler = MinMaxScaler()  # 객체로 만듦
scaler.fit(wbcd2) # min/max 정규화 계산을 함

wbcd2_scaled = scaler.transform(wbcd2)  # 위에서 계산한 내용으로 데이터를 변환해서 변수에 넣음
wbcd2_scaled  # numpy array 형태로 변경됨

wbcd2_scaled.shape # (569, 30) 데이터의 갯수가 맞는지 확인

> 판다스 시리즈에서 numpy array로 모든 데이터의 구조가 변경되었음

y = wbcd['diagnosis'].to_numpy()  # 정답(결과)데이터를 numpy로 변경함

 

7. 훈련 데이터와 테스트 데이터로 데이터를 분리(9:1)

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(wbcd2_scaled,y,test_size = 0.1, random_state=1)

>함수에 반드시 numpy array배열로 넣어줘야 함.

x_train : 훈련데이터, x_test : 테스트 데이터

y_train : 훈련데이터의 정답, y_test : 테스트 데이터의 정답

random_state = 1은 어느 자리에서든 동일한 정확도를 보이는 모델을 만들기 위해 설정한 것

test_size = 0.1로 했기 때문에 훈련 90%, 테스트 10%로 나뉨.

print(x_train.shape)  #(512, 30)
print(x_test.shape)  #(57, 30)
print(y_train.shape)  #(512,)
print(y_test.shape)  #(57,)

> 훈련데이터와 테스트 데이터 나뉜 것 확인

 

8. 모델 설정

from sklearn.neighbors import KNeighborsClassifier

model = KNeighborsClassifier(n_neighbors = 5)  # knn모델 생성, k값은 일단 임의로 5 부여

> 적절한 k값은 모델 설계자가 알아내면 됨.

 

9. 모델 훈련

model.fit(x_train, y_train)

> 90%의 훈련데이터로 모델을 훈련 시킴.

 

10. 훈련된 모델로 테스트 데이터 예측

result = model.predict(x_test)
result

 

11. 모델 평가

y_test == result

> 실제값과 예측값을 비교하면 True, False로 나뉘어져서 값이 출력됨.

sum(y_test == result)/57*100

> 정확도 만들어서 출력하기 

함수를 이용해서 정확도 출력해도 됨

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, result)  #accuracy_score(실제값, 예측값)
accuracy

 

12. 모델의 성능 높이기

k= 5일때, 정확도 98%가 나옴. 어떤 것이 틀렸는지 확인해야함.

from sklearn.metrics import confusion_matrix

a = confusion_matrix(y_test, result)
print(a)

[[43  0]
 [ 1 13]]

tn,fp,fn,tp = confusion_matrix(y_test,result,labels = ['B','M']).ravel()
print(tn,fp,fn,tp)

 

43 0 1 13

> labels = ['B','M']을 설정하면 관심범주를 설정할 수 있음. ( labels = ['관심범주 아닌 것','관심범주인 것'] )

여기서의 관심범주는 'M'(악성종양)

 

ㅇ이원 교차표 설명 -p.138

  예측
정상
실제 정상 43(TN) 0(FP)
1(FN) 13(TP)

우리의 관심범주? = 암

정상환자를 잘 찾는 기계보다는 암환자를 잘 찾는 기계를 만드는게 중요하기 때문에 관심범주는 "암"

positive = 관심범주(1이 관심범주)

TP : True 잘 판단했다 / Positive : 암환자로 => 암환자로 잘 판단함 => (암환자를) 암환자로 잘 판단함

FP : False 잘못 판단했다 / Positive : 암환자로 => 암환자로 잘못 판단함 => (정상환자를) 암환자로 잘못 판단함

TN : True 잘 판단했다 / Negative : 정상환자로 => 정상환자로 잘 판단함 => (정상환자를) 정상환자로 잘 판단함

FN : False 잘못 판단했다 / Negative : 정상환자로 = > 정상환자로 잘못 판단함 => (암환자를) 정상환자로 잘못 판단함

 

 

 

FN, FP모두 0이 나오는게 중요함. 특히 의료쪽에서는 FN이 0이 나오는게 정확도보다 중요함.

 

 

- p.142 

k값 거짓부정(FN) 거짓긍정(FP) 부정확하게 분류된 백분율
1 1 3 4%
5 2 0 2%
11 3 0 3%
15 3 0 3%
21 2 0 2%
27 4 0 4%

 

문제236. 위의 유방암의 악성 종양을 판별하는 KNN 모델 전체코드를 다시 하나로 모아서 수행하시오.

# 1. 데이터 로드
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")

# 2. 데이터 확인
#wbcd.info()
#wbcd.shape
#wbcd.describe()

# 3. 결측치 확인
# wbcd.isnull().sum()

# 4. 이상치 함수생성
def outlier_value(x):
    for i in x.columns[x.dtypes == 'float64']:  # 숫자형 컬럼들의 데이터만 가져옴
        Q1 = x[i].quantile(0.25)  # 숫자형 컬럼에서 25%에 해당하는 지점을 Q1에 담음
        Q3 = x[i].quantile(0.75)  # 숫자형 컬럼에서 75%에 해당하는 지점을 Q3에 담음
        IQR = Q3 - Q1  # 사분위수 범위값을 구함
        print(i,x[i][ (x[i] > Q3 + IQR*5) | (x[i] < Q1 - IQR*5) ].count() ) # count로 이상치의 갯수만 확인하겠음
                # 범위의 너비는 1.5로 하면 너무 많은 이상치가 나와서 5로 넓힘. 사용자가 임의로 변경 가능
            
# outlier_value(wbcd) #이상치 확인

# 5. 정규화
from sklearn.preprocessing import MinMaxScaler

wbcd2 = wbcd.iloc[:,2:] # 환자번호(id)와 정답(결과)컬럼인 diagnosis를 제외

scaler = MinMaxScaler()  # 객체로 만듦
scaler.fit(wbcd2) # min/max 정규화 계산을 함

wbcd2_scaled = scaler.transform(wbcd2)  # 위에서 계산한 내용으로 데이터를 변환해서 변수에 넣음
wbcd2_scaled  # numpy array 형태로 변경됨

wbcd2_scaled.shape # (569, 30) 데이터의 갯수가 맞는지 확인

y = wbcd['diagnosis'].to_numpy()  # 정답(결과)데이터를 numpy로 변경함


# 6. 훈련데이터와 테스트 데이터 나누기
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(wbcd2_scaled,y,test_size = 0.1, random_state=1)


# 7. KNN 모델 생성 
from sklearn.neighbors import KNeighborsClassifier

model = KNeighborsClassifier(n_neighbors = 5)  # knn모델 생성, k값은 일단 임의로 5 부여

# 8. 모델 훈련
model.fit(x_train, y_train)

# 9. 테스트 데이터 실시
result = model.predict(x_test)
result

# 10. 모델 성능평가
y_test == result

# 정확도1
# sum(y_test == result)/57*100

# 정확도2
# from sklearn.metrics import accuracy_score
# accuracy = accuracy_score(y_test, result)
# accuracy

# 11. 이원교차표 확인
from sklearn.metrics import confusion_matrix

a = confusion_matrix(y_test, result)
print(a)

tn,fp,fn,tp = confusion_matrix(y_test,result,labels = ['B','M']).ravel()
print(tn,fp,fn,tp)

 

+) FN이 0인 k값 찾는 코드

# 1. 데이터 로드
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")

# 2. 데이터 확인
#wbcd.info()
#wbcd.shape
#wbcd.describe()

# 3. 결측치 확인
# wbcd.isnull().sum()

# 4. 이상치 함수생성
def outlier_value(x):
    for i in x.columns[x.dtypes == 'float64']:  # 숫자형 컬럼들의 데이터만 가져옴
        Q1 = x[i].quantile(0.25)  # 숫자형 컬럼에서 25%에 해당하는 지점을 Q1에 담음
        Q3 = x[i].quantile(0.75)  # 숫자형 컬럼에서 75%에 해당하는 지점을 Q3에 담음
        IQR = Q3 - Q1  # 사분위수 범위값을 구함
        print(i,x[i][ (x[i] > Q3 + IQR*5) | (x[i] < Q1 - IQR*5) ].count() ) # count로 이상치의 갯수만 확인하겠음
                # 범위의 너비는 1.5로 하면 너무 많은 이상치가 나와서 5로 넓힘. 사용자가 임의로 변경 가능
            
# outlier_value(wbcd) #이상치 확인

# 5. 정규화
from sklearn.preprocessing import MinMaxScaler

wbcd2 = wbcd.iloc[:,2:] # 환자번호(id)와 정답(결과)컬럼인 diagnosis를 제외

scaler = MinMaxScaler()  # 객체로 만듦
scaler.fit(wbcd2) # min/max 정규화 계산을 함

wbcd2_scaled = scaler.transform(wbcd2)  # 위에서 계산한 내용으로 데이터를 변환해서 변수에 넣음
wbcd2_scaled  # numpy array 형태로 변경됨

wbcd2_scaled.shape # (569, 30) 데이터의 갯수가 맞는지 확인

y = wbcd['diagnosis'].to_numpy()  # 정답(결과)데이터를 numpy로 변경함


# 6. 훈련데이터와 테스트 데이터 나누기
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(wbcd2_scaled,y,test_size = 0.1, random_state=3)


# 7. KNN 모델 생성 
from sklearn.neighbors import KNeighborsClassifier

for i in range(1,512,2):
    model = KNeighborsClassifier(n_neighbors = i)  # knn모델 생성, k값은 일단 임의로 5 부여

    # 8. 모델 훈련
    model.fit(x_train, y_train)

    # 9. 테스트 데이터 실시
    result = model.predict(x_test)
    result

    # 10. 모델 성능평가
    y_test == result

    # 정확도1
    # sum(y_test == result)/57*100

    # 정확도2
    # from sklearn.metrics import accuracy_score
    # accuracy = accuracy_score(y_test, result)
    # accuracy

    # 11. 이원교차표 확인
    from sklearn.metrics import confusion_matrix

    a = confusion_matrix(y_test, result)
#     print(a)

    tn,fp,fn,tp = confusion_matrix(y_test,result,labels = ['B','M']).ravel()
    if fn == 0:
        print('k값이 ',i,'일때, FN이 0입니다.')

> FN이 0이 나오지 않는다면 random_state를 바꿔서 다시 실행해보면 됨.

 

문제237. 테스트 데이터의 정확도도 함께 출력하시오

# 1. 데이터 로드
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")

# 2. 데이터 확인
#wbcd.info()
#wbcd.shape
#wbcd.describe()

# 3. 결측치 확인
# wbcd.isnull().sum()

# 4. 이상치 함수생성
def outlier_value(x):
    for i in x.columns[x.dtypes == 'float64']:  # 숫자형 컬럼들의 데이터만 가져옴
        Q1 = x[i].quantile(0.25)  # 숫자형 컬럼에서 25%에 해당하는 지점을 Q1에 담음
        Q3 = x[i].quantile(0.75)  # 숫자형 컬럼에서 75%에 해당하는 지점을 Q3에 담음
        IQR = Q3 - Q1  # 사분위수 범위값을 구함
        print(i,x[i][ (x[i] > Q3 + IQR*5) | (x[i] < Q1 - IQR*5) ].count() ) # count로 이상치의 갯수만 확인하겠음
                # 범위의 너비는 1.5로 하면 너무 많은 이상치가 나와서 5로 넓힘. 사용자가 임의로 변경 가능
            
# outlier_value(wbcd) #이상치 확인

# 5. 정규화
from sklearn.preprocessing import MinMaxScaler

wbcd2 = wbcd.iloc[:,2:] # 환자번호(id)와 정답(결과)컬럼인 diagnosis를 제외

scaler = MinMaxScaler()  # 객체로 만듦
scaler.fit(wbcd2) # min/max 정규화 계산을 함

wbcd2_scaled = scaler.transform(wbcd2)  # 위에서 계산한 내용으로 데이터를 변환해서 변수에 넣음
wbcd2_scaled  # numpy array 형태로 변경됨

wbcd2_scaled.shape # (569, 30) 데이터의 갯수가 맞는지 확인

y = wbcd['diagnosis'].to_numpy()  # 정답(결과)데이터를 numpy로 변경함


# 6. 훈련데이터와 테스트 데이터 나누기
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(wbcd2_scaled,y,test_size = 0.1, random_state=3)


# 7. KNN 모델 생성 
from sklearn.neighbors import KNeighborsClassifier

for i in range(1,512,2):
    model = KNeighborsClassifier(n_neighbors = i)  # knn모델 생성, k값은 일단 임의로 5 부여

    # 8. 모델 훈련
    model.fit(x_train, y_train)

    # 9. 테스트 데이터 실시
    result = model.predict(x_test)
    result

    # 10. 모델 성능평가
    y_test == result

    # 정확도1
    #sum(y_test == result)/57*100

    # 정확도2
    from sklearn.metrics import accuracy_score
    accuracy = accuracy_score(y_test, result)

    # 이원교차표 확인
    from sklearn.metrics import confusion_matrix

    a = confusion_matrix(y_test, result)
#     print(a)

    tn,fp,fn,tp = confusion_matrix(y_test,result,labels = ['B','M']).ravel()
    if fn == 0:
        print('k값이 %d 일때, FN이 0입니다. 정확도는 %s 입니다'%(i,accuracy))

 

문제238. 파이썬 자동화 코드 17번에 점심시간 문제 코드를 추가하시오.

knn = """# 1. 데이터 로드
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")

# 2. 데이터 확인
#wbcd.info()
#wbcd.shape
#wbcd.describe()

# 3. 결측치 확인
# wbcd.isnull().sum()

# 4. 이상치 함수생성
def outlier_value(x):
    for i in x.columns[x.dtypes == 'float64']:  # 숫자형 컬럼들의 데이터만 가져옴
        Q1 = x[i].quantile(0.25)  # 숫자형 컬럼에서 25%에 해당하는 지점을 Q1에 담음
        Q3 = x[i].quantile(0.75)  # 숫자형 컬럼에서 75%에 해당하는 지점을 Q3에 담음
        IQR = Q3 - Q1  # 사분위수 범위값을 구함
        print(i,x[i][ (x[i] > Q3 + IQR*5) | (x[i] < Q1 - IQR*5) ].count() ) # count로 이상치의 갯수만 확인하겠음
                # 범위의 너비는 1.5로 하면 너무 많은 이상치가 나와서 5로 넓힘. 사용자가 임의로 변경 가능
            
# outlier_value(wbcd) #이상치 확인

# 5. 정규화
from sklearn.preprocessing import MinMaxScaler

wbcd2 = wbcd.iloc[:,2:] # 환자번호(id)와 정답(결과)컬럼인 diagnosis를 제외

scaler = MinMaxScaler()  # 객체로 만듦
scaler.fit(wbcd2) # min/max 정규화 계산을 함

wbcd2_scaled = scaler.transform(wbcd2)  # 위에서 계산한 내용으로 데이터를 변환해서 변수에 넣음
wbcd2_scaled  # numpy array 형태로 변경됨

wbcd2_scaled.shape # (569, 30) 데이터의 갯수가 맞는지 확인

y = wbcd['diagnosis'].to_numpy()  # 정답(결과)데이터를 numpy로 변경함


# 6. 훈련데이터와 테스트 데이터 나누기
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(wbcd2_scaled,y,test_size = 0.1, random_state=3)


# 7. KNN 모델 생성 
from sklearn.neighbors import KNeighborsClassifier

for i in range(1,512,2):
    model = KNeighborsClassifier(n_neighbors = i)  # knn모델 생성, k값은 일단 임의로 5 부여

    # 8. 모델 훈련
    model.fit(x_train, y_train)

    # 9. 테스트 데이터 실시
    result = model.predict(x_test)
    result

    # 10. 모델 성능평가
    y_test == result

    # 정확도1
    #sum(y_test == result)/57*100

    # 정확도2
    from sklearn.metrics import accuracy_score
    accuracy = accuracy_score(y_test, result)

    # 이원교차표 확인
    from sklearn.metrics import confusion_matrix

    a = confusion_matrix(y_test, result)
     #print(a)

    tn,fp,fn,tp = confusion_matrix(y_test,result,labels = ['B','M']).ravel()
    if fn == 0:
        print('k값이 %d 일때, FN이 0입니다. 정확도는 %s 입니다'%(i,accuracy)) """

print(knn)

 

 

p.143 knn은 많은 분류 알고리즘과 달리 어떤 학습도 하지 않음. 단순히 훈련 데이터를 글자 그대로 저장함. 라벨링된 훈련 데이터를 펼쳐놓고 그 위에 테스트 데이터를 뿌려서 k개에 따른 가장 가까운 이웃을 자기 자신으로 분류하는 것.

반응형