最近鄰方法


【簡介】

  鄰近算法,或者說K最近鄰(kNN,k-NearestNeighbor)分類算法是數據挖掘分類技術中最簡單的方法之一。所謂K最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。kNN算法的核心思想是如果一個樣本在特征空間中的k個最相鄰的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別,並具有這個類別上樣本的特性。該方法在確定分類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。 kNN方法在類別決策時,只與極少量的相鄰樣本有關。由於kNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,kNN方法較其他方法更為適合(來自百度百科)。
【最近鄰算法】
  最近鄰算法通過計算預測點與測試樣例點數據的歐式距離,找出待測數據與測試數據的最小歐式距離點,並返回該測試點的類型,從而確定預測數據類型的算法。
#coding:utf-8  
import sys  
from numpy import *  
import operator  
import matplotlib.pyplot as plt    
  
def classify(input,dataSet,label):  
    dataSize = dataSet.shape[0]  
    ####計算歐式距離  
    tarry=tile(input,(dataSize,1));#生成dataSet一樣的矩陣,進行剪發運算
    diff = tarry - dataSet  
    sqdiff = diff ** 2  #各參數平方(X²,Y²),得到距離
    squareDist = sum(sqdiff,axis = 1)#行向量分別相加,從而得到新的一個行向量  X²,Y²相加,
    dist = list(squareDist ** 0.5)  #開放,得到歐式距離
    return label[dist.index(min(dist))]  #返回最近鄰  //找到距離最小值,並得與之對應的類型
  
  
dataSet = array([[0.1,2.8],[1.9,0.6],[1.0,2.0],  
                 [3.0,2.5],[2.0,2.5],[1.8,3.0],  
                 [0.1,0.1],[0.5,0.5],[1.5,0.5],  
                 [1.5,1.5],[1.7,0.1],[2.5,0.2],  
                 ])  
labels = ['A','A','A','B','B','B','C','C','C','D','D','D']  
  
input = array([1.9,0.5])  
  
print("input = ",input)  
output = classify(input,dataSet,labels)  
print("class = ",output)  
  
plt.figure(figsize=(5,5))    
  
for i,j in enumerate(dataSet):  
    if labels[i] == 'A':  
        plt.scatter(j[0],j[1],marker ="^",c="blue",s=80)   
    elif labels[i] == 'B':  
        plt.scatter(j[0],j[1],marker ="D",c ="green",s=80)   
    elif labels[i] == 'C':  
        plt.scatter(j[0],j[1],marker ="o",c ="darkorange",s=80)  
    elif labels[i] == 'D':  
        plt.scatter(j[0],j[1],marker ="s",c ="purple",s=80)   
  
plt.scatter(input[0],input[1],marker ="*",c ="red",s=200)   
  
plt.axis('tight')    
    
plt.show()
View Code

結果:

【K近鄰算法】

  最近鄰算法的最大缺陷是對干擾數據過於敏感,為了解決這個問題,我們可以把未知樣本周邊的多個鄰近樣本計算在內,擴大參與決策的樣本量,以避免個別數據直接決定決策結果。由此,我們引進K-最近鄰算法(KNN)。K近鄰算法是最近鄰算法的一個延伸。思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。一般情況下,在分類時較大的K值能夠減小干擾數據的影響。

#coding:utf-8  
import sys  
from numpy import *  
import operator  
import matplotlib.pyplot as plt    
  
###通過KNN進行分類  
def classify(input,dataSet,label,k):  
    dataSize = dataSet.shape[0]  
    ####計算歐式距離  
    diff = tile(input,(dataSize,1)) - dataSet  
    sqdiff = diff ** 2  
    squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而得到新的一個行向量  
    dist = squareDist ** 0.5  
      
    ##對距離進行排序  
    sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標  
  
    classCount={}  
    for i in range(k):  
        voteLabel = label[sortedDistIndex[i]]  
        ###對選取的K個樣本所屬的類別個數進行統計  
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1  
    ###選取出現的類別次數最多的類別  
    maxCount = 0  
    for key,value in classCount.items():  
        if value > maxCount:  
            maxCount = value  
            classes = key  
  
    return classes     
  
  
dataSet = array([[0.1,2.8],[1.9,0.6],[1.0,2.0],  
                 [3.0,2.5],[2.0,2.5],[1.8,3.0],  
                 [0.1,0.1],[0.5,0.5],[1.5,0.5],  
                 [1.5,1.5],[1.7,0.1],[2.5,0.2],  
                 ])  
labels = ['A','A','A','B','B','B','C','C','C','D','D','D']  
  
input = array([1.9,0.5])  
  
  
print("input = ",input)  
for K in range(1,13):  
    output = classify(input,dataSet,labels,K)  
    print("K = ",K,"class = ",output)  
  
  
plt.figure(figsize=(5,5))    
  
for i,j in enumerate(dataSet):  
    if labels[i] == 'A':  
        plt.scatter(j[0],j[1],marker ="^",c="blue",s=80)   
    elif labels[i] == 'B':  
        plt.scatter(j[0],j[1],marker ="D",c ="green",s=80)   
    elif labels[i] == 'C':  
        plt.scatter(j[0],j[1],marker ="o",c ="darkorange",s=80)  
    elif labels[i] == 'D':  
        plt.scatter(j[0],j[1],marker ="s",c ="purple",s=80)   
  
plt.scatter(input[0],input[1],marker ="*",c ="red",s=200)   
  
plt.axis('tight')    
    
plt.show() 
View Code

結果:

 【K-Means++算法

  K-Means++算法在聚類中心的初始化過程中的基本原則是使得初始的聚類中心之間的相互距離盡可能遠,這樣可以避免出現上述的問題。K-Means++算法的初始化過程如下所示:

  在數據集中隨機選擇一個樣本點作為第一個初始化的聚類中心

  選擇出其余的聚類中心: 

  計算樣本中的每一個樣本點與已經初始化的聚類中心之間的距離,並選擇其中最短的距離,記為d_i 以概率選擇距離最大的樣本作為新的聚類中心,

重復上述過程,直到k個聚類中心都被確定 對k個初始化的聚類中心,利用K-Means算法計算最終的聚類中心。

#隨機生成數據
def CreateDataset(number):
    #生成數組
    dataArry=np.zeros((number,2));
    #轉為矩陣
    dataSet=np.mat(dataArry);
    #數據分類聚類
    offset=[[-80,-80],[-80,80],[-20,-20],[0,0],[80,-80],[30,-80],[80,80]];
    #生成隨機數據
    for i in range(number):
        dataSet[i]=np.random.uniform(-20,20)+offset[i%7][0],np.random.uniform(-20,20)+offset[i%7][1];
    #返回數據
    return dataSet;

#矩陣求歐式距離
def Distance(vectot1,vector2):
    #求樣本數據差
    sub=vector2-vectot1;
    #求矩陣平方
    pows=np.power(sub,2);
    _sum=np.sum(pows);
    #求距離
    distance=np.sqrt(_sum);
    return distance;

#求樣本數據在聚集點數據中的最近點
def nearest(point,cluster_centers):
    #線初始化一個比較大的最小值
    min_dis=10000000;
    # 當前已經初始化的聚類中心的個數
    m=np.shape(cluster_centers)[0];
    #遍歷聚類中心
    for i in range(m):
        #計算point與每個聚類中心的距離
        d=Distance(point,cluster_centers[i,]);
        #判斷是否小是最短距離
        if min_dis>d:
            min_dis=d;
    return min_dis;
        
#生成聚類點
def clusterCenter(dataSet,k):
    #1、獲取樣本數據集的shape
    num,dim=dataSet.shape;
    #2、創建聚集點集
    clusterPoints=np.zeros((k,dim));
    cluster_centers=np.mat(clusterPoints);
    #3、隨機在樣本數據中選取一個點作為第一個聚集點
    index=np.random.randint(0,num);
    cluster_centers[0,]=dataSet[index,];
    #4、初始化一個距離序列
    disList=[0.0 for _ in range(num)];
    #5、從第二個點開始遍歷聚合點(第一個點已經賦值了)
    for i in range(1,k):
        sum_all=0;
        for j in range(num):
            #6、對每一個樣本點找到最近的聚類中心
            point=dataSet[j,];#獲取第j個樣本
            cluster_points=cluster_centers[0:i,];#獲取前i個樣本數據
            disList[j]=nearest(point,cluster_points);
            #7、將所有最短距離相加
            sum_all=sum_all+disList[j];
        #8、獲取sum_all之間的隨機值
        sum_all = np.random.uniform(0,int(sum_all));
        # 9、獲得距離最遠的樣本點作為聚類中心點
        for j, di in enumerate(disList):
            sum_all -= di
            if sum_all > 0:
                continue
            cluster_centers[i] = dataSet[j,];
            break
    return cluster_centers;

#K-Means聚類
def kmeans(data,k,centroids):
    #獲取樣本維度,m表示樣本個數,n表示樣本維度
    m,n=np.shape(data);
    #初始化樣本所屬類別
    subCenter=np.mat(np.zeros((m,n)));
    #初始化判斷變量
    change=True;
    #訓練數據
    while change==True:
        #重置變量
        change=False;
        #遍歷樣本數據
        for i in range(m):
            minDis=10000000;#初始化最小數據
            minIndex=0;#初始化最小距離的
            #遍歷聚集點
            for j in range(k):
                #計算兩點距離
                dist=Distance(data[i,],centroids[j,]);
                #判斷距離是否為最小
                if dist <minDis:
                    minDis=dist;
                    minIndex=j;
            #判斷是否需要改變  subCenter[i,0]不等於minindex
            if subCenter[i,0] != minIndex:
                change=True;
                subCenter[i,]=np.mat([minIndex, minDis])
        #重新計算聚類中心
        for j in range(k):
            #創建數據維度的總和矩形
            sum_all=np.mat(np.zeros((1,n)));
            count=0;#沒類的樣本個數
            #循環所屬類別數據
            for i in range(m):
                if subCenter[i,0]==j:
                    sum_all+=data[i,];
                    count+=1;
            #遍歷數據維度
            for z in range(n):
                try:
                    centroids[j,z]=sum_all[0,z]/count;
                except:
                    print("count為零");
    return  subCenter;

#保存聚類數據   
def save_result(file_name, source):
    m, n = np.shape(source)
    f = open(file_name, "w")
    for i in range(m):
        tmp = []
        for j in range(n):
            tmp.append(str(source[i, j]))
        f.write("\t".join(tmp) + "\n")
    f.close()
    print("保存完成");
    
#主函數
if __name__=="__main__":
    dataNum=300;#樣本數據集量
    k=7;#分類數
    # 1、創建數據
    dataSet=CreateDataset(dataNum);
    print("數據初始化完成");
    #生成聚合點
    cluster_centers=clusterCenter(dataSet,k);
    print("生成聚合點");
    #開始聚類
    subcenter=kmeans(dataSet,k,cluster_centers);
    print("聚類完成");
    #保存數據所屬類別數據
    save_result("subcenter.txt",subcenter);
    #保存數據所屬類別數據
    save_result("cluster_centers.txt",cluster_centers);
    #畫圖
    #plt.figure(figsize=(-100,100));
    #繪制數據
    numSamples, dim = dataSet.shape  
    mark = ['or', 'og', 'ob', 'oc', 'om', 'oy', 'ok', 'ow']  
    for i in range(numSamples):  
        markIndex = int(subcenter[i, 0]);
        plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex-1])
    #繪制聚合點
    mark = ['*r', '*g', '*b', '*c', '*m', '*y', '*k', '*w']  
    for i in range(k):  
        plt.plot(cluster_centers[i, 0], cluster_centers[i, 1], mark[i-1], markersize = 12) 
    plt.axis('tight')    
    plt.show()  
    print("完成");

 

 【參考文獻】

https://blog.csdn.net/sm9sun/article/details/78521927

https://www.cnblogs.com/charlesblc/p/6193979.html

http://blog.csdn.net/acdreamers/article/details/44672305

http://blog.csdn.net/u013414741/article/details/47108317

https://www.cnblogs.com/ybjourney/p/4702562.html

https://blog.csdn.net/google19890102/article/details/53284285


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM