1. 程式人生 > >k-means演算法與Python實踐

k-means演算法與Python實踐


       機器學習演算法與Python實踐這個系列主要是參考《機器學習實戰》這本書。因為自己想學習Python,然後也想對一些機器學習演算法加深下了解,所以就想通過Python來實現幾個比較常用的機器學習演算法。恰好遇見這本同樣定位的書籍,所以就參考這本書的過程來學習了。

       機器學習中有兩類的大問題,一個是分類,一個是聚類。分類是根據一些給定的已知類別標號的樣本,訓練某種學習機器,使它能夠對未知類別的樣本進行分類。這屬於supervised learning(監督學習)。而聚類指事先並不知道任何樣本的類別標號,希望通過某種演算法來把一組未知類別的樣本劃分成若干類別,這在機器學習中被稱作 unsupervised learning (無監督學習)。在本文中,我們關注其中一個比較簡單的聚類演算法:k-means演算法。

一、k-means演算法

       通常,人們根據樣本間的某種距離或者相似性來定義聚類,即把相似的(或距離近的)樣本聚為同一類,而把不相似的(或距離遠的)樣本歸在其他類。

       我們以一個二維的例子來說明下聚類的目的。如下圖左所示,假設我們的n個樣本點分佈在圖中所示的二維空間。從資料點的大致形狀可以看出它們大致聚為三個cluster,其中兩個緊湊一些,剩下那個鬆散一些。我們的目的是為這些資料分組,以便能區分出屬於不同的簇的資料,如果按照分組給它們標上不同的顏色,就是像下圖右邊的圖那樣:

       如果人可以看到像上圖那樣的資料分佈,就可以輕鬆進行聚類。但我們怎麼教會計算機按照我們的思維去做同樣的事情呢?這裡就介紹個集簡單和經典於一身的k-means演算法。

       k-means演算法是一種很常見的聚類演算法,它的基本思想是:通過迭代尋找k個聚類的一種劃分方案,使得用這k個聚類的均值來代表相應各類樣本時所得的總體誤差最小。

       k-means演算法的基礎是最小誤差平方和準則。其代價函式是:

       式中,μc(i)表示第i個聚類的均值。我們希望代價函式最小,直觀的來說,各類內的樣本越相似,其與該類均值間的誤差平方越小,對所有類所得到的誤差平方求和,即可驗證分為k類時,各聚類是否是最優的。

      上式的代價函式無法用解析的方法最小化,只能有迭代的方法。k-means演算法是將樣本聚類成 k個簇(cluster),其中k是使用者給定的,其求解過程非常直觀簡單,具體演算法描述如下:

1、隨機選取 k個聚類質心點

2、重複下面過程直到收斂  {

      對於每一個樣例 i,計算其應該屬於的類:

      對於每一個類 j,重新計算該類的質心:

}

      下圖展示了對n個樣本點進行K-means聚類的效果,這裡k取2。

其虛擬碼如下:

********************************************************************

建立k個點作為初始的質心點(隨機選擇)

當任意一個點的簇分配結果發生改變時

       對資料集中的每一個數據點

              對每一個質心

                     計算質心與資料點的距離

              將資料點分配到距離最近的簇

       對每一個簇,計算簇中所有點的均值,並將均值作為質心

********************************************************************

二、Python實現

      我使用的Python是2.7.5版本的。附加的庫有Numpy和Matplotlib。在程式碼中已經有了比較詳細的註釋了。不知道有沒有錯誤的地方,如果有,還望大家指正(每次的執行結果都有可能不同)。裡面我寫了個視覺化結果的函式,但只能在二維的資料上面使用。直接貼程式碼:

kmeans.py   

#################################################
# kmeans: k-means cluster
# Author : zouxy
# Date   : 2013-12-25
# HomePage : http://blog.csdn.net/zouxy09
# Email  : [email protected]
#################################################

from numpy import *
import time
import matplotlib.pyplot as plt


# calculate Euclidean distance
def euclDistance(vector1, vector2):
	return sqrt(sum(power(vector2 - vector1, 2)))

# init centroids with random samples
def initCentroids(dataSet, k):
	numSamples, dim = dataSet.shape
	centroids = zeros((k, dim))
	for i in range(k):
		index = int(random.uniform(0, numSamples))
		centroids[i, :] = dataSet[index, :]
	return centroids

# k-means cluster
def kmeans(dataSet, k):
	numSamples = dataSet.shape[0]
	# first column stores which cluster this sample belongs to,
	# second column stores the error between this sample and its centroid
	clusterAssment = mat(zeros((numSamples, 2)))
	clusterChanged = True

	## step 1: init centroids
	centroids = initCentroids(dataSet, k)

	while clusterChanged:
		clusterChanged = False
		## for each sample
		for i in xrange(numSamples):
			minDist  = 100000.0
			minIndex = 0
			## for each centroid
			## step 2: find the centroid who is closest
			for j in range(k):
				distance = euclDistance(centroids[j, :], dataSet[i, :])
				if distance < minDist:
					minDist  = distance
					minIndex = j
			
			## step 3: update its cluster
			if clusterAssment[i, 0] != minIndex:
				clusterChanged = True
				clusterAssment[i, :] = minIndex, minDist**2

		## step 4: update centroids
		for j in range(k):
			pointsInCluster = dataSet[nonzero(clusterAssment[:, 0].A == j)[0]]
			centroids[j, :] = mean(pointsInCluster, axis = 0)

	print 'Congratulations, cluster complete!'
	return centroids, clusterAssment

# show your cluster only available with 2-D data
def showCluster(dataSet, k, centroids, clusterAssment):
	numSamples, dim = dataSet.shape
	if dim != 2:
		print "Sorry! I can not draw because the dimension of your data is not 2!"
		return 1

	mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
	if k > len(mark):
		print "Sorry! Your k is too large! please contact Zouxy"
		return 1

	# draw all samples
	for i in xrange(numSamples):
		markIndex = int(clusterAssment[i, 0])
		plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])

	mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']
	# draw the centroids
	for i in range(k):
		plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)

	plt.show()

testSet.txt

1.658985	4.285136
-3.453687	3.424321
4.838138	-1.151539
-5.379713	-3.362104
0.972564	2.924086
-3.567919	1.531611
0.450614	-3.302219
-3.487105	-1.724432
2.668759	1.594842
-3.156485	3.191137
3.165506	-3.999838
-2.786837	-3.099354
4.208187	2.984927
-2.123337	2.943366
0.704199	-0.479481
-0.392370	-3.963704
2.831667	1.574018
-0.790153	3.343144
2.943496	-3.357075
-3.195883	-2.283926
2.336445	2.875106
-1.786345	2.554248
2.190101	-1.906020
-3.403367	-2.778288
1.778124	3.880832
-1.688346	2.230267
2.592976	-2.054368
-4.007257	-3.207066
2.257734	3.387564
-2.679011	0.785119
0.939512	-4.023563
-3.674424	-2.261084
2.046259	2.735279
-3.189470	1.780269
4.372646	-0.822248
-2.579316	-3.497576
1.889034	5.190400
-0.798747	2.185588
2.836520	-2.658556
-3.837877	-3.253815
2.096701	3.886007
-2.709034	2.923887
3.367037	-3.184789
-2.121479	-4.232586
2.329546	3.179764
-3.284816	3.273099
3.091414	-3.815232
-3.762093	-2.432191
3.542056	2.778832
-1.736822	4.241041
2.127073	-2.983680
-4.323818	-3.938116
3.792121	5.135768
-4.786473	3.358547
2.624081	-3.260715
-4.009299	-2.978115
2.493525	1.963710
-2.513661	2.642162
1.864375	-3.176309
-3.171184	-3.572452
2.894220	2.489128
-2.562539	2.884438
3.491078	-3.947487
-2.565729	-2.012114
3.332948	3.983102
-1.616805	3.573188
2.280615	-2.559444
-2.651229	-3.103198
2.321395	3.154987
-1.685703	2.939697
3.031012	-3.620252
-4.599622	-2.185829
4.196223	1.126677
-2.133863	3.093686
4.668892	-2.562705
-2.793241	-2.149706
2.884105	3.043438
-2.967647	2.848696
4.479332	-1.764772
-4.905566	-2.911070


test_kmeans.py

#################################################
# kmeans: k-means cluster
# Author : zouxy
# Date   : 2013-12-25
# HomePage : http://blog.csdn.net/zouxy09
# Email  : [email protected]
#################################################







from numpy import *
import time
import matplotlib.pyplot as plt
from kmeans import *

## step 1: load data
print "step 1: load data..."
dataSet = []
fileIn = open('/home/hk/Documents/dd/testSet.txt')
for line in fileIn.readlines():
	lineArr = line.strip().split('\t')
	dataSet.append([float(lineArr[0]), float(lineArr[1])])

## step 2: clustering...
print "step 2: clustering..."
dataSet = mat(dataSet)
k = 4
centroids, clusterAssment = kmeans(dataSet, k)

## step 3: show the result
print "step 3: show the result..."
showCluster(dataSet, k, centroids, clusterAssment)

注:不能直接跑通

    要把程式碼 
test_kmeans.py  增加一行  : from kmeans import *

修改後程式碼下載(無需積分喲):點選開啟連結

執行的結果是:

四、演算法分析

       k-means演算法比較簡單,但也有幾個比較大的缺點:

(1)k值的選擇是使用者指定的,不同的k得到的結果會有挺大的不同,如下圖所示,左邊是k=3的結果,這個就太稀疏了,藍色的那個簇其實是可以再劃分成兩個簇的。而右圖是k=5的結果,可以看到紅色菱形和藍色菱形這兩個簇應該是可以合併成一個簇的:

(2)對k個初始質心的選擇比較敏感,容易陷入區域性最小值。例如,我們上面的演算法執行的時候,有可能會得到不同的結果,如下面這兩種情況。K-means也是收斂了,只是收斂到了區域性最小值:

(3)存在侷限性,如下面這種非球狀的資料分佈就搞不定了:

620

(4)資料庫比較大的時候,收斂會比較慢。

       k-means老早就出現在江湖了。所以以上的這些不足也被世人的目光敏銳的捕捉到,並融入世人的智慧進行了某種程度上的改良。例如問題(1)對k的選擇可以先用一些演算法分析資料的分佈,如重心和密度等,然後選擇合適的k。而對問題(2),有人提出了另一個成為二分k均值(bisecting k-means)演算法,它對初始的k個質心的選擇就不太敏感,這個演算法我們下一個博文再分析和實現。

五、參考文獻

[3] http://blog.csdn.net/zouxy09/article/details/17589329

相關推薦

k-means演算法Python實踐

       機器學習演算法與Python實踐這個系列主要是參考《機器學習實戰》這本書。因為自己想學習Python,然後也想對一些機器學習演算法加深下了解,所以就想通過Python來實現幾個比較常用的機器學習演算法。恰好遇見這本同樣定位的書籍,所以就參考這本書的過程來學習了

機器學習演算法Python實踐之邏輯迴歸(Logistic Regression)(二)

#!/usr/bin/python # -*- coding:utf-8 -*- import numpy as np from numpy import * import matplotlib.pyplot as plt #處理資料函式 def loadDataSet():

K-means演算法python sklearn實現

目錄 前言 例項推演  K值的確定 輪廓係數 K-means演算法 前言 根據訓練樣本是否包含標籤資訊,機器學習可以分為監督學習和無監督學習。聚類演算法是典型的無監督學習,其訓練樣本中只包含樣本特徵,不包含樣本的標

k-means演算法python實現

本篇文章主要講解聚類分析中的一種常用的演算法k-means,它的全稱叫作k均值演算法。 k-means原理 k-means演算法是一種基於原型的、劃分的聚類技術。 基於原型可以理解為基於質心,也就是說,每個物件到定義該簇質心的距離比到其他簇質心的距離更近。當質心沒有意義

機器學習演算法Python實踐(9)

  ElasticNet 是一種使用L1和L2先驗作為正則化矩陣的線性迴歸模型.這種組合用於只有很少的權重非零的稀疏模型,比如:class:Lasso, 但是又能保持:class:Ridge 的正則化屬性.我們可以使用 l1_ratio 引數來調節L1和L2的凸

聚類演算法K-means演算法聚類演算法衡量指標

聚類就是按照某個特定標準(如距離準則)把一個數據集分割成不同的類或簇,使得同一個簇內的資料物件的相似性儘可能大,同時不在同一個簇中的資料物件的差異性也儘可能地大。即聚類後同一類的資料儘可能聚集到一起

周志華《機器學習》Ch9. 聚類:k-means演算法python實現

理論 k-means方法是一種常用的聚類方法,其目標是最小化 其中是第i個簇的中心。直接優化上式有難度,故k-means演算法採用一種近似方法。 簡單來說,k-means演算法由兩個步驟迴圈組成: 1. 計算每個sample到各個簇中心的距離,將該sample的類

機器學習演算法Python實踐之(七)邏輯迴歸(Logistic Regression)

Logistic regression (邏輯迴歸)是當前業界比較常用的機器學習方法,用於估計某種事物的可能性。比如某使用者購買某商品的可能性,某病人患有某種疾病的可能性,以及某廣告被使用者點選的可能性等。(注意這裡是:“可能性”,而非數學上的“概率”,logisitc迴

K-Means演算法、非負矩陣分解(NMF)影象壓縮(Python)

K-Means演算法是最基礎的聚類演算法、也是最常用的機器學習演算法之一。 本教程中,我們利用K-Means對影象中的畫素點進行聚類,然後用每個畫素所在的簇的中心點來代替每個畫素的真實值,從而達到影象壓縮的目的。 非負矩陣分解(Non-negative Matrix Fac

機器學習實踐(十七)—sklearn之無監督學習-K-means演算法

一、無監督學習概述 什麼是無監督學習 之所以稱為無監督,是因為模型學習是從無標籤的資料開始學習的。 無監督學習包含演算法 聚類 K-means(K均值聚類) 降維

K-Means演算法更多的討論想法

k-均值演算法的一個重要的侷限性即在於它的聚類模型。這一模型的中心思想是:得到相互分離的球狀聚類,在這些聚類中,均值點趨向收斂於聚類中心。 K-Means聚類得到的分類結果默認了資料關於其類別之間的差異性是隨著其歐氏距離的增大而增大的。K-Means聚類無法得到

python 實現周志華 機器學習書中 k-means 演算法

hello,all 上節採用python實現了決策樹,本節使用python實現k-means演算法,後一節將會採用map-reduce實現k-means演算法 演算法程式如下: 演算法程式碼如下: # coding=utf-8 import pprint import

scikit-learn學習之K-means聚類演算法 Mini Batch K-Means演算法

======================================================================本系列部落格主要參考 Scikit-Learn 官方網站上的每一個演算法進行,並進行部分翻譯,如有錯誤,請大家指正    轉載請註明出

k近鄰分類演算法python實踐

最近學習機器學習演算法,用python實現。 這裡記錄k近鄰演算法的python原始碼實現和一些理解。 文章參考了zouxy09的博文,程式碼參考machine learning in action. k近鄰分類演算法原理: 1、根據k近鄰,計算K個離待分類物品最近的物品

python 使用K-Means演算法對資料進行聚類

K-Means是聚類演算法的一種,以距離來判斷資料點間的相似度並對資料進行聚類。前面的文章中我們介紹過K-Means聚類演算法的原理及實現。本篇文章使用scikit-learn庫對資料進行聚類分析。準備工作開始之前先匯入要使用的各種庫檔案,首先是scikit-learn庫,然

scikit-learn學習之K-means聚類演算法 Mini Batch K-Means演算法 [轉自別的作者,還有其他sklearn翻譯]

http://blog.csdn.net/gamer_gyt/article/details/51244850 ====================================================================== 本系列部落格主要

(二)k-means演算法原理以及python實現

一、有監督學習和無監督學習 1. 有監督學習 監督學習(supervised learning):通過已有的訓練樣本(即已知資料以及其對應的輸出)來訓練,從而得到一個最優模型,再利用這個模型將所有新的資料樣本對映為相應的輸出結果,對輸出結果進行簡單的判斷從而

Pythonk-means演算法實現

# -*- coding: utf-8 -*- import math import random import matplotlib.pyplot as plt from matplotlib import colors as m_colors #生成樣本點 def g

K-means聚類演算法的三種改進(K-means++,ISODATA,Kernel K-means)介紹對比

  一、概述       在本篇文章中將對四種聚類演算法(K-means,K-means++,ISODATA和Kernel K-means)進行詳細介紹,並利用資料集來真實地反映這四種演算法之間的區別。       首先需要明確的是上述四種演算法都屬於"硬聚類”演算法,即資料集中每一個樣本都是被100%確定得

python 聚類分析實戰案例:K-means演算法(原理原始碼)

K-means演算法: 關於步驟:參考之前的部落格 關於程式碼與資料:暫時整理程式碼如下:後期會附上github地址,上傳原始資料與程式碼完整版, 各種聚類演算法的對比:參考連線 Kme