Kmeans算法精簡版(無for loop循環)

2021-01-08 CDA數據分析師

大家在學習算法的時候會學習到關於Kmeans的算法,但是網絡和很多機器學習算法書中關於Kmeans的算法理論核心一樣,但是代碼實現過於複雜,效率不高,不方便閱讀。這篇文章首先列舉出Kmeans核心的算法過程,並且會給出如何最大限度的在不用for循環的前提下,利用numpy, pandas的高效的功能來完成Kmeans算法。這裡會用到列表解析,它是相當於速度更快的for循環,標題裡指出的無for loop指的是除了列表解析解析以外不用for循環,來完成Kmeans算法。

一般在python數據清洗中,數據量大的情況下,for循環的方法會使的數據處理的過程特別慢,效率特別低。一個很好的解決方法就是使用numpy,pandas自帶的高級功能,不僅可以使得代碼效率大大提高,還可以使得代碼方便理解閱讀。這裡在介紹用numpy,pandas來進行Kmeans算法的同時,也是帶大家複習一遍numpy,pandas用法。

1 Kmeans的算法原理

創建k個點作為初始質心(通常是隨機選擇)

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

對數據集中的每個點:

對每個質:

計算質與數據點之間的距離

將數據點分配到據其最近的簇

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

直到簇不再發變化或者達到最大迭代次數

2 聚類損失函數

SSE=i=1∑kx∈Ci∑(cix)2

Ci指的是第i個簇,x是i個簇中的點,ci是第i個簇的質心

import numpy as npimport pandas as pdimport matplotlib as mplimport matplotlib.pyplot as pltfrom sklearn.datasets import make_blobsimport seaborn as sns

#r = np.random.randint(1,100)r =4#print(r)k =3x , y = make_blobs(n_samples =51, cluster_std =[0.3,0.3,0.3], centers =[[0,0],[1,1],[-1,1]],random_state = r )sim_data = pd.DataFrame(x, columns =['x','y'])sim_data['label']= ysim_data.head(5)data = sim_data.copy()plt.scatter(sim_data['x'], sim_data['y'], c = y)

上圖是一個隨機生成的2維的數據,可以用來嘗試完成Kmeans的代碼。

實際過程中,Kmeans需要能運行在多維的數據上,所以下面的代碼部分,會考慮多維的數據集,而不是僅僅2維的數據。

3 隨機生成數據點

這裡的嚴格意義上不是隨機的生成k個質心點,而是取出每個特徵的最大值最小值,在最大值和最小值中取出一個隨機數作為質心點的一個維度

definitial_centers(datasets, k =3):#首先將datasets的特徵名取出來,這裡需要除去label那一列 cols = datasets.columns data_content = datasets.loc[:, cols !='label']#直接用describe的方法將每一列的最小值最大值取出來 range_info = data_content.describe().loc[['min','max']]#用列表解析的方法和np.random.uniform的方法生成k個隨機的質心點#np.random.uniform(a, b, c) 隨機生成在[a,b)區間裡的3個數#對每個特徵都做此操作 k_randoms =[np.random.uniform(range_info[i]['min'], range_info[i]['max'], k)for i in range_info.columns] centers = pd.DataFrame(k_randoms, index = range_info.columns)return centers.T

centers = initial_centers(data, k =3)centers

4 計算所有的點到所有中心點的距離

將每一個中心點取出來,然後使用pandas的廣播的功能,可以直接將所有的實例和其中一個質心點相減。如下圖,下圖中是給出相加的例子,而我們的例子是減法。

所以對於一個DataFrame來說,比如說這裡的只包含x和y的data,假設我們的質心是c = [1,1],可以用以下的方式來給出所有的實例點的x和y和點(1,1)之間的差值。注意,這裡的c可以是list,也可以是numpy array,甚至可以是元組。

$$

$$

算出每個實例的每個特徵和質心點的差距之後,則需要將所有的數平方一下,然後按每一行加起來則給出了每一個實例點到質心的距離了

$$

$$

用的方法就是使用np.power(data - c, 2).sum(axis = 1)

defcal_distant(dataset, centers):#選出不是label的那些特徵列 data = dataset.loc[:, dataset.columns !='label']#使用列表解析式的格式,對centers表裡的每一行也就是每一個隨機的質心點,都算一遍所有的點到該質心點的距離,並且存入一個list中 d_to_centers =[np.power(data - centers.loc[i],2).sum(axis =1)for i in centers.index]#所有的實例點到質心點的距離都已經存在了list中,則可以直接帶入pd.concat裡面將數據拼起來return pd.concat(d_to_centers, axis =1)

d_to_centers = cal_distant(data, centers)d_to_centers.head(5)

5 找出最近的質心點

當每個實例點都和中心點計算好距離後,對於每個實例點找出最近的那個中心點,可以用np.where的方法,但是pandas已經提供更加方便的方法,用idxmin和idxmax,這2個函數可以直接給出DataFrame每行或者每列的最小值和最大值的索引,設置axis = 1則是想找出對每個實例點來說,哪個質心點離得最近。

curr_group = d_to_centers.idxmin(axis=1)

這個時候,每個點都有了新的group,這裡我們則需要開始更新我們的3個中心點了。對每一個臨時的簇來說,算出X的平均, 和Y的平均,就是這個臨時的簇的中心點。

6 重新計算新的質心點

centers = data.loc[:, data.columns !='label'].groupby(curr_group).mean()centers

7 迭代

這樣我們新的質心點就得到了,只是這個時候的算法還是沒有收斂的,需要將上面的步驟重複多次。

Kmeans代碼迭代部分就完成了,將上面的步驟做成一個函數,做成函數後,方便展示Kmeans的中間過程。

defiterate(dataset, centers):#計算所有的實例點到所有的質心點之間的距離 d_to_centers = cal_distant(dataset, centers)#得出每個實例點新的類別 curr_group = d_to_centers.idxmin(axis=1)#算出當前新的類別下每個簇的組內誤差 SSE = d_to_centers.min(axis =1).sum()#給出在新的實例點類別下,新的質心點的位置 centers = dataset.loc[:, dataset.columns !='label'].groupby(curr_group).mean()return curr_group, SSE, centers

curr_group, SSE, centers = iterate(data,centers)

centers, SSE

( x y 0 0.892579 0.931085 1 -1.003680 1.044955 2 0.008740 -0.130172, 19.041432436034352)

最後需要判斷什麼時候迭代停止,可以判斷SSE差值不變的時候,算法停止

#創建一個空的SSE_list,用來存SSE的,第一個位置的數為0,無意義,只是方便收斂時最後一個SSE和上一個SSE的對比SSE_list =[0]#初始化質心點centers = initial_centers(data, k =3)#開始迭代whileTrue:#每次迭代中得出新的組,組內誤差,和新的質心點,當前的新的質心點會被用於下一次迭代 curr_group, SSE, centers = iterate(data,centers)#檢查這一次算出的SSE和上一次迭代的SSE是否相同,如果相同,則收斂結束if SSE_list[-1]== SSE:break#如果不相同,則記錄SSE,進入下一次迭代 SSE_list.append(SSE)

SSE_list

[0, 37.86874675507244, 11.231524142566894, 8.419267088238051]

8 代碼整合

算法完成了,將所有的代碼整合在一起

definitial_centers(datasets, k =3): cols = datasets.columns data_content = datasets.loc[:, cols !='label'] range_info = data_content.describe().loc[['min','max']] k_randoms =[np.random.uniform(range_info[i]['min'], range_info[i]['max'], k)for i in range_info.columns] centers = pd.DataFrame(k_randoms, index = range_info.columns)return centers.Tdefcal_distant(dataset, centers): data = dataset.loc[:, dataset.columns !='label'] d_to_centers =[np.power(data - centers.loc[i],2).sum(axis =1)for i in centers.index]return pd.concat(d_to_centers, axis =1)defiterate(dataset, centers): d_to_centers = cal_distant(dataset, centers) curr_group = d_to_centers.idxmin(axis=1) SSE = d_to_centers.min(axis =1).sum() centers = dataset.loc[:, dataset.columns !='label'].groupby(curr_group).mean()return curr_group, SSE, centersdefKmeans_regular(data, k =3): SSE_list =[0] centers = initial_centers(data, k = k)whileTrue: curr_group, SSE, centers = iterate(data,centers)if SSE_list[-1]== SSE:break SSE_list.append(SSE)return curr_group, SSE_list, centers

上面的函數已經完成,當然這裡推薦大家儘量寫成class的形式更好,這裡為了方便觀看,則用簡單的函數完成。

最後的函數是Kmeans_regular函數,這個函數裡面包含了上面所有的函數。現在需要測試Kmeans_regular代碼對於多特徵的數據集鳶尾花數據集,是否也能進行Kmeans聚類算法

from sklearn.datasets import load_irisdata_dict = load_iris()iris = pd.DataFrame(data_dict.data, columns = data_dict.feature_names)iris['label']= data_dict.target

curr_group, SSE_list, centers = Kmeans_regular(iris.copy(), k =3)

np.array(SSE_list)

array([ 0. , 589.73485975, 115.8301874 , 83.29216169, 79.45325846, 78.91005674, 78.85144143])

pd.crosstab(iris['label'], curr_group)

np.diag(pd.crosstab(iris['label'], curr_group)).sum()/ iris.shape[0]

0.8933333333333333

最後可以看出我們的代碼是可以適用於多特徵變量的數據集,並且對於鳶尾花數據集來說,對角線上的數是預測正確的個數,準確率大約為90%。

9 Kmeans中間過程以及可視化展現

在完成代碼後,還是需要討論一下,為什麼我們的代碼的算法是那樣的,這個算法雖然看起來很有邏輯,但是它到底是從哪裡來的。

這個時候,我們就需要從Kmeans的損失函數出發來解釋剛才提出的問題。對於無監督學習算法來說,也是有一個損失函數。而我們的Kmeans的中間過程的邏輯,就是從最小化Kmeans的損失函數的過程。

假設我們有一個數據集x1,x2,...,xN, 每個樣本實例點x有多個特徵。我們的目標是將這個數據集通過某種方式切分成K份,或者說我們最後想將每個樣本點標上一個類別(簇),且總共有K個類別,使得每個樣本點到各自的簇中心點的距離最小,並且uk來表示各個簇的中心點。

我們還需要一些其他的符號,比如說rnk, 它的值是0或者1。下標k代表的是第k個簇,下標n表示的是第n個樣本點。

舉例說明,加入當前K=3,k的可取1,2,3。對於第一個實例點n = 1來說它屬於第3個簇,所以

rn=1,k=1=0

rn=1,k=2=0

rn=1,k=3=1

這個也可以把想像成獨熱編碼。

將上面的符號解釋完了後,以下就是損失函數。這裡是使用了求和嵌套了求和的公式,並且也引入了剛才所提到了rnk。這個損失函數其實很好理解,在給定的k個中心點uk以及分配好了各個實例點屬於哪一個簇之後,計算各個實例點到各自的簇中心點的距離,距離平方以下並且相加起來,就是損失函數。這個公式其實也就是在算簇內誤差和。

C=n=1∑Nk=1∑Krnk(xnuk)2

那怎麼來最小化這個損失函數呢,用的就是EM算法,這個算法總體來說分2個步驟,Expectation和Maximization,對Kmeans來說M應該說是Minimization

Expection:

保持uk不變,也就是各個簇的中心點的位置不變,計算各個實例點到哪個uk最近,將各個實例點劃分到離各自最近的那個簇裡面去,從而使得整體SSE降低。

Minimization:

保持當前實例點的簇的類別不變,為了整體降低損失函數,可以對每個簇內的損失函數公式做微分。由於當前我們的各個點的類別是不變的,變的是uk,所以做的微分是基於uk的

dukdk=1∑Krnk(xnuk)2=0

2k=1∑Krnk(xnuk)=0

uk=∑nrnk∑nrnkxn

得出來的uk其實就是在算各個簇內的新的中心點,也就是對各個簇內所有的實例點的各個特徵做平均數。

這時候得到新的中心點uk, 緊接著再到E階段,保持uk更新簇類別,再到M階段,保持簇類別不變更新uk,不斷的迭代知道SSE不變位置。這個就是Kmeans的算法過程。下面將用plotly可視化,動態展示Kmeans的過程。

使用之前寫好的函數,然後將數據的中間過程通過plotly展示出來。因為代碼比較長,所以這裡就不展示代碼了。由於當前是一個markdown,這裡放入一個gif圖片用來展示最後的Kmeans中間過程。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zaiSFuGB-1589536000909)(…/…/…/…/…/…/0 AI-work/B 部門/SEO/202001/rowdata/倪向陽_SEO_2020_01/Kmeans_Plotly中間過程/Kmeans_1.gif)]

對於這個數據集來看的話,我們的Kmeans算法可以使得每一個點最終可以找到各自的簇,但是這個算法也是有缺陷的,比如以下例子。

假如說現在有4個簇的話,Kmeans算法不一定能使最後的SSE最小。對於2列的數據集來說,我們取2組隨機的質心點來做對比。

第一組為設置seed為5的時候,以下為演示的結果。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-t7uRDf5U-1589536000912)(…/…/…/…/…/…/0 AI-work/B 部門/SEO/202001/rowdata/倪向陽_SEO_2020_01/Kmeans_Plotly中間過程/Kmeans_2.gif)]

從上面的動圖可以看出一共用了8次迭代,才收斂。那加入我們的seed為1的話,隨機的質心點的分布會變的很離譜,會導致下面的結果。這裡我們加快動畫的速度。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mEk3AXPf-1589536000913)(…/…/…/…/…/…/0 AI-work/B 部門/SEO/202001/rowdata/倪向陽_SEO_2020_01/Kmeans_Plotly中間過程/Kmeans_3.gif)]

這裡用34次,數據才迭代收斂,並且可以看出,在迭代的過程中,差點陷入了一個局部最小的一個情況。所以對於複雜的數據來說的話,我們最後看到迭代的次數會明顯的增加。

假如說我們的數據集再變的集中一點,其中的2個簇,稍微近一點,我們會看到以下的結果。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ztYH1wDQ-1589536000914)(…/…/…/…/…/…/0 AI-work/B 部門/SEO/202001/rowdata/倪向陽_SEO_2020_01/Kmeans_Plotly中間過程/Kmeans_4.gif)]

所以在這次迭代的過程中,我們明顯看到其中有個質心點消失了,原因就是因為由於點的分布的原因和初始質心點的原因,最開始隨機生成的一個離所有的點都最遠的質心點,由於它離所有的點都最遠,所以導致了在迭代的過程中,沒有任何一個點屬於這個質心點,最後導致這個點消失了。所以這個就是Kmeans算法的缺陷,那怎麼來優化這個算法了,我們可以利用BiKmeans算法。

相關焦點

  • 機器學習之基於sklearn的KMeans聚類
    聚類算法,無監督學習的代表算法,又叫做「無監督分類」即在訓練的時候只需要特徵矩陣,不需要真實值標籤可以有效地幫助我們探索數據的自然分布一、KMeans算法的運行過程運行的流程如下:自動聚類時的質心點的每步驟變化如下:
  • 您知道in the loop是什麼意思嗎?
    今天,我們一起看一下loop這個單詞。單詞loop很簡單,和它相似的單詞有loom和loon等。今天,我們就一起看一下loop的用法。首先,我們看一下loop做名詞的用法。1、The road went in a huge loop around the lake.那條路環湖繞了一個大圈。這句話中loop的意思是環形、環狀物、圓圈。2、He tied a loop of rope around his arm.他在手臂上用繩子系了一個圈。這句話中loop的意思是環、圈,通常指繩、電線等形成的環。打個圈可以表達為make a loop。
  • Unroll & Pipeline | 細粒度並行優化的完美循環
    正確地使用好這兩個指令能夠增強算法地並行性,提升吞吐量,降低延遲但是需要遵循一定的代碼風格。展開 (unroll) 指令是只針對 for 循環的展開指令,和流水線指令關係密切,所以我們放在一起首先我們來看一下這三個指令在 Xilinx 官方指南中的定義:  Unroll: Unroll for-loops to create multiple instances of the loop body and
  • #回購#生活工作好幫手——日淘的那些愛樂普(eneloop)鎳氫充電電池
    我會第一時間想起——愛樂普(eneloop)鎳氫充電電池。「愛樂普」是松下生產的環保電池「eneloop」鎳氫充電電池的中文名稱。Eneloop就是「能量環」的意思。因三洋電機已經被松下收購,自2013年4月26日起,日本本地的eneloop全部停止使用三洋品牌銷售,改用松下品牌。同時,第三代Eneloop電池已經停止生產,全面更新為新一代產品(第四代)。
  • ZBrush精簡版ZBrushCore震撼來襲
    北京時間2016年9月30日,Pixologic公司召開新聞發布會,宣布ZBrush精簡版ZBrushCore正式發布。該版本不僅支持中文,還支持多國語言,簡單點來說,ZBrushCore是ZBrush 4R7的「簡化版」            北京時間2016年9月30日,Pixologic公司召開新聞發布會,宣布ZBrush精簡版ZBrushCore正式發布。該版本不僅支持中文,還支持多國語言,包括法語、西班牙語等。
  • 谷歌精簡版搜索應用擴展至全球:7MB+適用入門機型
    網易科技訊 8月21日消息,據外媒報導,在印度和印尼推出一年半之後,谷歌精簡版搜索應用其他類似應用還包括精簡版電子郵件應用Gmail Go、精簡版圖片應用Gallery Go,甚至精簡版行動作業系統Android Go。
  • python之kmeans數據聚類算法
    一 Kmeans原理kmeans是屬於無監督學習的數據聚類算法,根據點與點之間的距離推測每個點屬於哪個中心,常用計算距離的方式有:餘弦距離、歐式距離、曼哈頓距離等,本文以歐式距離為例。圖1假設每個點的維度是n,即每個點有n個特徵維度,計算這些點數據到數據中心A、B、C的距離,從而將每個數據歸類到A或B或C。
  • 打怪、升級、然後重新來過:陷入無限loop的字節跳動
    在奇幻小說《怪屋女孩》裡,提到了一個叫「loop」的概念。具體情節是主角們陷入了一個時間循環怪圈,時間停留在了一個悲劇發生的日子,每一次醒來都是同樣的日期,要經歷同樣的痛苦但是無能為力。loop一次的中文翻譯是循環,但其實在英文中,loop更有一種「反覆清空歸零重新來過」的含義。從商業模式上講,小型手遊公司的運營模式最接近loop:不斷推出新遊戲,賺個首充之後又不斷被用戶遺忘。
  • CES 2020:售價4000美元的Hydraloop水循環裝置
    來源:天極網隨著人們對於水資源短缺的擔憂日益加劇,現在,大多數人在用水時都會很注意,但是,很多時候水還是不經意間的被浪費了,這時候,來自於荷蘭的Hydraloop公司,就發布了一款住宅水回收裝置,可以有效的節約水資源。而且這個裝置還贏得了CES 2020年度最佳創新獎。
  • Out of the loop?
    are a few articles that might help those who are out of the loop.If you’re out of the loop, that is, you don’t know what’s going on.The loop refers to, I think, the social circle or circles we belong or don’t belong.
  • 旗艦機精簡版 三星GALAXY S4 mini評測
    旗艦機精簡版 三星GALAXY S4 mini評測  三星GALAXY S4 mini在如今可以算作是很少見的小屏幕手機,當然,我們對於大小的概念也是一直在不斷變化著的但從另外一個角度來看,一款旗艦機型的精簡版,在界面、功能上與旗艦機型相差不大,保留了大部分功能,也算是三星GALAXY S4 mini的一大亮點。
  • 機器學習之分類算法K-Means介紹與代碼分析(篇四)
    這個問題在計算上是NP困難的,不過存在高效的啟發式算法。一般情況下,都使用效率比較高的啟發式算法,它們能夠快速收斂於一個局部最優解。這些算法通常類似於通過迭代優化方法處理高斯混合分布的最大期望算法(EM算法)。而且,它們都使用聚類中心來為數據建模;然而k-平均聚類傾向於在可比較的空間範圍內尋找聚類,期望-最大化技術卻允許聚類有不同的形狀。
  • 喜馬拉雅無廣告版
    中國最大聲音庫,但是使用過程中,想必大家也都見識喜馬拉雅的貼片廣告了吧,稍有不慎就會誤觸到廣告,今天SODA給大家分享的純淨版喜馬拉雅,完全去除了廣告。清爽無比!!!聽書、聽課、聽段子,6億用戶的選擇!郭德綱、馬東、吳曉波,盡在耳邊!通勤、堵車、失眠,好無聊?快來聽點有料的!排隊、等人、做家務,碎片時間變黃金;晨跑很單調?
  • 谷歌推出購物應用Shoploop,聽起來像是直播帶貨淨化版
    因此,谷歌帶來了其全新的購物平臺Shoploop。這是一個Google實驗室Area 120打造的產品。根據他們的說法是,創始人在乘坐地鐵時看到一個婦女為了購買一件彩妝商品不斷地從社交媒體切換到YouTube又切換到在線商店,於是想著是否能夠省去中間步驟,將社交媒體融合進線上商城,用戶在使用社交媒體時,如果有喜歡的同款便能直接下單。
  • |四個OFFICE精簡版總有一款適合你
    同時,大家平時使用最多的主要是Word、Excel、PowerPoint為主,所以為了輕裝上陣,本次推薦的除了2013版多一個ACCESS資料庫功能外,其他都是只包含Word、Excel、PPT的三合一(2013是四合一)精簡版本。
  • 風箏衝浪初學篇——loop
    ,也可以風箏在1點向下做一個dwonloop水起。backloop。志豪說    第一:loop的關鍵點在于堅定的完成整個loop,千萬不能風箏正在loop的過程中,特別是氣囊邊朝下的時候,必須是在風箏完成了loop
  • loop 遊戲解析
    本篇為對上一篇推送:微型劇本loop展示 中遊戲的分析,建議先讀上一篇。
  • 終於明白了:蘋果海報原來這麼有內涵-蘋果,發布會,海報,內涵,Loop...
    此前蘋果為這場發布會定下的主題是「Let us loop you in」,中文的意思是「讓我們和你進入循環」。看起來有點摸不著頭腦,發布會結束之後,就讓我們再來看看蘋果究竟想給我們傳達哪些深意?蘋果春季發布會的主題Let us loop you in先給大家解釋下英文單詞Loop是什麼意思。在英文中,Loop就是循環,成環的意思。
  • 基於KNN和Kmeans算法利用MNIST數據集實現手寫數字識別
    作者: 陳千鶴 來源:人工智慧學習圈 KNN算法發展狀況K-最近鄰法(K-Nearest Neighbor, KNN)最初由Cover和Hart於1968年提出,是一個在理論上比較成熟的分類算法。這是一種基於模板匹配思想的算法,雖然簡單,但很有效,至今仍在被使用。
  • 秘密行動《Loop循環》:有限的循環無限的驚喜
    秘密行動《Loop循環》  今年似乎是成都樂隊的風水寶年。但和許多這個時代的樂隊一樣,風格化的標籤,同樣不適合「秘密行動」和他們的這張《Loop循環》專輯。因為他們的音樂,沒那麼簡單。  或者是因為樂隊成員出身川音的背景,使得《Loop循環》這張專輯,不像大多數樂隊的優秀處子碟那樣,處處透著生猛海鮮的味道,只放不收,任由自己的靈感汪洋恣意,卻沒有克制和節制的收斂。「秘密行動」的音樂似乎從一開始就在靈與妙之間,進行著儘可能完美的平衡。