無監督學習——K-均值聚類算法對未標註數據分組
無監督學習
和監督學習不同的是,在無監督學習中數據並沒有標簽(分類)。無監督學習需要通過算法找到這些數據內在的規律,將他們分類。(如下圖中的數據,並沒有標簽,大概可以看出數據集可以分為三類,它就是一個無監督學習過程。)
無監督學習沒有訓練過程。
聚類算法
該算法將相似的對象軌道同一個簇中,有點像全自動分類。簇內的對象越相似它的分類效果越好。
未接觸這個概念可能覺得很高大上,稍微看了一會其實算法的思路和KNN一樣很簡單。
原始數據集如下(數據有兩個特征,分別用橫縱坐標表示),原始數據集並沒有任何標簽和分類信息:
由圖中的數據可以大概判斷,該數據集可以分為三類數據(定義為0,1,2),那麽每個點到底屬於哪個分類呢,這裏通過K-均值聚類算法得到三個質心點,並根據每個點到三個質心的距離進行分類(到0,1,2三個質心距離最近,則將該數據分為該類),計算出的三個質心點如下圖(圖中紅叉點表示):
K-均值聚類算法
該算法的流程如下:
1. 加載數據集 2. 數據初始化 2.1 創建隨機質心點 2.2 穿件保存結果的各個矩陣/數組 3. 多次叠代 (判斷所有點的分類是否發生變化) 3.1 計算所有點的分類 3.2 根據3.1分類結果,重新計算質心點(用屬於當前類的數據取平均作為新的質心點) 4. 返回數據
該算法缺點:
算法容易收斂到局部最小值,而非全局最小值。(局部最小值指結果還可以,但是並非最好結果,全局最小值時可能的最好結果)
二分K-均值聚類算法
SSE: 度量聚類效果的指標(Sum of Squared Erro,誤差平方和)
SSE越小說明所有數據點越接近他們的質心,聚類效果也就越好。
該算法的流程如下:
1. 將所有點看成一個簇 2. 當簇數目小於K時 2.1 對每個簇 2.1.1 計算總誤差 2.1.2 在給定簇上面進行K-均值聚類(K=2) 2.1.2 計算在該簇上一分為二之後的總誤差 2.2 選擇是的誤差最小的那個簇進行劃分
Python實現
數據加載
def loadDataSet(fileName): #general function to parse tab -delimited floats dataMat = [] #assume last column is target valuefr = open(fileName) for line in fr.readlines(): curLine = line.strip().split(‘\t‘) fltLine = map(float,curLine) #map all elements to float() dataMat.append(fltLine) return dataMat
數據的形式如下,和監督學習數據形式最大的區別是這裏的數據是不帶有標簽的數據。每個數據是一個二維的向量。
3.275154 2.957587 -3.344465 2.603513 0.355083 -3.376585 1.852435 3.547351 -2.078973 2.552013 -0.993756 -0.884433 2.682252 4.007573 -3.087776 2.878713 -1.565978 -1.256985 2.441611 0.444826 -0.659487 3.111284 -0.459601 -2.618005 2.177680 2.387793 -2.920969 2.917485 -0.028814 -4.168078 3.625746 2.119041 -3.912363 1.325108 -0.551694 -2.814223 2.855808 3.483301 ..................
向量歐式距離計算函數
def distEclud(vecA, vecB): return sqrt(sum(power(vecA - vecB, 2))) #la.norm(vecA-vecB)
隨機產生n個質心
def randCent(dataSet, k): n = shape(dataSet)[1] centroids = mat(zeros((k,n)))#create centroid mat for j in range(n):#create random cluster centers, within bounds of each dimension minJ = min(dataSet[:,j]) rangeJ = float(max(dataSet[:,j]) - minJ) centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1)) return centroids
K-均值聚類算法
缺點: 該算法必須要業務提前輸入分類的個數K。
該函數返回值為質心坐標centroids,以及每個點最近的質心(即該點的分類結果)和它的距離clusterAssment。
這裏需要註意叠代的終止條件: clusterChanged,該標記位用來標記此次叠代是否有數據的分類和上一次得帶不同,如果當前這次叠代的對所有數據的分類和上一次分類結果完全相同,則不再繼續叠代。
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): #計算數據個數 m = shape(dataSet)[0] # 存放每個數據到哪個質心距離最近,以及它的距離值 clusterAssment = mat(zeros((m,2)))#create mat to assign data points #to a centroid, also holds SE of each point centroids = createCent(dataSet, k)#產生隨機的質心點(通過叠代,逐步變得精確) clusterChanged = True #分類是否改變,叠代結束的條件 while clusterChanged: clusterChanged = False for i in range(m):#for each data point assign it to the closest centroid minDist = inf; minIndex = -1 for j in range(k): distJI = distMeas(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):#recalculate centroids #ptsInClust表示到該質心距離最近的點集合 ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]#get all the point in this cluster #將質心坐標 用最近點坐標的均值代替,所以稱為均值聚類算法 centroids[cent,:] = mean(ptsInClust, axis=0) #assign centroid to mean return centroids, clusterAssment
二分K-均值算法
該算法的輸入和輸出和K-均值算都相同,只是它的內部實現更復雜。
def biKmeans(dataSet, k, distMeas=distEclud): m = shape(dataSet)[0] clusterAssment = mat(zeros((m,2))) centroid0 = mean(dataSet, axis=0).tolist()[0] centList =[centroid0] #create a list with one centroid for j in range(m):#calc initial Error clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2 while (len(centList) < k): lowestSSE = inf for i in range(len(centList)): ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]#get the data points currently in cluster i centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas) sseSplit = sum(splitClustAss[:,1])#compare the SSE to the currrent minimum sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1]) print "sseSplit, and notSplit: ",sseSplit,sseNotSplit if (sseSplit + sseNotSplit) < lowestSSE: bestCentToSplit = i bestNewCents = centroidMat bestClustAss = splitClustAss.copy() lowestSSE = sseSplit + sseNotSplit bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList) #change 1 to 3,4, or whatever bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit print ‘the bestCentToSplit is: ‘,bestCentToSplit print ‘the len of bestClustAss is: ‘, len(bestClustAss) centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids centList.append(bestNewCents[1,:].tolist()[0]) clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss#reassign new clusters, and SSE return mat(centList), clusterAssment
其它機器學習算法:
監督學習——隨機梯度下降算法(sgd)和批梯度下降算法(bgd)
監督學習——決策樹理論與實踐(上):分類決策樹
監督學習——決策樹理論與實踐(下):回歸決策樹(CART)
監督學習——K鄰近算法及數字識別實踐
監督學習——樸素貝葉斯分類理論與實踐
監督學習——logistic進行二分類(python)
監督學習——AdaBoost元算法提高分類性能
參考:
《機器學習實戰》
無監督學習——K-均值聚類算法對未標註數據分組