KNN+交叉驗(yàn)證
復(fù)習(xí)
- 機(jī)器學(xué)習(xí)概述
- 概念
- 樣本
- 特征工程
- 概念
- 作用
- 特征抽取
- 特征值化
- one-hot
- jieba分詞
- 特征的預(yù)處理
- 歸一化
- 標(biāo)準(zhǔn)化
- 特征選擇
- PCA
- 方差過(guò)濾
- 機(jī)器學(xué)習(xí)基礎(chǔ)
- 數(shù)據(jù)集的獲取
- sklearn
- 數(shù)據(jù)集的切分
- 訓(xùn)練集
- 測(cè)試集
- 數(shù)據(jù)類型
- 離散型
- 連續(xù)性
- 回歸問(wèn)題
- 回歸模型
- 分類問(wèn)題
- 分類模型
- 數(shù)據(jù)集的獲取
KNN分類模型
分類:將一個(gè)未知?dú)w類的樣本歸屬到某一個(gè)已知的類群中
預(yù)測(cè):可以根據(jù)數(shù)據(jù)的規(guī)律計(jì)算出一個(gè)未知的數(shù)據(jù)
-
概念:
- K-近鄰算法采用測(cè)量不同特征值之間的距離方法進(jìn)行分類(k-Nearest Neighbor,KNN)
k值的作用及取值
k值:模型的超參數(shù)
模型的超參數(shù):如果模型類中的相關(guān)參數(shù)的不同,會(huì)導(dǎo)致分類或者回歸效果的不同
- K值較小瞳遍,則模型復(fù)雜度較高似扔,容易發(fā)生過(guò)擬合,學(xué)習(xí)的估計(jì)誤差會(huì)增大辆毡,預(yù)測(cè)結(jié)果對(duì)近鄰的實(shí)例點(diǎn)非常敏感赞赖。
- K值較大可以減少學(xué)習(xí)的估計(jì)誤差,但是學(xué)習(xí)的近似誤差會(huì)增大通砍,與輸入實(shí)例較遠(yuǎn)的訓(xùn)練實(shí)例也會(huì)對(duì)預(yù)測(cè)起作用贾铝,使預(yù)測(cè)發(fā)生錯(cuò)誤,k值增大模型的復(fù)雜度會(huì)下降埠帕。
- 在應(yīng)用中垢揩,k值一般取一個(gè)比較小的值,通常采用交叉驗(yàn)證法來(lái)來(lái)選取最優(yōu)的K值敛瓷。
適用場(chǎng)景
- 小數(shù)據(jù)場(chǎng)景叁巨,樣本為幾千,幾萬(wàn)的
歐幾里得距離(Euclidean Distance)
常見(jiàn)距離量度呐籽,衡量多維空間中各個(gè)點(diǎn)之間的絕對(duì)距離
歐幾里得距離.png
#案例:電影分類
import pandas as pd
df=pd.read_excel('./datasets/my_films.xlsx') #讀數(shù)據(jù)
df.head()
feature=df[['Action Lens','Love Lens']] #特征
target=df['target'] #標(biāo)簽
from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier(n_neighbors=3) #k=3
knn.fit(feature,target) #訓(xùn)練
#使用模型做分類
knn.predict([[60,55]])#測(cè)試電影類型 ['Action Lens','Love Lens'] 二維數(shù)組
#輸出結(jié)果:
array(['Action'], dtype=object)
算法描述:
1)計(jì)算測(cè)試數(shù)據(jù)與各個(gè)訓(xùn)練數(shù)據(jù)之間的距離锋勺;
2)按照距離的遞增關(guān)系進(jìn)行排序;
3)選取距離最小的K個(gè)點(diǎn)狡蝶;
4)確定前K個(gè)點(diǎn)所在類別的出現(xiàn)頻率庶橱;
5)返回前K個(gè)點(diǎn)中出現(xiàn)頻率最高的類別作為測(cè)試數(shù)據(jù)的預(yù)測(cè)分類。
在scikit-learn庫(kù)中使用k-近鄰算法
分類問(wèn)題:from sklearn.neighbors import KNeighborsClassifier
鳶尾花分類的實(shí)現(xiàn)
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
import sklearn.datasets as datasets
from sklearn.model_selection import train_test_split
#1.捕獲鳶尾花數(shù)據(jù)
iris = datasets.load_iris()
#2.提取樣本數(shù)據(jù)
feature = iris.data
target = iris.target
feature.shape #(150,4)
target.shape #(150,)
#3.數(shù)據(jù)集進(jìn)行拆分
x_train,x_test,y_train,y_test = train_test_split(feature,target,test_size=0.2,random_state=2020)'
x_train.shape #(120,4)
y_train.shape'#(120,)
#4.觀察數(shù)據(jù)集:看是否需要進(jìn)行特征工程的處理
x_train
#5.實(shí)例化模型對(duì)象
knn = KNeighborsClassifier(n_neighbors=5)
#6.使用訓(xùn)練集數(shù)據(jù)訓(xùn)練模型
#X:特征(特征數(shù)據(jù)的維度必須是二維(表格型數(shù)據(jù))) #x_train.shape (120,4)
#y:標(biāo)簽
knn.fit(x_train,y_train) #訓(xùn)練集
#7.測(cè)試模型:使用測(cè)試數(shù)據(jù)
knn.score(x_test,y_test) #0.9 受k影響
#8.使用模型進(jìn)行分類
print('真實(shí)的分類結(jié)果:',y_test)
print('模型的分類結(jié)果:',knn.predict(x_test))
#輸出結(jié)果:
真實(shí)的分類結(jié)果: [2 0 1 1 1 2 2 1 0 0 2 2 0 2 2 0 1 1 2 0 0 2 1 0 2 1 1 1 0 0]
模型的分類結(jié)果: [2 0 1 1 1 1 2 1 0 0 2 1 0 2 2 0 1 1 2 0 0 2 2 0 2 1 1 1 0 0]
- 預(yù)測(cè)年收入是否大于50K美元
from sklearn.preprocessing import StandardScaler,MinMaxScaler
df = pd.read_csv('./datasets/adults.txt')
df.head()
#使用one-hot的形式
#1.提取樣本數(shù)據(jù)
feature = df[['age','education_num','occupation','hours_per_week']]
target = df['salary']
#2.特征工程-特征值化
one_hot_feature = pd.concat((feature[['age','education_num','hours_per_week']],pd.get_dummies(feature['occupation'])),axis=1)
#特征的預(yù)處理
s = StandardScaler()
s_feature = s.fit_transform(one_hot_feature)
#3.切分?jǐn)?shù)據(jù)集
x_train,x_test,y_train,y_test = train_test_split(s_feature,target,test_size=0.2,random_state=20)
#4.實(shí)例化模型對(duì)象
knn = KNeighborsClassifier(30)
knn.fit(x_train,y_train) #訓(xùn)練集
knn.score(x_test,y_test) #測(cè)試數(shù)據(jù)
#
#1.提取樣本數(shù)據(jù)
feature = df[['age','education_num','occupation','hours_per_week']]
target = df['salary']
count = 1
dic = {}
for occ in feature['occupation'].unique().tolist():
dic[occ] = count
count += 1
feature['occupation'] = feature['occupation'].map(dic)
#數(shù)據(jù)集切分
x_train,x_test,y_train,y_test = train_test_split(feature,target,test_size=0.2,random_state=20)
knn = KNeighborsClassifier(n_neighbors=30) #實(shí)例化對(duì)象
knn.fit(x_train,y_train) #訓(xùn)練集
knn.score(x_test,y_test) #測(cè)試數(shù)據(jù)
#使用模型對(duì)未知數(shù)據(jù)分類
print('真實(shí)分類結(jié)果:',y_test[0:10])
print('模型分類結(jié)果:',knn.predict(x_test)[0:10])
- k-近鄰算法之約會(huì)網(wǎng)站配對(duì)效果判定(datingTestSet.txt)
#讀數(shù)據(jù)
df = pd.read_csv('./datasets/datingTestSet.txt',header=None,sep='\t')
df.head()
#樣本數(shù)據(jù)提取
feature_col = [col for col in df.columns if col != 3]
feature = df[feature_col]
target = df[3]
#特征工程
mm = MinMaxScaler() #歸一化
m_feature = mm.fit_transform(feature)
#數(shù)據(jù)集切分
x_train,x_test,y_train,y_test = train_test_split(m_feature,target,test_size=0.2,random_state=2020)
#實(shí)例化
knn = KNeighborsClassifier(n_neighbors=10)
#訓(xùn)練集
knn.fit(x_train,y_train)
#測(cè)試數(shù)據(jù)
knn.score(x_test,y_test)
-
學(xué)習(xí)曲線尋找最優(yōu)的k值
窮舉不同的k值
ks = [5,7,9,12,15,20,25,30,35,40,45,50,60,70,80,90,100]
for k in ks:
knn = KNeighborsClassifier(n_neighbors=k).fit(x_train,y_train)
score=knn.score(x_test,y_test)
scores.append(score)
#畫(huà)圖
import matplotlib.pyplot as plt
plt.plot(ks,scores)
plt.xlabel('k')
plt.ylabel('score')
#找到分值最大的元素下標(biāo)
import numpy as np
arr_scores = np.array(scores)
np.argmax(arr_scores) #5
arr_scores
#輸出結(jié)果:
array([0.77537233, 0.77951789, 0.78335636, 0.78995854, 0.79180101,
0.79425764, 0.79072624, 0.79149394, 0.79302933, 0.79210809,
0.79180101, 0.79149394, 0.79164747, 0.79287579, 0.79318287,
0.79272225, 0.79318287])
ks[5] #最高分值對(duì)應(yīng)的k為20
#基于最優(yōu)的k值建模
knn = KNeighborsClassifier(n_neighbors=20)
knn.fit(x_train,y_train)
knn.score(x_test,y_test) #0.7942576385690158
- 在knn中樣本的標(biāo)簽數(shù)據(jù)是不需要參與運(yùn)算 贪惹,可以為非數(shù)值型數(shù)據(jù)
K折交叉驗(yàn)證
- 目的:
- 選出最為適合的模型超參數(shù)的取值苏章,然后將超參數(shù)的值作用到模型的創(chuàng)建中。
- 思想:
- 將樣本的訓(xùn)練數(shù)據(jù)交叉的拆分出不同的訓(xùn)練集和驗(yàn)證集奏瞬,使用交叉拆分出不同的訓(xùn)練集和驗(yàn)證集測(cè)分別試模型的精準(zhǔn)度枫绅,然就求出的精準(zhǔn)度的均值就是此次交叉驗(yàn)證的結(jié)果。將交叉驗(yàn)證作用到不同的超參數(shù)中硼端,選取出精準(zhǔn)度最高的超參數(shù)作為模型創(chuàng)建的超參數(shù)即可
- 實(shí)現(xiàn)思路:
- 將數(shù)據(jù)集平均分割成K個(gè)等份
- 使用1份數(shù)據(jù)作為測(cè)試數(shù)據(jù)并淋,其余作為訓(xùn)練數(shù)據(jù)
- 計(jì)算驗(yàn)證準(zhǔn)確率
- 使用不同的測(cè)試集,重復(fù)2珍昨、3步驟
- 對(duì)準(zhǔn)確率做平均县耽,作為對(duì)未知數(shù)據(jù)預(yù)測(cè)準(zhǔn)確率的估計(jì)
k交叉驗(yàn)證.png
-
API
- from sklearn.model_selection import cross_val_score
- cross_val_score(estimator,X,y,cv):
- estimator:模型對(duì)象
- X,y:訓(xùn)練集數(shù)據(jù)
- cv:折數(shù)
交叉驗(yàn)證在KNN中的基本使用
from sklearn.model_selection import cross_val_score
knn=KNeighborsClassifier(n_neighbors=10)
cross_val_score(knn,x_train,y_train,cv=5).mean() #拆分成5等分 #0.798372178061742
- 使用交叉驗(yàn)證&學(xué)習(xí)曲線找尋最優(yōu)的超參數(shù)
ks = [5,7,9,12,15,20,25,30,35,40,45,50,60,70,80,90,100]
scores = []
for k in ks:
knn=KNeighborsClassifier(n_neighbors=k)
score=cross_val_score(knn,x_train,y_train,cv=5).mean() #均值
scores.append(score)
plt.plot(ks,scores)
ks[np.argmax(np.array(scores))] #20
交叉驗(yàn)證也可以幫助我們進(jìn)行模型選擇
from sklearn.linear_model import LogisticRegression
knn = KNeighborsClassifier(n_neighbors=5)
print (cross_val_score(knn, x_train, y_train, cv=10).mean())
lr = LogisticRegression()
print(cross_val_score(lr,x_train,y_train,cv=10).mean())
(了解)K-Fold&cross_val_score
- Scikit中指供了K-Fold的API
- n-split就是折數(shù)
- shuffle指是否對(duì)數(shù)據(jù)洗牌
- random_state為隨機(jī)種子,固定隨機(jī)性
from numpy import array
from sklearn.model_selection import KFold
# data sample
data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6])
kfold = KFold(n_splits=3, shuffle = True, random_state= 1)
for train, test in kfold.split(data):
print('train: %s, test: %s' % (data[train], data[test]))
- Scikit中提取帶K-Fold接口的交叉驗(yàn)證接口sklearn.model_selection.cross_validate,但是該接口沒(méi)有數(shù)據(jù)shuffle功能镣典,所以一般結(jié)合Kfold一起使用兔毙。如果Train數(shù)據(jù)在分組前已經(jīng)經(jīng)過(guò)了shuffle處理,比如使用train_test_split分組骆撇,那就可以直接使用cross_val_score接口
from sklearn.model_selection import cross_val_score
iris = datasets.load_iris()
X, y = iris.data, iris.target
knn = KNeighborsClassifier(n_neighbors=5)
n_folds = 5
kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(X)
scores = cross_val_score(knn, X, y, cv = kf)
scores.mean() #0.9733333333333334
手寫(xiě)數(shù)字識(shí)別實(shí)現(xiàn)
from sklearn.model_selection import cross_val_score
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
#加載一張圖片數(shù)據(jù)
img_arr = plt.imread('./digist/3/3_100.bmp')
img_arr.shape #(28, 28)
plt.imshow(img_arr)
- 對(duì)所有數(shù)據(jù)的讀取和加載瞒御,將其封裝成樣本數(shù)據(jù)
feature_list = []
target_list = []
#1.加載數(shù)據(jù)父叙,封裝成樣本數(shù)據(jù)
for i in range(10):
for j in range(1,501):
img_path = './digist/'+str(i)+'/'+str(i)+'_'+str(j)+'.bmp'
img_arr = plt.imread(img_path)
feature_list.append(img_arr)
target_list.append(i)
len(feature_list) #5000
len(target_list) #5000
#每一個(gè)列表元素為2維神郊,則當(dāng)前列表一定是一個(gè)三維數(shù)據(jù)結(jié)構(gòu)
#訓(xùn)練模型需要的特征數(shù)據(jù)必須是二維
feature_list[0].shape #(28, 28)
#對(duì)feature_list進(jìn)行扁平化處理:三維的列表變成二維(每一個(gè)列表元素由二維變成1維肴裙,則整體列表就變形成了2維)
feature = []
for img_arr in feature_list:
feature.append(img_arr.reshape((28*28,)))
feature = np.array(feature) #將列表轉(zhuǎn)換成數(shù)組
target = np.array(target_list) #將列表轉(zhuǎn)換成數(shù)組
#拆分?jǐn)?shù)據(jù)集
x_train,x_test,y_train,y_test = train_test_split(feature,target,test_size=0.1,random_state=2020)
#找尋模型最優(yōu)的超參數(shù)
scores = []
ks = []
for k in range(3,100):
knn = KNeighborsClassifier(n_neighbors=k)
score = cross_val_score(knn,x_train,y_train,cv=5).mean()
ks.append(k)
scores.append(score)
best_k = ks[np.argmax(np.array(scores))]
best_k
#3
#實(shí)例化
knn = KNeighborsClassifier(n_neighbors=best_k)
knn.fit(x_train,y_train) #訓(xùn)練集
knn.score(x_test,y_test) #0.938
#使用模型進(jìn)行圖像識(shí)別
print('真實(shí)的圖像識(shí)別結(jié)果:',y_test[0:10])
print('模型分類的結(jié)果:',knn.predict(x_test)[0:10])
#輸出結(jié)果:
真實(shí)的圖像識(shí)別結(jié)果: [4 4 6 0 2 4 7 7 8 4]
模型分類的結(jié)果: [4 4 6 0 2 4 7 7 8 4]
- 讓模型識(shí)別外部圖片
img_arr = plt.imread('./123.jpg')
plt.imshow(img_arr)
#將5切出來(lái)
five_img_arr = img_arr[300:430,185:290]
plt.imshow(five_img_arr)
five_img_arr.shape #(130, 105)
- 訓(xùn)練好的模型識(shí)別的圖片數(shù)據(jù)只能是對(duì)28*28像素圖片進(jìn)行扁平化處理后的數(shù)據(jù)
#將five_img_arr進(jìn)行像素的等比例壓縮(28*28),在對(duì)其進(jìn)行扁平化處理即可
import scipy.ndimage as ndimage
five_img_arr_zoom = ndimage.zoom(five_img_arr,zoom=(28/130,28/105))
plt.imshow(five_img_arr_zoom)
#扁平化處理
# five_img_arr_zoom.reshape((28*28,)) #1維結(jié)構(gòu)
#在進(jìn)行predict的時(shí)候需要傳入的X涌乳,必須是二維
knn.predict(five_img_arr_zoom.reshape((1,784))) #array([5])