ML15-KNN近鄰算法

KNN算法也是基于距離的簡單算法刺覆,本主題主要說明:
??1. KNN算法的數(shù)學模型哥倔;
??2. KNN的實現(xiàn)與應用兜喻;
??3. 交叉驗證尋找最合適的K涩哟;


KNN緊鄰算法的說明

  • KNN(K-Nearest Neighbor)K最近鄰算法
  • 對于KNN緊鄰算法需要說明的有如下幾點:
    1. KNN緊鄰算法是基于距離的算法。
    2. KNN主要用于分類侵贵。
    3. KNN是一種有監(jiān)督學習届搁。

KNN緊鄰算法

KNN(K-Nearest Neighbor)的特點

  • KNN算法沒有訓練過程,對一個沒有標簽的數(shù)據(jù)窍育,KNN算法直接在已經標簽的數(shù)據(jù)集(俗稱訓練集)之上對未標簽的數(shù)據(jù)分類卡睦。

KNN的算法模型

  1. 假設已知訓練數(shù)據(jù)集

    • X_i= [x_{i1}, x_{i2},\dots, x_{in}], \qquad i=\{1,2,\dots, m\}, \qquad m \text{是樣本的類別數(shù)}
    • 樣本總數(shù)就是m \times n
  2. 假設需要分類的樣本是s

  3. 算法過程

    • 計算待分類樣本s到所有訓練樣本的距離D = [d_1,d_2,\dots,d_{m \times n}]
    • 在D中取前K個比較小的距離。
    • 統(tǒng)計每個類別在K個較小距離中對應的樣本點的數(shù)量漱抓;
    • 待分類樣本就屬于樣本點最多的那個類別表锻。
  4. 算法例子說明:

    • 假設數(shù)據(jù)集是鳶尾花,150個樣本辽旋,一共三類(假設A浩嫌,B檐迟,C三類)补胚。
    • 待分類樣本s
    • 計算s到150個樣本的距離(一般歐氏距離),一共得到150個距離追迟。
    • 在150個距離中溶其,取前K個較小距離。
    • 統(tǒng)計K個距離中敦间,ABC三類占的數(shù)量瓶逃。
    • 樣本s就屬于最大那個分類。

KNN算法中K值的選擇

  • K緊鄰算法中的K的選擇對分類結果會產生比較大的影響廓块。

    1. K較小
      • 預測結果對近鄰的實例點非常敏感厢绝。
      • 容易發(fā)生過擬合(估計誤差會增大【爭對測試集】,近似誤差較少【爭對訓練集】)
    2. K較大
      • 較遠的訓練實例也會對預測起作用
      • 使預測發(fā)生錯誤带猴,k值增大模型的復雜度會下降昔汉,當K=樣本數(shù)量N的時候,模型就變成單一模型拴清。
  • 在實際應用靶病,K值一般選取比較下的值会通。

  • 距離的選擇在這里也顯得比較重要。

距離的定義

  • 常見的距離的定義
    • 歐氏距離(Euclidean)
    • 曼哈頓距離(Manhattan / City Block distance)
    • 切比雪夫距離(Chebyshev)
    • 閔可夫斯基距離(Minkowski)
    • 標準化歐氏距離(Standardized Euclidean)
    • 馬氏距離(Mahalanobis)
    • 巴氏距離(Bhattacharyya)
    • 漢明距離(Hamming)
    • 夾角余弦(Cosine)
    • 杰卡德距離(Jaccard)
    • 皮爾遜距離(Pearson)

KNN算法實現(xiàn)與應用

KNN算法標量版本

import numpy as np
import sklearn.datasets as ds

def knn(train_data, train_label, sample, k):
    """
    train_data:訓練集
    train_label:訓練集的分類標簽
    sample:待分類樣本
    k:用來分類判定的前K個距離的個數(shù)
    """
    # 1. 計算待分類樣本sample與所有訓練集的距離
    distances = []   # 存放sample到所有訓練集的距離
    for s in train_data:
        diff = (s - sample)**2
        distance = np.sqrt(diff.sum())
        distances.append(distance)
    # 2. 對距離排序(從小到大)娄周,取前K個來統(tǒng)計分類(返回排序后的下標)
    distances_np = np.array(distances)   # 轉換為ndarray涕侈,利用其中的返回排序后的下標功能
    sorted_index = distances_np.argsort()  
    # 3. 統(tǒng)計前K個距離對應訓練樣本的分類數(shù)量
    categories = {}   # 存放前k個距離的類別統(tǒng)計
    for i in range(k):
        # 取排序下標,在target標簽中得到類別
        idx = sorted_index[i]    # 取下標
        category = train_label[idx]   # 取列別
        if category not in categories:
            categories[category] = 0
        categories[category] += 1
    # print(categories)
    # 4. 分類數(shù)量最多的就是帶分類樣本的分類類別(返回類別下標)
    # 對統(tǒng)計的類別 categories 進行排序煤辨,其中最后一個就是最多的類別就是待分類樣本的類別裳涛。
    categories_sorted = sorted(categories.items(), key= lambda x: x[1], reverse=True)   # 返回列表
    return categories_sorted[0][0]  # 第一個最大,取第一個數(shù)據(jù)的第一個值:就是類別
    
#  --- 數(shù)據(jù)加載與測試
# 數(shù)據(jù)加載
data, target = ds.load_iris(return_X_y=True)
# 使用第一個樣本來測試掷酗,k=7
data, target = ds.load_iris(return_X_y=True)
knn(data, target, data[100], 7)
2

KNN算法向量版本

import numpy as np
import sklearn.datasets as ds

def knn_v(train_data, train_label, sample, k):
    diff = (train_data - sample)**2
    distances = np.sqrt(diff.sum(axis=1))
    sorted_index = distances.argsort()
    categories = {}
    for i in range(k):
        category = train_label[sorted_index[I]]
        categories[category] = categories.get(category,0) + 1
    # print(categories)
    categories_sorted = sorted(categories.items(), key= lambda x: x[1], reverse=True)   # 返回列表
    return categories_sorted[0][0]  # 第一個最大调违,取第一個數(shù)據(jù)的第一個值:就是類別

data, target = ds.load_iris(return_X_y=True)
knn_v(data, target, data[100], 7)
2
#  --- 數(shù)據(jù)加載與測試
# 數(shù)據(jù)加載
data, target = ds.load_iris(return_X_y=True)

# 生成交叉驗證方案
kf = KFold(n_splits=5)
ss = ShuffleSplit(n_splits=10, test_size=0.20) 
result_split = ss.split(data)   

# 開始交叉驗證
# 存放k=1,k=2泻轰,...技肩,k=120的正確數(shù),最高的那個k就是我們選擇的k
k_rates = {}    # key對應k的值浮声,value對應分類正確數(shù)

Ks = 120

for index_train, index_test in result_split:
    # 根據(jù)索引得到訓練集與測試集
    data_train = data.take(index_train, axis=0)
    target_train = target.take(index_train)
    # 訓練測試集虚婿,統(tǒng)計識別正確總數(shù)(對所有交叉方案統(tǒng)計的結果)
    for idx in index_test:
        sample = data[idx]
        # 訓練取k
        for k in range(1, Ks+1):
            c = knn(data_train, target_train, sample, k)
            # 判定分類是否正確
            if c == target[idx]:  # 分類正確
                # 統(tǒng)計數(shù)據(jù)到k_rates
                if k not in k_rates:   # 如果字典中沒有k對應的key,則增加一個
                    k_rates[k] = 0
                k_rates[k] +=1   # 正確數(shù)累加

# 選擇正確最高的作為k
k_rates_sorted = sorted(k_rates.items(), key= lambda x: x[1], reverse=True)   
best_k = k_rates_sorted[0][0]
print(best_k, k_rates_sorted[0][1])

# k_rates_sorted
%matplotlib inline
import matplotlib.pyplot as plt

figure = plt.figure('KNN', figsize=(8, 6))

ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])

dict_sorted = dict(sorted(k_rates.items(), key= lambda x: x[0], reverse=False)) 

ax.plot(dict_sorted.keys(), dict_sorted.values(), color=(1, 0, 0, 1))

plt.show()
dict_data.keys()
9 296
K的選取曲線
dict_keys([69, 71, 72, 55, 70, 57, 58, 65, 73, 76, 54, 59, 68, 75, 56, 66, 60, 64, 52, 53, 67, 74, 61, 63, 51, 62, 50, 47, 77, 78, 44, 48, 45, 46, 33, 49, 35, 36, 37, 38, 43, 90, 42, 31, 34, 40, 79, 105, 80, 84, 89, 91, 39, 28, 29, 41, 88, 107, 87, 27, 32, 24, 26, 92, 93, 30, 82, 83, 110, 106, 86, 85, 94, 114, 104, 23, 25, 81, 115, 117, 20, 113, 103, 19, 95, 108, 21, 22, 111, 116, 97, 98, 101, 14, 109, 112, 119, 102, 96, 18, 120, 99, 100, 1, 2, 17, 5, 12, 16, 118, 10, 6, 8, 9, 13, 15, 3, 7, 11, 4])

交叉驗證與k的選取

交叉驗證的概念

  • 交叉驗證的包含兩個重要的操作
    • 數(shù)據(jù)集分成兩個部分:一部分用來作為訓練數(shù)據(jù)集泳挥,另外一部分用來測試數(shù)據(jù)集然痊。
    • 數(shù)據(jù)重復使用,多次訓練與測試(我們把一次訓練與測試稱為一次驗證):在重復驗證過程屉符,某個數(shù)據(jù)在第一次驗證可能是訓練樣本剧浸,在下一次驗證有可能是測試樣本。

交叉驗證的樣本選擇方式

  • 基本交叉驗證

    • 數(shù)據(jù)集隨機洗牌打亂矗钟,然后按照比例分成兩部分:訓練數(shù)據(jù)集與測試數(shù)據(jù)集唆香;
    • 反復重復上述過程。
  • K折交叉驗證

    • 據(jù)集隨機洗牌打亂吨艇,分成K份躬它。

    • 隨機的選擇K-1份作為訓練集,剩下的1份做測試集东涡,這樣數(shù)據(jù)集分成兩個部分:訓練數(shù)據(jù)集與測試數(shù)據(jù)集冯吓。

    • 重復從K分鐘隨機選擇K-1份作為訓練集,剩下的1份做測試集疮跑;(這里是對K份重復隨機组贺,不再對數(shù)據(jù)集再隨機洗牌打亂)

    • 注意:K折方式也可以反復調用。

  • 留一交叉驗證

    • 是K折交叉驗證的特例祖娘,就是K = N(N是樣本總數(shù))
    • 這種情況用于樣本數(shù)比較少的情況失尖。
  • 留P交叉驗證

    • 與留一交叉驗證類似,只是從訓練集中剔除P個樣本。
  • 在sklearn提供了用戶自定義數(shù)據(jù)集劃分方式

sklearn的樣本切割實現(xiàn)

切割函數(shù)train_test_split

  • 把數(shù)據(jù)集隨機切割成兩個部分
    sklearn.model_selection.train_test_split(
        *arrays : sequence of indexables with same length / shape[0]   # 拆分數(shù)據(jù)集
        test_size : float, int or None, optional (default=None)   # 測試集比例
        train_size : float, int, or None, (default=None)  # 訓練集比例
        shuffle : boolean, optional (default=True)    # 是否打亂
    )

import sklearn.datasets as ds
from sklearn.model_selection import train_test_split

# 加載數(shù)據(jù)集
data,target = ds.load_iris(return_X_y=True)  

# 切分數(shù)據(jù)集
data_train, data_test, target_train, target_test = train_test_split(
    data,    # 數(shù)據(jù)集
    target,    # 數(shù)據(jù)集標簽
    test_size=0.2)  

print(data_train.shape, data_test.shape)
(120, 4) (30, 4)

切割類KFold雹仿,LeaveOneOut增热,LeavePOut,ShuffleSplit

  • sklearn提供了系列的切分類:
    • sklearn的切分API類
  1. KFold
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit

# 加載數(shù)據(jù)集
data,target = ds.load_iris(return_X_y=True)  

# k折切分
kf = KFold(n_splits=5)
result_split = kf.split(data)    # 返回生成器
for index_train, index_test in result_split:
    print(index_train.shape, index_test.shape)

# 返回下標胧辽,可以在原來數(shù)據(jù)上操作

data_test = data.take(index_test, axis=0)
data_train = data.take(index_train, axis=0)

print(data_train.shape, data_test.shape)
(120,) (30,)
(120,) (30,)
(120,) (30,)
(120,) (30,)
(120,) (30,)
(120, 4) (30, 4)
  1. LeaveOneOut
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit

# 加載數(shù)據(jù)集
data,target = ds.load_iris(return_X_y=True)  

# 留一切分
loo = LeaveOneOut()
result_split = loo.split(data)    # 返回生成器

for index_train, index_test in result_split:
    print(index_train.shape, index_test.shape)
    break

# 返回下標峻仇,可以在原來數(shù)據(jù)上操作

data_test = data.take(index_test, axis=0)
data_train = data.take(index_train, axis=0)

print(data_train.shape, data_test.shape)

(149,) (1,)
(149, 4) (1, 4)
  1. LeavePOut
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit

# 加載數(shù)據(jù)集
data,target = ds.load_iris(return_X_y=True)  

# 留p切分
lpo = LeavePOut(p=30)   # 留30個
result_split = lpo.split(data)    # 返回生成器

for index_train, index_test in result_split:
    print(index_train.shape, index_test.shape)
    break

# 返回下標,可以在原來數(shù)據(jù)上操作

data_test = data.take(index_test, axis=0)
data_train = data.take(index_train, axis=0)

print(data_train.shape, data_test.shape)


(120,) (30,)
(120, 4) (30, 4)
  1. ShuffleSplit
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit

# 加載數(shù)據(jù)集
data,target = ds.load_iris(return_X_y=True)  

# 隨機切分
ss = ShuffleSplit(n_splits=2, test_size=0.20)    # 生成的重復次數(shù)
result_split = ss.split(data)    # 返回生成器

for index_train, index_test in result_split:
    print(index_train.shape, index_test.shape)
    # break

# 返回下標邑商,可以在原來數(shù)據(jù)上操作

data_test = data.take(index_test, axis=0)
data_train = data.take(index_train, axis=0)

print(data_train.shape, data_test.shape)


(120,) (30,)
(120,) (30,)
(120, 4) (30, 4)

KNN的k的選擇

  • 使用K折交叉驗證摄咆,其他的可以自己使用
import numpy as np
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit
from sklearn.model_selection import train_test_split


def knn(train_data, train_label, sample, k):
    """
    train_data:訓練集
    train_label:訓練集的分類標簽
    sample:待分類樣本
    k:用來分類判定的前K個距離的個數(shù)
    """
    # 1. 計算待分類樣本sample與所有訓練集的距離
    distances = []   # 存放sample到所有訓練集的距離
    for s in train_data:
        diff = s - sample
        distance = np.sqrt(np.dot(diff, diff))
        distances.append(distance)
    # 2. 對距離排序(從小到大),取前K個來統(tǒng)計分類(返回排序后的下標)
    distances_np = np.array(distances)   # 轉換為ndarray人断,利用其中的返回排序后的下標功能
    sorted_index = distances_np.argsort()  
    # 3. 統(tǒng)計前K個距離對應訓練樣本的分類數(shù)量
    categories = {}   # 存放前k個距離的類別統(tǒng)計
    for i in range(k):
        # 取排序下標吭从,在target標簽中得到類別
        idx = sorted_index[i]    # 取下標
        category = train_label[idx]   # 取列別
        if category not in categories:
            categories[category] = 0
        categories[category] += 1
    
    # 4. 分類數(shù)量最多的就是帶分類樣本的分類類別(返回類別下標)
    # 對統(tǒng)計的類別 categories 進行排序,其中最后一個就是最多的類別就是待分類樣本的類別恶迈。
    categories_sorted = sorted(categories.items(), key= lambda x: x[1], reverse=True)   # 返回列表
    return categories_sorted[0][0]  # 第一個最大涩金,取第一個數(shù)據(jù)的第一個值:就是類別
    
#  --- 數(shù)據(jù)加載與測試
# 數(shù)據(jù)加載
data, target = ds.load_iris(return_X_y=True)

# 生成交叉驗證方案
kf = KFold(n_splits=5)
ss = ShuffleSplit(n_splits=10, test_size=0.20) 
result_split = ss.split(data)   

# 開始交叉驗證
# 存放k=1,k=2暇仲,...步做,k=120的正確數(shù),最高的那個k就是我們選擇的k
k_rates = {}    # key對應k的值奈附,value對應分類正確數(shù)

Ks = 120

for index_train, index_test in result_split:
    # 根據(jù)索引得到訓練集與測試集
    data_train = data.take(index_train, axis=0)
    target_train = target.take(index_train)
    # 訓練測試集全度,統(tǒng)計識別正確總數(shù)(對所有交叉方案統(tǒng)計的結果)
    for idx in index_test:
        sample = data[idx]
        # 訓練取k
        for k in range(1, Ks+1):
            c = knn(data_train, target_train, sample, k)
            # 判定分類是否正確
            if c == target[idx]:  # 分類正確
                # 統(tǒng)計數(shù)據(jù)到k_rates
                if k not in k_rates:   # 如果字典中沒有k對應的key,則增加一個
                    k_rates[k] = 0
                k_rates[k] +=1   # 正確數(shù)累加
                
          
# 選擇正確最高的作為k
k_rates_sorted = sorted(k_rates.items(), key= lambda x: x[1], reverse=True)   
best_k = k_rates_sorted[0][0]
print(best_k, k_rates_sorted[0][1])
# k_rates_sorted


15 292
# 可視化
%matplotlib inline
import matplotlib.pyplot as plt

figure = plt.figure('KNN', figsize=(8, 6))

ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])

dict_sorted = dict(sorted(k_rates.items(), key= lambda x: x[0], reverse=False)) 

ax.plot(dict_sorted.keys(), dict_sorted.values(), color=(1, 0, 0, 1))

plt.show()
dict_data.keys()
K選擇的測試
dict_keys([69, 71, 72, 55, 70, 57, 58, 65, 73, 76, 54, 59, 68, 75, 56, 66, 60, 64, 52, 53, 67, 74, 61, 63, 51, 62, 50, 47, 77, 78, 44, 48, 45, 46, 33, 49, 35, 36, 37, 38, 43, 90, 42, 31, 34, 40, 79, 105, 80, 84, 89, 91, 39, 28, 29, 41, 88, 107, 87, 27, 32, 24, 26, 92, 93, 30, 82, 83, 110, 106, 86, 85, 94, 114, 104, 23, 25, 81, 115, 117, 20, 113, 103, 19, 95, 108, 21, 22, 111, 116, 97, 98, 101, 14, 109, 112, 119, 102, 96, 18, 120, 99, 100, 1, 2, 17, 5, 12, 16, 118, 10, 6, 8, 9, 13, 15, 3, 7, 11, 4])

k選擇的測試

  • 根據(jù)上面的交叉驗證斥滤,選擇k=7将鸵,下面是測試結果。
import numpy as np
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit
from sklearn.model_selection import train_test_split

def knn(train_data, train_label, sample, k):
    """
    train_data:訓練集
    train_label:訓練集的分類標簽
    sample:待分類樣本
    k:用來分類判定的前K個距離的個數(shù)
    """
    # 1. 計算待分類樣本sample與所有訓練集的距離
    distances = []   # 存放sample到所有訓練集的距離
    for s in train_data:
        diff = s - sample
        distance = np.sqrt(np.dot(diff, diff))
        distances.append(distance)
    # 2. 對距離排序(從小到大)佑颇,取前K個來統(tǒng)計分類(返回排序后的下標)
    distances_np = np.array(distances)   # 轉換為ndarray顶掉,利用其中的返回排序后的下標功能
    sorted_index = distances_np.argsort()  
    # 3. 統(tǒng)計前K個距離對應訓練樣本的分類數(shù)量
    categories = {}   # 存放前k個距離的類別統(tǒng)計
    for i in range(k):
        # 取排序下標,在target標簽中得到類別
        idx = sorted_index[i]    # 取下標
        category = train_label[idx]   # 取列別
        if category not in categories:
            categories[category] = 0
        categories[category] += 1
    
    # 4. 分類數(shù)量最多的就是帶分類樣本的分類類別(返回類別下標)
    # 對統(tǒng)計的類別 categories 進行排序漩符,其中最后一個就是最多的類別就是待分類樣本的類別一喘。
    categories_sorted = sorted(categories.items(), key= lambda x: x[1], reverse=True)   # 返回列表
    return categories_sorted[0][0]  # 第一個最大驱还,取第一個數(shù)據(jù)的第一個值:就是類別
    
#  --- 數(shù)據(jù)加載與測試
# 數(shù)據(jù)加載
data, target = ds.load_iris(return_X_y=True)
# 使用第一個樣本來測試嗜暴,k=60

# data_train, data_test, target_train, target_test = train_test_split(
#     data,    # 數(shù)據(jù)集
#     target,    # 數(shù)據(jù)集標簽
#     test_size=0.2)  

ss = ShuffleSplit(n_splits=1, test_size=0.20) 
result_split = ss.split(data) 
for index_train, index_test in result_split:
    data_test = data.take(index_test, axis=0)
    data_train = data.take(index_train, axis=0)
    target_test = target.take(index_test, axis=0)
    target_train = target.take(index_train, axis=0)

correct_counter = 0
for d, t in zip(data_test, target_test):
    c = knn(data_train, target_train, d, 17)
    if c==t:
        correct_counter += 1

print(F'訓練集與測試集不重疊- 識別正確:{correct_counter},測試樣本數(shù):{len(target_test)}')


correct_counter = 0
for d, t in zip(data_test, target_test):
    c = knn_v(data, target, d, 7)
    # print(c,t)
    if c==t:
        correct_counter += 1

print(F'訓練集與測試集重疊- 識別正確:{correct_counter}议蟆,測試樣本數(shù):{len(target_test)}')

# for d in data[100:150]:
#     c = knn(data, target, d, 7)
#     print(c)
訓練集與測試集不重疊- 識別正確:30闷沥,測試樣本數(shù):30
訓練集與測試集重疊- 識別正確:30,測試樣本數(shù):30

KNN的sklearn應用

from sklearn.neighbors import KNeighborsClassifier
import numpy as np
import sklearn.datasets as ds
from sklearn.model_selection import KFold, LeaveOneOut, LeavePOut, ShuffleSplit
from sklearn.model_selection import train_test_split


k_nn = KNeighborsClassifier(n_neighbors=7)

data, target = ds.load_iris(return_X_y=True)
# 使用第一個樣本來測試咐容,k=60

# data_train, data_test, target_train, target_test = train_test_split(
#     data,    # 數(shù)據(jù)集
#     target,    # 數(shù)據(jù)集標簽
#     test_size=0.2)  

ss = ShuffleSplit(n_splits=1, test_size=0.20) 
result_split = ss.split(data) 
for index_train, index_test in result_split:
    data_test = data.take(index_test, axis=0)
    data_train = data.take(index_train, axis=0)
    target_test = target.take(index_test, axis=0)
    target_train = target.take(index_train, axis=0)

k_nn.fit(data_train, target_train) 


c = k_nn.predict(data_test)
print(c)
(c ==  target_test).sum()


[1 2 0 0 0 2 1 0 1 2 2 2 0 2 0 2 0 2 0 1 2 2 1 0 0 2 2 0 0 2]





29

KNN的手寫數(shù)字識別

  • 代碼來自《機器學習實戰(zhàn)》一書的源代碼舆逃,并使用sklearn的KNeighborsClassifier類改寫。
import numpy as np
import operator
from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN

'''
函數(shù)說明:將32*32的二進制圖片轉換為1*1024向量
Parameters:
    filename - 文件名
Returns:
    returnVect - 返回的二進制圖像的1*1024向量
'''
def img2vector(filename):
    #創(chuàng)建1*1024的0向量
    returnVect = np.zeros((1,1024))
    fr = open(filename)
    #按行讀取
    for i in range(32):
        #讀一行數(shù)據(jù)
        lineStr=fr.readline()
        #每一行的前32個數(shù)據(jù)依次添加到returnVect
        for j in range(32):
            returnVect[0,32*i+j]=int(lineStr[j])
    return returnVect

'''
函數(shù)說明:手寫數(shù)字分類測試
Parameters:
    filename - 無
Returns:
    returnVect - 無
'''
def handwritingClassTest():
    #測試集的labels
    hwLabels=[]
    #返回trainingDigits目錄下的文件名
    trainingFileList=listdir('digits/trainingDigits')
    #返回文件夾下文件的個數(shù)
    m=len(trainingFileList)
    #初始化訓練的Mat矩陣的測試集
    trainingMat=np.zeros((m,1024))
    
    #從文件名中解析出訓練集的類別
    for i in range(m):
        fileNameStr=trainingFileList[I]
        classNumber = int(fileNameStr.split('_')[0])
        #將獲取的類別添加到hwLabels中
        hwLabels.append(classNumber)
        #將每一個文件的1*1024數(shù)據(jù)存儲到trainingMat矩陣中
        trainingMat[i,:]=img2vector('digits/trainingDigits/%s'%(fileNameStr))
        
        
    #構建KNN分類器
    neigh = kNN(n_neighbors=3,algorithm='auto')
    #擬合模型,trainingMat為測試矩陣,hwLabels為對應的標簽
    neigh.fit(trainingMat,hwLabels)
    #返回testDigits目錄下的文件列表
    testFileList=listdir('digits/testDigits')
    errorCount=0.0
    mTest=len(testFileList)
    #從文件中解析出測試集的類別并進行分類測試
    for i in range(mTest):
        fileNameStr=testFileList[I]
        classNumber=int(fileNameStr.split('_')[0])
        #獲得測試集的1*1024向量用于訓練
        vectorUnderTest=img2vector('digits/testDigits/%s'%(fileNameStr))
        #獲得預測結果
        classifierResult=neigh.predict(vectorUnderTest)
        print ("分類返回結果%d\t真實結果%d"%(classifierResult,classNumber))
        if (classNumber != classifierResult):
            errorCount += 1.0
    print ("總共錯了%d個\t錯誤率為%f%%"%(errorCount,errorCount/mTest*100))


handwritingClassTest()
分類返回結果0 真實結果0
分類返回結果0 真實結果0
分類返回結果0 真實結果0
分類返回結果0 真實結果0

......

分類返回結果9 真實結果9
分類返回結果9 真實結果9
總共錯了12個 錯誤率為1.268499%

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末路狮,一起剝皮案震驚了整個濱河市虫啥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奄妨,老刑警劉巖涂籽,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砸抛,居然都是意外死亡评雌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門直焙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來景东,“玉大人,你說我怎么就攤上這事奔誓〗锿拢” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵厨喂,是天一觀的道長曲初。 經常有香客問我,道長杯聚,這世上最難降的妖魔是什么臼婆? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮幌绍,結果婚禮上颁褂,老公的妹妹穿的比我還像新娘。我一直安慰自己傀广,他們只是感情好颁独,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伪冰,像睡著了一般誓酒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贮聂,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天靠柑,我揣著相機與錄音,去河邊找鬼吓懈。 笑死歼冰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的耻警。 我是一名探鬼主播隔嫡,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼甸怕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腮恩?” 一聲冷哼從身側響起梢杭,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秸滴,沒想到半個月后式曲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缸榛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年吝羞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片内颗。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡洽蛀,死狀恐怖盗冷,靈堂內的尸體忽然破棺而出潜秋,到底是詐尸還是另有隱情垃杖,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布找前,位于F島的核電站糟袁,受9級特大地震影響,放射性物質發(fā)生泄漏躺盛。R本人自食惡果不足惜项戴,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望槽惫。 院中可真熱鬧周叮,春花似錦、人聲如沸界斜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽各薇。三九已至项贺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間峭判,已是汗流浹背开缎。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朝抖,地道東北人啥箭。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓谍珊,卻偏偏與公主長得像治宣,于是被迫代替她去往敵國和親急侥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內容