機器學習實戰之KNN算法

書上的代碼看不懂,自己寫了一個,就是太麻煩,書上才15行,我用了26行代碼,,可是我爲什麼看不懂別人的代碼啊!哭唧唧

主要是思路,這裏我用的數據特別簡單,就是自己寫了四個點,然後給他們標籤,來一個新的數據,通過計算該點與已知數據點(帶有標籤的那種)的距離,選取K個最近的點,統計這K個點的標籤,選取最多類別的那一個作爲最後該新輸入數據集的標籤,其實原理類似於說,你周圍的點是什麼樣子,其實大概率決定了你以後是什麼樣子。

接下來直接附上代碼。

# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 13:55:48 2018

@author: xuanxuan
"""
import numpy as np

#計算兩點之間的距離,把距離作爲key以及訓練數據的標籤作爲value存成一個字典
def comp_dis(X,L,Y):  #這裏傳的參數都是數組類型的
    D={}  #存儲計算的距離
    for i in range(len(X)):
        d=np.sqrt((X[i][0]-Y[0][0])**2+(X[i][1]-Y[0][1])**2)
        D[d]=L[i][0]

    #將存成的字典按照Key進行排序  返回一個數組,每一項第一個元素都是距離,另一個是相應的標籤;
    #只不過第一項是已經排好序的
    D_sorted=sorted(D.items(),key=lambda x:x[0])
    #print(D_sorted)
    return D_sorted


def Knn(D_sorted,k=2):
    d={}
    for i in range(k):
        key=D_sorted[i][1]
        if key not in d:
            d[key]=0
        else:
            d[key]+=1
    d_sorted=sorted(d.items(),key=lambda x:x[1],reverse=True)
    label=d_sorted[0][0]
    return label




if __name__=="__main__":
    train_data=np.array([[10,1],[10,2],[1,10],[1,8]])
    train_label=np.array([['A'],['A'],['B'],['B']])
    test_data=np.array([[5,1]])
    D_sorted=comp_dis(train_data,train_label,test_data)
    label=Knn(D_sorted,3)
    print("對該輸入數據的分類爲:\n{}".format(label))


************************下面是一個約會網站預測的例子**********************

這個數據集是機器學習實戰裏面的數據集。我看了一遍書,有了思路之後,然後用自己的方法實現了一下,其實主要還是對算法理解了才行,實現方式可以有很多種,還有就是對於書上的代碼順着敲一遍是沒有任何意義的,嘻嘻

可是,書上預測的錯誤率才0.024,我的竟然0.36,,,,哭唧唧
還有就是參數我選的80%訓練,20%測試,然後K選的10,好像是最好的了,按照課本的90%訓練 10%測試,K=3更不忍直視,能怎麼辦,寶寶也很絕望啊

下面是代碼:

# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 18:57:19 2018

@author: xuanxuan
"""
#knn算法應用在約會網站上

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cross_validation import train_test_split


#首先導入數據
def getdata():
    dataarr=[]
    labelarr=[]
    file=open("E:/pyhtonworkspace/py3-pratice/book_practice_python/mechinelearning_in_action/chapter02/datingTestSet2.txt")
    for line in file:
        linearr=line.strip().split()
        L=[]
        for s in linearr:
            L.append(float(s))
        dataarr.append(L[:-1])  
        labelarr.append(L[-1])  
    datamat=np.mat(dataarr)      #把訓練數據轉變爲1000*3的矩陣
    labelmat=np.mat(labelarr).T  #把測試數據轉變爲1000*1的矩陣
    return datamat,labelmat 


def draw(datamat,labelmat):

    m=np.shape(datamat)[0]
    for i in range(m):
        plt.scatter(datamat[i,0],datamat[i,1],10*labelmat[i,0],4*labelmat[i,0])

    plt.show()

#主要是對數據進行歸一化處理
def norm(datamat0):
    m,n=np.shape(datamat0)
    max=datamat0.max(0)  #1*3的矩陣
    min=datamat0.min(0)  #1*3的矩陣
    #print(max,min)
    dataarr=[]
    for i in range(m):
        L=[]
        for j in range(n):
            a=(datamat0[i,j]-min[0,j])/(max[0,j]-min[0,j])
            L.append(float(a))
        dataarr.append(L)
    datamat=np.mat(dataarr)
    #print(datamat[:10])
    return datamat  #返回歸一化之後的數據矩陣

def predict(d_new,k):  #這裏的d_new是一個列表 裏邊的元素是tuple!!
    d={}
    for i in range(k):
        key=d_new[i][1]
        if key not in d:
            d[key]=0
        else:
            d[key]+=1

    #現在的d是key-value:標籤-個數的字典,現在需要按照value進行排序(降序主要是多數表決着最多的類別數作爲該測試點最終的樣本標籤)
    d_sorted=sorted(d.items(),key=lambda x:x[1],reverse=True)
    return d_sorted[0][0]  #返回的是最終對該樣本預測的標籤


def KNN(train_data,train_label,test_data,test_label,k=15):
    m=np.shape(test_data)[0]    #測試數據集的維度 m*3
    n=np.shape(train_data)[0] #訓練數據集的維度 n*3
    num=0  #用來統計預測錯誤率的
    for i in range(m):
        d={}  #用來存放測試集中該樣本與訓練集中相應點之間的距離,以及相應的標籤
        for j in range(n):
            dis=np.sqrt((test_data[i,0]-train_data[j,0])**2+(test_data[i,1]-train_data[j,1])**2+(test_data[i,2]-train_data[j,2]**2))
            d[dis]=train_label[j,0]  #存成一個字典,key-value:距離,標籤
        d_new=sorted(d.items(),key=lambda x:x[0])  #對字典的key進行排序(升序,主要是着距離最近的k個點) 返回一個tuple!!!而不再是字典了不過對應的仍然是距離-標籤 的形式
        pre=predict(d_new,k)
        if pre!=test_label[i]:
            num+=1
    error=num/m
    return error




if __name__=="__main__":
    datamat0,labelmat=getdata()
    datamat=norm(datamat0)  #將數據及逆行歸一化之後返回的數據矩陣
    #draw(datamat,labelmat)
    train_data,test_data,train_label,test_label=train_test_split(datamat,labelmat,test_size=0.25,random_state=33)
    error=KNN(train_data,train_label,test_data,test_label,10)
    print("使用KNN算法預測的錯誤率爲:\n{}".format(error))


還有就是,我實現一個算法要好久,三個小時,怎麼肥si?
明天也要加油鴨~~~

******************************KNN算法識別手寫數字**********************

看完書之後按照自己的理解實現了一下,可是爲什麼我運行不出來啊,是我的電腦有問題,嗯,我邏輯是對的~~~
是電腦配置太低了嘛,,,

接下來直接附上代碼啦~~

# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 21:56:21 2018

@author: xuanxuan
"""

#識別手寫數字,使用K近鄰算法
import numpy as np
from os import listdir

#讀取其中一個文件比如0_0.txt 把該文件作爲一個樣本,共有1024個特徵
def openfile(filename):
    file=open(filename)
    dataarr=[]
    for i in range(32):
        line=file.readline()
        for j in range(32):
            dataarr.append(int(line[j]))

    return dataarr  #返回的是一個列表 裏面由1024個元素,代表一個文件樣本的1024個特徵



def get_data1():

    filenames=listdir("E:/pyhtonworkspace/py3-pratice/book_practice_python/mechinelearning_in_action/chapter02/digits/trainingDigits" )
    m=len(filenames)  #訓練數據集中文件個數(樣本數)
    labels=[]
    datas=[]
    for i in range(m):
        L=[]
        filename=filenames[i]
        filenamenum=filename.split('.')[0]
        label=filenamenum.split('_')[0]
        L.append(label)  #對於每一個樣本都有一個label標籤,把所有的label存在一個列表labels
        labels.append(L)
        data=openfile("E:/pyhtonworkspace/py3-pratice/book_practice_python/mechinelearning_in_action/chapter02/digits/trainingDigits" +'/'+filename)
        datas.append(data)
    datamat=np.mat(datas)
    labelmat=np.mat(labels)
    #print(np.shape(labelmat))  #維度是(1934,1)
    #print(np.shape(datamat))   #維度是(1934,1024)
    return datamat,labelmat    


#get_data()
def get_data2():

    filenames=listdir("E:/pyhtonworkspace/py3-pratice/book_practice_python/mechinelearning_in_action/chapter02/digits/testDigits" )
    m=len(filenames)  #訓練數據集中文件個數(樣本數)
    labels=[]
    datas=[]
    for i in range(m):
        L=[]
        filename=filenames[i]
        filenamenum=filename.split('.')[0]
        label=filenamenum.split('_')[0]
        L.append(label)  #對於每一個樣本都有一個label標籤,把所有的label存在一個列表labels
        labels.append(L)
        data=openfile("E:/pyhtonworkspace/py3-pratice/book_practice_python/mechinelearning_in_action/chapter02/digits/testDigits" +'/'+filename)
        datas.append(data)
    datamat=np.mat(datas)
    labelmat=np.mat(labels)
    #print(np.shape(labelmat))  #維度是(946,1)
    #print(np.shape(datamat))   #維度是(946,1024)
    return datamat,labelmat    

def predict(D,K):
    D_list=sorted(D.items(),key=lambda x:x[0])  #對D按照key(距離)進行排序(升序)  得到的結果是一個列表!!列表中每一個元素都是一個tuple對應着距離和標籤
    D1={}
    for i in range(K):
        key=D_list[i][1]
        if key not in D1:
            D1[key]=0
        else:
            D1[key]+=1  #D2是一個字典 key-value 是標籤-該標籤出現的次數
    D1_list=sorted(D1.items(),key=lambda x:x[1],reverse=True)  #對D1按照value進行排序 ,也就是距離最小的k個訓練樣本中出現標籤最多的那個作爲該測試樣本的標籤
    pred=D1_list[0][0]  #作爲最終的預測標籤
    return pred






def KNN(test_datamat,test_labelmat,train_datamat,train_labelmat,K=9):
    m1,n=np.shape(test_datamat)  #測試樣本數和特徵數
    m2=np.shape(train_datamat)[0] #訓練樣本數
    num_error=0
    for i in range(m1):
        D={}
        for j in range(m2):
            d=0
            for k in range(n):
                d+=(test_datamat[i,k]-train_datamat[j,k])**2
            d=d**0.5
            D[d]=train_labelmat[j,0]   #D字典key-value:測試集合中的一個樣本和訓練集中每一個樣本的距離-和訓練集中對應樣本的標籤
        pred=predict(D,K)
        if pred!=test_labelmat[i,0]:
            num_error+=1
    error=num_error/m1
    return error





if __name__=="__main__":
    train_datamat,train_labelmat=get_data1()
    test_datamat,test_labelmat=get_data2()
    error=KNN(test_datamat,test_labelmat,train_datamat,train_labelmat)
    print("使用KNN算法的錯誤率爲:\n{}".format(error))


明天也要加油鴨~~

今天不開心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章