1. 程式人生 > >K-means實現二分類問題

K-means實現二分類問題

最近做一個有關二分類問題,我打算使用K-means演算法實現baseline。

首先,我的資料檔案形式是“.arff”格式的,在處理這種資料格式的時候,我是花了一些精力的,話不多說,程式碼如下:

import numpy as np

def readarff(filename):
    #dataMat=np.zeros(shape=(1000,4096))
    dataMat=[[0 for i in range(4096)] for j in range(591)]
    arff_file=open(filename)
    lines=arff_file.readlines()
    count
=0 for l in lines: content=[] if not (l.startswith("@")): content.append(l) for c in content: cs=c.split(',') cs.pop(0) cs.pop(0) cs.pop(0) flag=True while flag: temp
=cs[0].split(' ') index=int(temp[1]) if not(index==4099): dataMat[count][index-3]=(float)(temp[2]) #print count #print index-4 cs.pop(0) else: flag
=False count=count+1 dataMat=np.matrix(dataMat) return dataMat dataMat=readarff('data/temp1.arff')

我的資料檔案中,前三個屬性是不應該作為特徵屬性的,這就是出現了三個pop()的原因。

dataMat是一個數據矩陣,這個矩陣也是最後需要的一個返回值。關於這個矩陣,在初始化時,一定要使用:

dataMat=[[0 for i in range(4096)] for j in range(591)]

這種形式,而不要使用:

dataMat=[[0]*4096]*591

因為,如果使用下面這種形式的話,在給矩陣賦值的時候,例如:

dataMat[0][0]=0.123456

這樣改變的不只是(0,0)這一個位置的值,而是會改變所有行的第0列的值。(具體知識點涉及到了list的淺拷貝問題,可以參照:https://www.cnblogs.com/btchenguang/archive/2012/01/30/2332479.html)

另外,由於我的資料格式是“ 1 0.123456789”,第二個數字才是我需要的,這也就是我為什麼使用split對空格進行分割的原因了。

還有一個注意點:

就是我的強制型別轉換那一步:

dataMat[count][index-3]=(float)(temp[2])

這裡如果不進行強制型別轉化,會發現在後面進行K-means演算法時,資料之間的運算會出問題,這是因為,這個矩陣中資料型別是unicode型的。

下面就是K-means演算法了:

#計算歐幾里得距離
def
distEclud(vecA,vecB): return sqrt(sum(power(vecA-vecB,2))) # 計算兩個向量之間的距離
#隨機生成k個質心
def randCent(dataSet,k): #n=shape(dataSet)[1] n=dataSet.shape[1] centroids=mat(zeros((k,n))) for j in range(n): minJ=min(dataSet[:,j]) maxJ=max(dataSet[:,j]) rangeJ=float(maxJ-minJ) #這一步就是上面說的如果不進行強制型別轉換會出現問題的位置 centroids[:,j]=minJ+rangeJ*random.rand(k,1) return centroids
#k-means演算法:
def kMeans(dataSet,k,distMeans=distEclud,createCent=randCent): m=dataSet.shape[0] clusterAssment=mat(zeros((m,2))) #存放該樣本屬於哪類,以及距質心的距離 centroids=createCent(dataSet,k) clusterChanged=True while clusterChanged: clusterChanged=False; for i in range(m): minDist=inf;minIndex=-1; for j in range(k): distJI=distMeans(centroids[j,:],dataSet[i,:]) if distJI<minDist: minDist=distJI;minIndex=j if clusterAssment[i,0]!=minIndex:clusterChanged=True; clusterAssment[i,:]=minIndex,minDist**2 print(centroids) #在每一輪迭代後都輸出一次質心的座標
      #更新質心點的座標
for cent in range(k): ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] centroids[cent,:]=mean(ptsInClust,axis=0) return centroids,clusterAssment datMat=mat(readarff('data/temp1.arff')) myCentroids,clustAssing=kMeans(datMat,2) print(myCentroids) print(clustAssing)

K是類別的個數,這裡我定為了2,;具體情況可以自己改變。