手寫識別也是當前機器學習的一大熱點,數字手寫識別是手寫識別中的基礎,咱們用到的是knn算法,今天給你們講一下個人實現方法;git
IDE:Eclipse
語言:Javagithub
數據採集:咱們知道,一張圖片能夠被看做一個個點組成的矩陣,對於手寫數字,咱們只要建立一個全0數組看成背景,手寫完畢把數字所佔區域置爲1,就能夠保存看成一個樣本了,以下圖所示。
算法:KNN算法,其距離度量咱們採用歐拉距離。
歐拉距離計算方法:咱們將數組看做40*40向量,採用距離公式計算。web
請原諒做者對於美笨拙的感知,我所繪製的界面不可以再簡單了。如圖:算法
面板按鈕介紹:數組
在數據讀取存儲上走了不少彎路,以後要好好總結下數據流的幾個傳輸方式。
咱們將每張圖片轉化爲一個二維數組後,存放進一個txt文件中。對於每一個單獨的文件,咱們要產生一個獨一無二的文件名,因此文件取名方式採起「數字+隨機id .txt」的格式命名,隨機id咱們經過構造UID對象,獲取其hashcode值做爲id。app
//獲取下拉框選中的數字
String selectedNumber=cbItem.getSelectedItem().toString();
UID id=new UID();
//文件的前綴路徑
String rootPath="C:\\Users\\DearYou\\eclipse-workspace\\GUI\\src\\Demo\\handwritingIdentify\\TrainingData\\";
//生成文件名
String fileName=selectedNumber+"-"+id.hashCode();
//生成絕對路徑下的一個文件
String absoluteFile=rootPath+fileName+".txt";
File file=new File(absoluteFile);
try {
//建立文件
if(!file.exists())
file.createNewFile();
//將數組寫入文件
FileWriter out = new FileWriter(file);
for(int i=0;i<40;i++) {
for(int j=0;j<40;j++) {
out.write(pixel[i][j]+"");
}
}
out.flush();
out.close();
}catch(Exception e1) {
e1.printStackTrace();
}
Common thinking :KNN目的是找到k個離測試樣本最近的訓練樣本,看了下同窗的方法,大多都使用了排序,但本身想一想排序實在是多餘,一個排序就將複雜度升到了O(nlgn),數據容量一大,性能就會降低。
My thinking:我想咱們只要找到k個距離最近的樣本,和順序並無關係。筆者細想了一下,我麼只要構建一個大小爲k的數組或者隊列,對於前k個元素,咱們直接放進數組,後面的n-k個元素,咱們找到存放在數組中的k個元素中最大值,將兩者比較看是否替代。這樣咱們只需遍歷一遍,複雜度降爲O(n),也是一種小優化。eclipse
僞代碼:
KnnNode[] dist=new KnnNode[k];
for(int i=0->k){
KnnNode temp=new KnnNode(distance);
dist.append(temp)
}
for(the rest of test set){
if(temp.distance < the maximum element in dist)
dist[index of max]=temp;
}
方法以下展現:
咱們也能夠在識別以後保存該樣本,這樣不能不斷擴大數據集,讓精度更高。機器學習
雖然能在O(n)複雜度裏實現Knn算法,可是個人knn延展性太差,我應該能夠把這個knn的參數換成算好的距離,而不是傳入的數組,這樣就能將這個KNN封裝好方便之後再用。
源代碼參考地址:https://github.com/Gray-way/HandwritingRecognitionsvg