监督学习:KNN(K-近邻)算法实现手写数字识别的三种方法
沒人會看的開場白:本來覺得自己從數據建模轉人工智能方向應該問題不大(自我感覺自己算法學的不錯)。結果一個K-鄰近實現手寫數字識別的代碼就讓我改了三四天。雖然網上這方面的代碼是很多,但是我運行了好幾個,結果都不是很理想。一次偶然的念想——為什么我不把這些代碼的優點結合在一起呢,于是說做就做,年輕人嘛,反正有時間燥起來,再加上自己準備的畢業論文也是這個,動動手總有益處,于是就拙筆于此,有更好的建議與意見,歡迎指正。?
開篇說明:內容很多,沉不下心,想速成的朋友請繞行,學習新知識嘛,坑要一個一個填實。打碎的骨頭才更牢靠吧!
本篇所有的源碼資源都已上傳:https://download.csdn.net/download/zzz_cming/10377414?
–—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-——-—-—-—-—-—-—-—-—-—-—-—-—-—-——-?
什么是K-近鄰算法
百度百科上的定義:K-近鄰(k-Nearest Neighbor,KNN)是分類算法,是一個理論上比較成熟的方法,也是最簡單的機器學習算法之一。該方法的思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬于某一個類別,則該樣本也屬于這個類別。
K-近鄰算法怎么應用于數字識別實現過程直觀點說:根據測試數據與每個訓練集數據距離的大小來判斷該測試數據分屬哪個類別——我們有一堆已經注明好它是哪個數字的圖片(這一堆圖片組成訓練集,也叫比較集、樣本空間)?,F在有一個測試數據“6”來了,我們要識別這個“6”的步驟就是:
(說明:左圖是我用Windows自帶的畫圖工具寫的一個“6”,圖片大小是28*28。右圖是經過我切割、拉伸轉化后的0-1矩陣圖)?
??
1. 將測試數據由圖片形式轉換成只有一列的0-1矩陣形式:上左圖中有像素點的位置記為1,沒有像素點的位置記為0,成上右圖(上右圖是經過我切割、拉伸后的結果)。再將上右圖中所有后一行數字接到前一行末尾,形成一行,最后轉置即可得一列0-1矩陣形式?
2. 將所有(L個)訓練數據也都用上方法從圖片形式轉換成只有一列的0-1矩陣形式?
3. 把L個單列數據存入新矩陣A中——矩陣A每一列存儲一個圖片的所有信息?
4. 用測試數據與矩陣A中的每一列求距離,求得的L個距離存入距離數組中(距離 = 對應位差值的平方和再求平方根)?
5. 從距離數組中取出最小的K個距離所對應的訓練集的索引?
6. 擁有最多索引的值就是預測值(有多個眾數時,按距離和最小)
三個KNN實現數字識別的方法(說明:這是自己在網上看到的三個大神寫的比較好的代碼,前兩個都能實現要求,后一個是預處理方法。我也只是站在大神的肩膀上做一點點修改,原理還是他們教的我,在此向他們表示致敬)
第一個:圖片大小28*28,手寫數字圖片識別
來源說明:騰訊課堂米度教育《AI人工智能 機器學習 深度學習VIP實戰就業班(人臉識別 無人駕駛)》第一節課。
獻丑貼出自己的代碼:?
優化說明如下:(小修改未說明)
Pierre老師的代碼中K值是等于1,即只選取與訓練集數據最近的那個類。優化后成為可變的K,可自由選擇最近的K個值進行比較
# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing
# -*- 2017/12/25
# -*- python3.5
?
import numpy as np
from image import image2onebit as it
import sys
from tensorflow.examples.tutorials.mnist import input_data
import math
import datetime
?
#KNN算法主體:計算測試樣本與每一個訓練樣本的距離
def get_index(train_data,test_data, i):
??? #1、 np.argmin(np.sqrt(np.sum(np.square(test_data[i]-train_data),axis=1)))
??? #2、a數組存入:測試樣本與每一個訓練樣本的距離
??? all_dist = np.sqrt(np.sum(np.square(test_data[i]-train_data),axis=1)).tolist()
??? return all_dist
?
#KNN算法主體:計算查找最近的K個訓練集所對應的預測值
def get_number(all_dist):
??? all_number = []
??? min_index = 0
??? #print('距離列表:', all_dist,)
??? for k in range(Nearest_Neighbor_number):
??????? # 最小索引值 = 最小距離的下標編號
??????? min_index = np.argmin(all_dist)
??????? #依據最小索引值(最小距離的下標編號),映射查找到預測值
??????? ss = np.argmax((train_label[min_index])).tolist()
??????? print('第',k+1,'次預測值:',ss)
??????? #將預測值改為字符串形式存入新元組bb中
??????? all_number = all_number + list(str(ss))
??????? #在距離數組中,將最小的距離值刪去
??????? min_number = min(all_dist)
??????? xx = all_dist.index(min_number)
??????? del all_dist[xx]
??? print('預測值總體結果:',all_number)
??? return all_number
?
#KNN算法主體:在K個預測值中,求眾數,找到分屬最多的那一類,輸出
def get_min_number(all_number):
??? c = []
??? #將string轉化為int,傳入新列表c
??? for i in range(len(all_number)):
??????? c.append(int(all_number[i]))
??? #求眾數
??? new_number = np.array(c)
??? counts = np.bincount(new_number)
??? return np.argmax(counts)
?
t1 = datetime.datetime.now()????? #計時開始
print('說明:訓練集數目取值范圍在[0,60000],K取值最好<10\n' )
train_sum = int(input('輸入訓練集數目:'))
Nearest_Neighbor_number = int(input('選取最鄰近的K個值,K='))
?
#依照文件名查找,讀取訓練與測試用的圖片數據集
mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)
#取出訓練集數據、訓練集標簽
train_data, train_label = mnist.train.next_batch(train_sum)
?
#調用自創模塊內函數read_image():依照路徑傳入圖片處理,將圖片信息轉換成numpy.array類型
x1_tmp = it.read_image("png/55.png")
test_data = it.imageToArray(x1_tmp)
test_data = np.array(test_data)
#print('test_data',test_data)
#調用自創模塊內函數show_ndarray():用字符矩陣打印圖片
it.show_ndarray(test_data)
?
#KNN算法主體
all_dist = get_index(train_data,test_data,0)
all_number = get_number(all_dist)
min_number = get_min_number(all_number )
print('最后的預測值為:',min_number)
?
t2=datetime.datetime.now()
print('耗 時 = ',t2-t1)
評價:使用的訓練集、測試集數據來源于Google的那個經典的壓縮包。程序限制圖片數據大小是28*28的,也就是說像素點一共784個,所以缺陷在于(應該說是KNN算法缺陷硬傷)
大多數數據圖片占據的像素點很接近,距離區分度比較低;
未考慮不同數字間的內部結構特征
改善的方法有:
將圖片尺寸擴大,但這樣又會增加內存,使計算時間變長
規范的書寫測試數據
增大訓練數據集有效空間大小
這是我學習KNN算法做數字識別的啟蒙物,再次感謝老師的幫助與指導
第二個:32*32,0-1字符矩陣的數字識別
來源說明:算法實現功能的大體步驟是不會變的,只是實現的方法各有不同。網上又看到的《Python 手寫數字識別-knn算法應用》。雖然這位前輩一運用的是0-1字符矩陣,與之前Pierre老師的圖片有不同,但是前輩一的代碼更細致的展示出KNN算法實現的過程。源碼鏈接地址:https://www.cnblogs.com/chenbjin/p/3869745.html
獻丑再貼出自己的代碼:?
說明如下:大的優化沒有,由于我有自己習慣的名稱定義,修改了源代碼中大部分的名稱,小的修改也未注明?
注意:代碼中需要的訓練集、測試集數據均來源于上鏈接里,為了讓大家更清楚下面代碼的原理,強烈建議看完上面前輩的作品。
# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing
# -*- 2017/12/28
# -*- python3.5
?
from os import listdir
from numpy import *
import numpy as np
import operator
import datetime
?
def KNN(test_data,train_data,train_label,k):
??? #已知分類的數據集(訓練集)的行數
??? dataSetSize = train_data.shape[0]
??? #求所有距離:先tile函數將輸入點拓展成與訓練集相同維數的矩陣,計算測試樣本與每一個訓練樣本的距離
??? all_distances = np.sqrt(np.sum(np.square(tile(test_data,(dataSetSize,1))-train_data),axis=1))
??? #print("所有距離:",all_distances)
??? #按all_distances中元素進行升序排序后得到其對應索引的列表
??? sort_distance_index = all_distances.argsort()
??? #print("文件索引排序:",sort_distance_index)
??? #選擇距離最小的k個點
??? classCount = {}
??? for i in range(k):
??????? #返回最小距離的訓練集的索引(預測值)
??????? voteIlabel = train_label[sort_distance_index[i]]
??????? #print('第',i+1,'次預測值',voteIlabel)
??????? classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
??? #求眾數:按classCount字典的第2個元素(即類別出現的次數)從大到小排序
??? sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
??? return sortedClassCount[0][0]
?
#文本向量化 32x32 -> 1x1024
def img2vector(filename):
??? returnVect = []
??? fr = open(filename)
??? for i in range(32):
??????? lineStr = fr.readline()
??????? for j in range(32):
??????????? returnVect.append(int(lineStr[j]))
??? return returnVect
?
#從文件名中解析分類數字
def classnumCut(fileName):
??? #參考文件名格式為:0_3.txt
??? fileStr = fileName.split('.')[0]
??? classNumStr = int(fileStr.split('_')[0])
??? return classNumStr
?
#構建訓練集數據向量,及對應分類標簽向量
def trainingDataSet():
??? train_label = []
??? trainingFileList = listdir('trainingDigits')
??? m = len(trainingFileList)
??? train_data = zeros((m,1024))
??? #獲取訓練集的標簽
??? for i in range(m):
??????? # fileNameStr:所有訓練集文件名
??????? fileNameStr = trainingFileList[i]
??????? # 得到訓練集索引
??????? train_label.append(classnumCut(fileNameStr))
??????? train_data[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
??? return train_label,train_data
?
#測試函數
def main():
??? t1 = datetime.datetime.now()? # 計時開始
??? Nearest_Neighbor_number = int(input('選取最鄰近的K個值,K='))
??? train_label,train_data = trainingDataSet()
??? testFileList = listdir('testDigits')
??? error_sum = 0
??? test_number = len(testFileList)
??? for i in range(test_number):
??????? #測試集文件名
??????? fileNameStr = testFileList[i]
??????? #切片后得到測試集索引
??????? classNumStr = classnumCut(fileNameStr)
??????? test_data = img2vector('testDigits/%s' % fileNameStr)
??????? #調用knn算法進行測試
??????? classifierResult = KNN(test_data, train_data, train_label, Nearest_Neighbor_number)
??????? print ("第",i+1,"組:","預測值:",classifierResult,"真實值:",classNumStr)
??????? if (classifierResult != classNumStr):
??????????? error_sum += 1.0
??? print ("\n測試集總數為:",test_number)
??? print ("測試出錯總數:",error_sum)
??? print ("\n錯誤率:",error_sum/float(test_number)*100,'%')
??? t2 = datetime.datetime.now()
??? print('耗 時 = ', t2 - t1)
?
if __name__ == "__main__":
??? main()
評價:這位前輩一所使用的訓練集、測試集數據雖然是0-1矩陣,但是是可以通過代碼生成打印出來。除此之外,前輩一代碼的識別錯誤率比較低,測試時候946個測試數據只出錯11個,出錯率是1.16%,也就是成功率達98.84%。有圖有真相:?
大神一的方法也讓我檢驗了最合適的K值選定是3(大家自己動手試試,選取不同的K值,就能得到不同的錯誤率)
于是用大神一的方法,再結合米度教育Pierre老師的代碼,寫了第一份自己的手寫數字識別的代碼(這里就沒有貼出了)。問題總是在實際實現的過程中被發現——每個人用畫板寫出來的數字各不相同,形狀有大有小,筆畫有粗有細,就連同一個數字的結構比例都千差萬別。這對識別的成功率影響很大。恰當這時,無意中發現了大神二的方法——統一不同人寫出來的數字,也就是添加圖片預處理,加入切割、拉伸函數。
第三個:圖片預處理——切割、拉伸函數
大神二的原貼鏈接地址附上:http://m.blog.csdn.net/Hanpu_Liang/article/details/78237913?
大神二的思路如下:
將讀取的圖片先轉換成0-1矩陣形式
再根據灰度閾值,計算有效圖片的邊界索引,切割返回有效圖片的索引尺寸
切割后的有效圖片尺寸各不相同,運用拉伸函數將各不相同的有效圖片轉換成尺寸相同的有效圖片
最后用轉化后的同尺寸的訓練集、測試集數據求距離,做預測
貼出自己的代碼:注意圖片存放的路徑,標準大小N的值
# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing
# -*- 2017/12/29
# -*- python3.5
?
from skimage import io
import numpy as np
import os
?
#Standard size 標準大小
N = 100
#灰度閾值
color = 100/255
?
#讀取訓練圖片并保存
def GetTrainPicture(files):
??? Picture = np.zeros([len(files), N**2])
??? #enumerate函數用于遍歷序列中的元素以及它們的下標(i是下標,item是元素信息)
??? for i, item in enumerate(files):
??????? #讀取這個圖片并轉為灰度值(黑死字體為0,白底為255)
??????? img = io.imread('./png1/'+item, as_grey = True)
??????? #清除噪音
??????? img[img>color] = 1
??????? #將圖片進行切割,得到有手寫數字的的圖像
??????? img = CutPicture(img)
??????? #將圖片進行拉伸,得到標準大小100x100
??????? img = StretchPicture(img).reshape(N**2)
??????? #將圖片存入矩陣
??????? Picture[i, 0:N**2] = img
??????? #將圖片的名字存入矩陣(需要存入名字,上面語句改Picture = np.zeros([len(files), N**2+1]))
??????? #Picture[i, N**2] = float(item[0])
??? return Picture
?
#切割圖象
def CutPicture(img):
??? #初始化新大小
??? size = []
??? #圖片的行數
??? length = len(img)
??? #圖片的列數
??? width = len(img[0,:])
??? #計算新大小
??? size.append(JudgeEdge(img, length, 0, [-1, -1]))
??? size.append(JudgeEdge(img, width, 1, [-1, -1]))
??? size = np.array(size).reshape(4)
??? #print('圖像尺寸(高低左右):',size)
??? return img[size[0]:size[1]+1, size[2]:size[3]+1]
?
def JudgeEdge(img, length, flag, size):
??? for i in range(length):
??????? #判斷是行是列
??????? if flag == 0:
??????????? #正序判斷該行是否有手寫數字
??????????? line1 = img[img[i,:]<color]
??????????? #倒序判斷該行是否有手寫數字
??????????? line2 = img[img[length-1-i,:]<color]
??????? else:
??????????? line1 = img[img[:,i]<color]
??????????? line2 = img[img[:,length-1-i]<color]
??????? #若有手寫數字,即到達邊界,記錄下行
??????? if len(line1)>=1 and size[0]==-1:
??????????? size[0] = i
??????? if len(line2)>=1 and size[1]==-1:
??????????? size[1] = length-1-i
??????? #若上下邊界都得到,則跳出
??????? if size[0]!=-1 and size[1]!=-1:
??????????? break
??? return size
?
#拉伸圖像
def StretchPicture(img):
??? newImg = np.ones(N**2).reshape(N, N)
??? newImg1 = np.ones(N ** 2).reshape(N, N)
??? #對每一行/列進行拉伸/壓縮
??? #每一行拉伸/壓縮的步長
??? step1 = len(img[0])/N
??? #每一列拉伸/壓縮的步長
??? step2 = len(img)/N
??? #對每一行進行操作
??? for i in range(len(img)):
??????? for j in range(N):
??????????? newImg[i, j] = img[i, int(np.floor(j*step1))]
??? #對每一列進行操作
??? for i in range(N):
??????? for j in range(N):
??????????? newImg1[j, i] = newImg[int(np.floor(j*step2)), i]
??? return newImg1
?
#用字符矩陣打印圖片
def show_ndarray(pic):
??? for i in range(N**2):
??????? if(pic[0,i] == 0):
??????????? print ("*",end='')
??????? else:
??????????? print ("0",end='')
??????? if (i+1)%N == 0 :
??????????? print()
?
#得到在num目錄下所有文件的名稱組成的列表
filenames = os.listdir(r"png1")
#得到所有訓練圖像向量的矩陣
pic = GetTrainPicture(filenames)
#print('圖像向量的矩陣',pic)
#調用show_ndarray()函數:用字符矩陣打印圖片
show_ndarray(pic)
N*N,手寫數字識別(DIY版)
先來幾點說明:
處理的圖片大小要小于設定的N
測試集圖片名稱的首字母要是真實值
當前訓練集庫所包含的樣本比較少,需多添加
代碼如下:(具體的注釋隨代碼附上)
# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing
# -*- 2017/12/30
# -*- python3.5
?
import operator
import datetime
import numpy as np
from numpy import *
from os import listdir
from skimage import io
?
print('程序處理的圖片大小,建議不要超過200*200\n')
N = int(input('需要處理的圖片的大小(100至200),N='))
#N = 120??????????? # 圖片大小:N*N
color = 100 / 255???? # 灰度閾值
?
#KNN算法主體
def KNN(test_data,train_data,train_label,k):
??? #已知分類的數據集(訓練集)的行數
??? dataSetSize = train_data.shape[0]
??? #求所有距離:tile函數將輸入點拓展成與訓練集相同維數的矩陣,并計算測試樣本與每一個訓練樣本的距離
??? all_distances = np.sqrt(np.sum(np.square(tile(test_data,(dataSetSize,1))-train_data),axis=1))
??? #按all_distances中元素進行升序排序后得到其對應索引的列表
??? sort_distance_index = all_distances.argsort()
??? #選擇距離最小的k個點
??? all_predictive_value = {}
??? for i in range(k):
??????? #返回最小距離的訓練集的索引(預測值)
??????? predictive_value = train_label[sort_distance_index[i]]
??????? print('第',i+1,'次預測值',predictive_value)
??????? all_predictive_value[predictive_value] = all_predictive_value.get(predictive_value,0)+1
??? #求眾數:按classCount字典的第2個元素(即類別出現的次數)從大到小排序
? ??sorted_class_count = sorted(all_predictive_value.items(), key = operator.itemgetter(1), reverse = True)
??? return sorted_class_count[0][0]
?
#訓練集:得到訓練集數據矩陣、下標簽索引
def get_all_train_data():
??? train_label = []
??? train_file_list = listdir('trainlist')? #獲取目錄內容
??? m = len(train_file_list)?????????????????????? #m維向量的訓練集
??? #get_train_data函數:得到所有訓練集圖像的向量矩陣
??? train_data = get_all_data(train_file_list,1)
??? for i in range(m):
??????? file_name = train_file_list[i]??????? #fileNameStr:所有訓練集文件名
??????? train_label.append(get_number_cut(file_name))??? #得到訓練集下標
??? return train_label,train_data
?
#得到所有訓練集/測試集的向量矩陣(k=1訓練集傳入;k=0測試集傳入)
def get_all_data(file_list,k):
??? train_data = np.zeros([len(file_list), N**2])
??? #enumerate函數用于遍歷序列中的元素以及它們的下標(i是下標,item是元素信息)
??? for i, item in enumerate(file_list):
??????? if k == 1:
??????????? #訓練集:讀取圖片并轉為灰度值(黑字體為0,白底為255)
??????????? img = io.imread('./trainlist/'+ item, as_grey = True)
??????? else:
??????????? #測試集:讀取圖片并轉為灰度值(黑字體為0,白底為255)
??????????? img = io.imread('./testlist/' + item, as_grey = True)
??????? #降噪處理
??????? img[img>color] = 1
??????? #將圖片進行切割,保留有值的部分
??????? img = get_cut_picture(img)
??????? #將圖片進行拉伸,得到需求大小:N*N
??????? img = get_stretch_picture(img).reshape(N**2)
??????? #將處理后的圖片信息存入矩陣
??????? train_data[i, 0:N**2] = img
??????? #若將圖片的真實值存入矩陣(需要存入圖片索引,上面語句改train_data = np.zeros([len(file_list), N**2+1])
??????? #train_data[i, N**2] = float(item[0])
??? return train_data
?
#切割圖象
def get_cut_picture(img):
??? #初始化新大小
??? size = []
??? #圖片的行數
??? length = len(img)
??? #圖片的列數
??? width = len(img[0,:])
??? #計算新大小
??? size.append(get_edge(img, length, 0, [-1, -1]))
??? size.append(get_edge(img, width, 1, [-1, -1]))
??? size = np.array(size).reshape(4)
??? #print('圖像尺寸(高低左右):',size)
??? return img[size[0]:size[1]+1, size[2]:size[3]+1]
?
#獲取切割邊緣(高低左右的索引)
def get_edge(img, length, flag, size):
??? for i in range(length):
??????? #判斷是行是列
??????? if flag == 0:
??????????? #正序判斷該行是否有手寫數字
??????????? line1 = img[img[i,:]<color]
??????????? #倒序判斷該行是否有手寫數字
??????????? line2 = img[img[length-1-i,:]<color]
??????? else:
??????????? line1 = img[img[:,i]<color]
??????????? line2 = img[img[:,length-1-i]<color]
??????? #若有手寫數字,即到達邊界,記錄下行
??????? if len(line1)>=1 and size[0]==-1:
??????????? size[0] = i
??????? if len(line2)>=1 and size[1]==-1:
??????????? size[1] = length-1-i
??????? #若上下邊界都得到,則跳出
??????? if size[0]!=-1 and size[1]!=-1:
??????????? break
??? return size
?
#拉伸圖像
def get_stretch_picture(img):
??? newImg = np.ones(N**2).reshape(N, N)
??? newImg1 = np.ones(N ** 2).reshape(N, N)
??? #對每一行/列進行拉伸/壓縮
??? #每一行拉伸/壓縮的步長
??? step1 = len(img[0])/N
??? #每一列拉伸/壓縮的步長
??? step2 = len(img)/N
??? #對每一行進行操作
??? for i in range(len(img)):
??????? for j in range(N):
??????????? newImg[i, j] = img[i, int(np.floor(j*step1))]
??? #對每一列進行操作
??? for i in range(N):
??????? for j in range(N):
??????????? newImg1[j, i] = newImg[int(np.floor(j*step2)), i]
??? return newImg1
?
#從文件名中分解出第一個數字(真實值)
def get_number_cut(file_name):
??? fileStr = file_name.split('.')[0]??? ??????????#文件名格式為:0_3.txt
??? classNumStr = int(fileStr.split('_')[0])
??? return classNumStr
?
#用字符矩陣打印圖片
def get_show(test_data):
??? for i in range(N**2):
??????? if(test_data[0,i] == 0):
??????????? print ("1",end='')
??????? else:
??????????? print ("0",end='')
??????? if (i+1)%N == 0 :
??????????? print()
?
def main():
??? t1 = datetime.datetime.now()? # 計時開始
??? Nearest_Neighbor_number = int(input('選取最鄰近的K個值(建議小于7),K='))
??? #訓練集:get_train_data()函數得到訓練集數據矩陣、下標簽索引
??? train_label, train_data = get_all_train_data()
?
??? #測試集:根據路徑,獲取測試集地址
??? test_file_list = listdir('testlist')
??? file_name = test_file_list[0]
??? #測試集:運用切片函數,得到測試集下標索引(真實值)
??? test_index = get_number_cut(file_name)
??? #測試集:得到訓練集圖像的向量矩陣
??? test_data = get_all_data(test_file_list,0)
??? #測試集:get_show()函數:用字符矩陣打印圖片
??? #get_show(test_data)
?
??? #調用knn算法進行測試
??? Result = KNN(test_data, train_data, train_label, Nearest_Neighbor_number)
??? print ("最終預測值為:",Result,"??? 真實值:",test_index)
??? t2 = datetime.datetime.now()
??? print('耗 時 = ', t2 - t1)
?
if __name__ == "__main__":
??? main()
結果如下:?
?
評價:效果看起來還馬馬虎虎了,但是對于那些書寫不標準的,識別度還是較低,改善空間還是很大,歡迎大家相互指正,相互學習。
—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-——-—-—-—-—-—-—-—-—-—-—-—-—-—-——-?
這里還有一篇很好玩的實現方法,用到的是openCV?
代碼鏈接:http://blog.csdn.net/littlethunder/article/details/51615237?
視頻鏈接:http://www.bilibili.com/video/av4904541/?
真心有意思?
–—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-——-—-—-—-—-—-—-—-—-—-—-—-—-—-——-?
本篇所有的源碼資源都已上傳:https://download.csdn.net/download/zzz_cming/10377414?
–—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-——-—-—-—-—-—-—-—-—-—-—-—-—-—-——-?
總結
KNN算法是一種比較簡單的分類方法,人工智能入門級吧
KNN算法缺陷在于沒有考慮不同數字間在結構特征上的差異
感謝本文作者zzZ_CMing的投稿!
總結
以上是生活随笔為你收集整理的监督学习:KNN(K-近邻)算法实现手写数字识别的三种方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过听力写代码?盲人程序员就是这样做的
- 下一篇: 程序员找不到对象是因为还没遇到一个有远见