KNN

0、導引

如何進行電影分類

衆所周知,電影能夠按照題材分類,然而題材自己是如何定義的?由誰來斷定某部電影屬於哪 個題材?也就是說同一題材的電影具備哪些公共特徵?這些都是在進行電影分類時必需要考慮的問 題。沒有哪一個電影人會說本身製做的電影和之前的某部電影相似,但咱們確實知道每部電影在風格 上的確有可能會和同題材的電影相近。那麼動做片具備哪些共有特徵,使得動做片之間很是相似, 而與愛情片存在着明顯的差異呢?動做片中也會存在接吻鏡頭,愛情片中也會存在打鬥場景,咱們 不能單純依靠是否存在打鬥或者親吻來判斷影片的類型。可是愛情片中的親吻鏡頭更多,動做片中 的打鬥場景也更頻繁,基於此類場景在某部電影中出現的次數能夠用來進行電影分類。git

本章介紹第一個機器學習算法:K-近鄰算法,它很是有效並且易於掌握。算法

一、k-近鄰算法原理

簡單地說,K-近鄰算法採用測量不一樣特徵值之間的距離方法進行分類。數組

  • 優勢:精度高、對異常值不敏感、無數據輸入假定。網絡

  • 缺點:時間複雜度高、空間複雜度高。app

  • 適用數據範圍:數值型和標稱型。dom

工做原理

存在一個樣本數據集合,也稱做訓練樣本集,而且樣本集中每一個數據都存在標籤,即咱們知道樣本集中每一數據 與所屬分類的對應關係。輸人沒有標籤的新數據後,將新數據的每一個特徵與樣本集中數據對應的 特徵進行比較,而後算法提取樣本集中特徵最類似數據(最近鄰)的分類標籤。通常來講,咱們 只選擇樣本數據集中前K個最類似的數據,這就是K-近鄰算法中K的出處,一般K是不大於20的整數。 最後 ,選擇K個最類似數據中出現次數最多的分類,做爲新數據的分類機器學習

回到前面電影分類的例子,使用K-近鄰算法分類愛情片和動做片。有人曾經統計過不少電影的打鬥鏡頭和接吻鏡頭,下圖顯示了6部電影的打鬥和接吻次數。假若有一部未看過的電影,如何肯定它是愛情片仍是動做片呢?咱們可使用K-近鄰算法來解決這個問題。學習

 

二、在scikit-learn庫中使用k-近鄰算法

  • 分類問題:from sklearn.neighbors import KNeighborsClassifier測試

  • 迴歸問題:from sklearn.neighbors import KNeighborsRegressorui

0)一個最簡單的例子

身高、體重、鞋子尺碼數據對應性別

# 導入KNN 分類算法
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
# !!! 樣本中,男女比例應該1:1
data = np.array([[175,70,43],[180,75,44],[165,50,38],[163,48,37],[170,68,42],[168,52,40]])
target = np.array(['男','男','女','女','男','女'])
# 聲明算法
knn = KNeighborsClassifier(n_neighbors=5)
# 使用算法,進行學習,訓練
knn.fit(data,target)
# 使用算法,進行預測數據
data_predict = np.array([[188,90,46],[166,55,38],[169,65,41]])
knn.predict(data_predict)

1)用於分類

導包,機器學習的算法KNN、數據藍蝴蝶

# 使用KNN算法,對一種花,進行分類
# 數據源在sklearn中

import sklearn.datasets as datasets
# 使用datasets中的方法,導入數據
# data屬性:花萼長度,花萼寬度,花瓣長度,花瓣寬度
# 鳶尾花分三類 :'target_names': array(['setosa', 'versicolor', 'virginica'], dtype='<U10')}
iris = datasets.load_iris()

data = iris['data']
target = iris['target']
# numpy 將數據打亂順序
# shuffle 隨機打亂順序,data ,target兩個都須要打亂順序
# 隨機種子,每次和每次都不一樣,因此,隨機數的時候,每次和每次都不一樣
# np.random.shuffle()
# np.random.seed(8)
# np.random.randint(0,150,size = 1)
# 只能使用一次
np.random.seed(11)
np.random.shuffle(data)
np.random.seed(11)
np.random.shuffle(target)
#訓練樣本
# 150個樣本,分紅兩份,140個(訓練數據),10個(預測)

# 獲取了140個訓練數據
X_train = data[:140]
y_train = target[:140]

# 預測數據
X_test = data[140:]
y_test = target[140:] #真實答案

knn = KNeighborsClassifier(n_neighbors=5)

# 第一步,訓練
knn.fit(X_train,y_train)

# 第二步,預測
# 返回本身的「觀點」
# 通常狀況下,機器學習返回結果 添加:_
y_ = knn.predict(X_test)

print('鳶尾花分類真實狀況是:',y_test)

print('鳶尾花機器學習分類狀況是: ',y_)

# 經過結果,看到,機器學習,將最後這10未知的數據,所有預測準確

# 計算算法的準確率
score = knn.score(X_test,y_test)
print('算法的準確率: ', score)
  • 使用pandas數據類型進行操做

#機器學習的數據能夠是numpy也能夠是pandas

import pandas as pd
from pandas import Series,DataFrame

#先將訓練數據轉換爲pandans類型數據
X_train_df = DataFrame(X_train,columns=['speal length','speal width','petal length','petal width'])
y_train_s = Series(y_train)

#將測試測試數據轉爲pandas數據
X_test_df = DataFrame(X_test,columns=['speal length','speal width','petal length','petal width'])
y_test_s = Series(y_test)

knn = KNeighborsClassifier(10)
knn.fit(X_train_df,y_train_s)

y_ = knn.predict(X_test_df)
print(y_test_s.values)
print(y_)
  • 訓練數字

2、KNN手寫數字識別

import numpy as np
# bmp 圖片後綴
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.neighbors import KNeighborsClassifier

digit = plt.imread('./data/3/3_200.bmp')
# 28 * 28 很小
# 首先將圖片放大顯示
plt.figure(figsize=(2,2))
plt.imshow(digit,cmap = 'gray')
  • 批量獲取數據

# 批量獲取數據
data = []
target = []

for i in range(10):
   for j in range(1,501):
#         plt.imread('./data/3/3_200.bmp')
#         digit是二維的數組,黑白
       digit = plt.imread('./data/%d/%d_%d.bmp'%(i,i,j))
       data.append(digit)
       
#         目標值
       target.append(i)
# data 和target 5000個數據
len(data)
# 將機器學習的數據轉換成ndarry,操做起來比較方便
# ndarray 提供了不少方法
data = np.array(data)
target = np.array(target)

print(data.shape,target.shape)
#顯示正確值及圖片,僅供測試
index = np.random.randint(0,5000,size = 1)[0]

print('該索引所對應的目標值: ',target[index])

digit = data[index]
plt.figure(figsize=(2,2))
plt.imshow(digit,cmap = 'gray')
  • 打亂數據,生成學習隊列

seed = np.random.randint(0,5000,size = 1)[0]

# 指明隨機數的種子,打亂順序
np.random.seed(seed)
np.random.shuffle(data)

# 指明的種子和上面的同樣,打亂順序的規則就和上面同樣
np.random.seed(seed)
np.random.shuffle(target)
# 驗證一下,順序是否匹配
index = np.random.randint(0,5000,size = 1)[0]

print('該索引所對應的目標值: ',target[index])

digit = data[index]
plt.figure(figsize=(2,2))
plt.imshow(digit,cmap = 'gray')
  • 機器學習,分割數據

knn = KNeighborsClassifier(n_neighbors=20)
# 最後保留50個數據做爲預測數據集
# 訓練數據
X_train,y_train = data[:4950],target[:4950]
# 測試數據
X_test,y_test = data[-50:],target[-50:]
  • 因算法只能接受二維數據,故學習和預測的數據都須要轉化爲二維數據

X_train = X_train.reshape((4950,784))

# 正着數像素784像素點,倒着數-1
X_test = X_test.reshape((50,-1))
  • 訓練

# 第一步進行訓練
knn.fit(X_train,y_train)
  • 預測

# 第二步,使用算法,進行預測
y_ = knn.predict(X_test)

print('真實數據:',y_test)
print('預測數據: ',y_)
  • 將五十條數據畫出來

# 可視化,將50張繪製出來

plt.figure(figsize=(2*5,3*10))

for i in range(50):
   
#     10行5列
#     子視圖,在每個子視圖中繪製圖片
   subplot = plt.subplot(10,5,i+1)
   
#     最後50張圖片在 X_test中
#     !!! 像素點須要reshape成圖片形狀
   subplot.imshow(X_test[i].reshape((28,28)))
   
#     添加標題,True:0
#               Predict:0
#     y_test ----真實
#     y_ ------預測
   t = y_test[i]
   p = y_[i]
   subplot.set_title('True: %d\nPredict:%d'%(t,p))

獲取網絡上的數字圖片進行識別

  • 讀取圖片轉化爲灰度

digits = plt.imread('./數字.jpg')
digits = digits.mean(axis = 2)
plt.imshow(digits,cmap = 'gray')
  • 將圖片中的數字切片切下來

data_pre = digits[175:240,78:143]
plt.imshow(data_pre,cmap = 'gray')
  • 將圖片轉爲28*28

import scipy.ndimage as ndimage
data_pre_test = ndimage.zoom(data_pre,zoom = (28/65,28/65))
print(data_pre_test.shape)

plt.figure(figsize=(2,2))
plt.imshow(data_pre_test,cmap = 'gray')
  • 機器預測

# 從網絡上獲取的數據,有時候,由於寫數字,和樣本不一樣,偏差可能會很大
knn.predict(data_pre_test.reshape((1,-1)))
knn.predict(data_pre_test.reshape((1,784)))

3、保存模型

# 保存模型
# knn 算法,模型,estimator
# 數學建模,model 算法
from sklearn.externals import joblib
# 保存
joblib.dump(knn,'數字識別.m')
# 提取算法
knn_digits = joblib.load('./數字識別.m')
#使用模型
knn_digits.predict(data_pre_test.reshape((1,-1)))

4、預測癌症

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from sklearn.neighbors import KNeighborsClassifier
  • 讀取.csv文件,以\t做爲換行符

cancer = pd.read_csv('./data/cancer.csv',sep = '\t')
print(cancer.shape)
cancer
  • 將數據進行切片,獲取有用數據

# 獲取數據
data = cancer.iloc[:,2:]
target = cancer.iloc[:,1]
# target目標值中,M惡性,B良性,沒事兒
display(data.head(),target.head())
  • 設置鄰點個數,將數據分爲訓練和測試兩部分

knn = KNeighborsClassifier(n_neighbors=50)
# 打亂順序,而且一分爲二,訓練數據,預測數據
# sklearn 爲咱們提供了方法
from sklearn.model_selection import train_test_split
# 使用train_test_split進行數據分割
X_train,X_test,y_train,y_test = train_test_split(data,target,test_size = 0.1)
  • 訓練數據

knn.fit(X_train,y_train)
  • 預測數據

#檢查預測率
print(knn.score(X_test,y_test))
y_ = knn.predict(X_test)
  • 設置交叉表

# y_ 預測值
# y_test 真實值

# 交叉表,能夠說明,真實值和預測的哪一些數據不一樣
pd.crosstab(index = y_,columns=y_test,rownames=['Predict'],colnames=['True'],margins=True)
  • 提高準確度

因樣本中的數據大小良莠不齊,會給預測的準確性帶來誤差,故將數據歸一化處理後在進行機器學習,能夠提升預測的準確性

# !!!對數據進行處理,清洗
# 歸一化
# (num - min)/(max - min) 0 ~ 1
columns = data.columns
columns
  • 獲取全部的列

columns = data.columns
columns
  • 對列的值歸一化處理

for col in columns:
   data_min = data[col].min()
   data_max = data[col].max()
   #一次將一整列的數據都處理了
   data[col] = (data[col] - data_min)/(data_max - data_min)
  • 將數據分爲學習和預測兩部分

X_train,X_test,y_train,y_test = train_test_split(data,target,test_size = 0.1)
  • 開始學習

knn = KNeighborsClassifier(n_neighbors=15)
knn.fit(X_train,y_train)
knn.score(X_test,y_test)
# 數據清洗以後,準確率大幅提高,30列屬性,單位不一樣, 歸一化數據,準確率很大幅度進行了提高
y_ = knn.predict(X_test)
  • 交叉表

# 交叉表

pd.crosstab(index=y_,columns=y_test,rownames=['Predict'],colnames=['True'])
相關文章
相關標籤/搜索