成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

手擼Golang 基本數據結構與算法 k-means聚類算法

開發 前端 算法
最近閱讀<<我的第一本算法書>>(【日】石田保輝;宮崎修一)本系列筆記擬采用golang練習之k-means聚類算法。

緣起

最近閱讀<<我的第一本算法書>>(【日】石田保輝;宮崎修一)

本系列筆記擬采用golang練習之

k-means聚類算法

聚類就是在輸入為多個數據時, 將“相似”的數據分為一組的操作。 k-means算法是聚類算法中的一種。 首先隨機選擇k個點作為簇的中心點, 然后重復執行“將數據分到相應的簇中”和 “將中心點移到重心的位置”這兩個操作, 直到中心點不再發生變化為止。 k-means算法中,隨著操作的不斷重復, 中心點的位置必定會在某處收斂, 這一點已經在數學層面上得到證明。 摘自 <<我的第一本算法書>> 【日】石田保輝;宮崎修一

場景

  • 某地突然爆發新冠疫情, 現防疫急需根據病例分布, 查找可能的病源地
  • 首先將病例分布的坐標, 錄入系統
  • 然后根據k-means算法, 按k從1到3, 分別進行聚類
  • 聚類的中心點, 可能就是病源地

流程

  1. 給定若干樣本, 和樣本距離計算器, 需要求解k個樣本中心點
  2. 首先從樣本中隨機抽取k個點, 作為中心點
  3. 循環每個樣本

    1. 分別計算樣本點到k個中心點的距離
    2. 判斷距離樣本點最小的中心點
    3. 將樣本劃分到該最小中心點的簇
  4. 計算每個簇的中心點, 作為新的中心點

    1. 循環簇中的每個樣本
    2. 計算該樣本, 到本簇其他樣本的距離之和
    3. 與其他樣本的距離和最小的點, 就是新的中心點
  5. 重復3-4, 直到中心點不再變化, 計算完畢

設計

  • IPoint: 樣本點接口, 其實是一個空接口
  • IDistanceCalculator: 距離計算器接口
  • IClassifier: 分類器接口, 將samples聚類成k個, 并返回k個中心點
  • tPerson: 病例樣本點, 實現IPoint接口, 含x,y坐標
  • tPersonDistanceCalculator: 病例距離計算器, 計算兩點間x,y坐標的直線距離
  • tKMeansClassifier: k-means聚類器, 實現IClassifier接口.

單元測試

k_means_test.go

  1. package others 
  2.  
  3. import ( 
  4.     km "learning/gooop/others/k_means" 
  5.     "strings" 
  6.     "testing" 
  7.  
  8. func Test_KMeans(t *testing.T) { 
  9.     // 創建樣本點 
  10.     samples := []km.IPoint { 
  11.         km.NewPerson(211), 
  12.         km.NewPerson(28), 
  13.         km.NewPerson(26), 
  14.  
  15.         km.NewPerson(312), 
  16.         km.NewPerson(310), 
  17.  
  18.         km.NewPerson(47), 
  19.         km.NewPerson(43), 
  20.  
  21.         km.NewPerson(511), 
  22.         km.NewPerson(59), 
  23.         km.NewPerson(52), 
  24.  
  25.         km.NewPerson(79), 
  26.         km.NewPerson(76), 
  27.         km.NewPerson(73), 
  28.  
  29.         km.NewPerson(812), 
  30.  
  31.         km.NewPerson(93), 
  32.         km.NewPerson(95), 
  33.         km.NewPerson(910), 
  34.  
  35.         km.NewPerson(103), 
  36.         km.NewPerson(106), 
  37.         km.NewPerson(1012), 
  38.  
  39.         km.NewPerson(119), 
  40.     } 
  41.  
  42.     fnPoints2String := func(points []km.IPoint) string { 
  43.         items := make([]string, len(points)) 
  44.         for i,it := range points { 
  45.             items[i] = it.String() 
  46.         } 
  47.         return strings.Join(items, " "
  48.     } 
  49.  
  50.     for k:=1;k<=3;k++ { 
  51.         centers := km.KMeansClassifier.Classify(samples, km.PersonDistanceCalculator, k) 
  52.         t.Log(fnPoints2String(centers)) 
  53.     } 

測試輸出

  1. $ go test -v k_means_test.go  
  2. === RUN   Test_KMeans 
  3.     k_means_test.go:53: p(7,6
  4.     k_means_test.go:53: p(5,9) p(7,3
  5.     k_means_test.go:53: p(9,10) p(3,10) p(7,3
  6. --- PASS: Test_KMeans (0.00s) 
  7. PASS 
  8. ok      command-line-arguments  0.002s 

IPoint.go

樣本點接口, 其實是一個空接口

  1. package km 
  2.  
  3. import "fmt" 
  4.  
  5. type IPoint interface { 
  6.     fmt.Stringer 

IDistanceCalculator.go

距離計算器接口

  1. package km 
  2.  
  3. type IDistanceCalculator interface { 
  4.     Calc(a, b IPoint) int 

IClassifier.go

分類器接口, 將samples聚類成k個, 并返回k個中心點

  1. package km 
  2.  
  3. type IClassifier interface { 
  4.     // 將samples聚類成k個, 并返回k個中心點 
  5.     Classify(samples []IPoint, calc IDistanceCalculator, k int) []IPoint 

tPerson.go

病例樣本點, 實現IPoint接口, 含x,y坐標

  1. package km 
  2.  
  3. import "fmt" 
  4.  
  5. type tPerson struct { 
  6.     x int 
  7.     y int 
  8.  
  9. func NewPerson(x, y int) IPoint { 
  10.     return &tPerson{x, y, } 
  11.  
  12. func (me *tPerson) String() string { 
  13.     return fmt.Sprintf("p(%v,%v)", me.x, me.y) 

tPersonDistanceCalculator.go

病例距離計算器, 計算兩點間x,y坐標的直線距離

  1. package km 
  2.  
  3.  
  4. type tPersonDistanceCalculator struct { 
  5.  
  6. var gMaxInt = 0x7fffffff_ffffffff 
  7.  
  8. func newPersonDistanceCalculator() IDistanceCalculator { 
  9.     return &tPersonDistanceCalculator{} 
  10.  
  11. func (me *tPersonDistanceCalculator) Calc(a, b IPoint) int { 
  12.     if a == b { 
  13.         return 0 
  14.     } 
  15.  
  16.     p1, ok := a.(*tPerson) 
  17.     if !ok { 
  18.         return gMaxInt 
  19.     } 
  20.  
  21.     p2, ok := b.(*tPerson) 
  22.     if !ok { 
  23.         return gMaxInt 
  24.     } 
  25.  
  26.     dx := p1.x - p2.x 
  27.     dy := p1.y - p2.y 
  28.  
  29.     d := dx*dx + dy*dy 
  30.     if d < 0 { 
  31.         panic(d) 
  32.     } 
  33.     return d 
  34.  
  35. var PersonDistanceCalculator = newPersonDistanceCalculator() 

tKMeansClassifier.go

k-means聚類器, 實現IClassifier接口.

  1. package km 
  2.  
  3. import ( 
  4.     "math/rand" 
  5.     "time" 
  6.  
  7. type tKMeansClassifier struct { 
  8.  
  9. type tPointEntry struct { 
  10.     point IPoint 
  11.     distance int 
  12.     index int 
  13.  
  14. func newPointEntry(p IPoint, d int, i int) *tPointEntry { 
  15.     return &tPointEntry{ 
  16.         p, d, i, 
  17.     } 
  18.  
  19. func newKMeansClassifier() IClassifier { 
  20.     return &tKMeansClassifier{} 
  21.  
  22. // 將samples聚類成k個, 并返回k個中心點 
  23. func (me *tKMeansClassifier) Classify(samples []IPoint, calc IDistanceCalculator, k int) []IPoint { 
  24.     sampleCount := len(samples) 
  25.     if sampleCount <= k { 
  26.         return samples 
  27.     } 
  28.  
  29.     // 初始化, 隨機選擇k個中心點 
  30.     rnd := rand.New(rand.NewSource(time.Now().UnixNano())) 
  31.     centers := make([]IPoint, k) 
  32.     for selected, i:= make(map[int]bool, 0), 0;i < k; { 
  33.         n := rnd.Intn(sampleCount) 
  34.         _,ok := selected[n] 
  35.  
  36.         if !ok { 
  37.             selected[n] = true 
  38.             centers[i] = samples[n] 
  39.             i++ 
  40.         } 
  41.     } 
  42.  
  43.  
  44.     // 根據到中心點的距離, 劃分samples 
  45.     for { 
  46.         groups := me.split(samples, centers, calc) 
  47.  
  48.         newCenters := make([]IPoint, k) 
  49.         for i,g := range groups { 
  50.             newCenters[i] = me.centerOf(g, calc) 
  51.         } 
  52.  
  53.         if me.groupEquals(centers, newCenters) { 
  54.             return centers 
  55.         } 
  56.         centers = newCenters 
  57.     } 
  58.  
  59. // 將樣本點距離中心點的距離進行分簇 
  60. func (me *tKMeansClassifier) split(samples []IPoint, centers []IPoint, calc IDistanceCalculator) [][]IPoint { 
  61.     k := len(centers) 
  62.     result := make([][]IPoint, k) 
  63.     for i := 0;i<k;i++ { 
  64.         result[i] = make([]IPoint, 0
  65.     } 
  66.  
  67.     entries := make([]*tPointEntry, k) 
  68.     for i,c := range centers { 
  69.         entries[i] = newPointEntry(c, 0, i) 
  70.     } 
  71.  
  72.     for _,p := range samples { 
  73.         for _,e := range entries { 
  74.             e.distance = calc.Calc(p, e.point) 
  75.         } 
  76.  
  77.         center := me.min(entries) 
  78.         result[center.index] = append(result[center.index], p) 
  79.     } 
  80.  
  81.     return result 
  82.  
  83. // 計算一簇樣本的重心. 重心就是距離各點的總和最小的點 
  84. func (me *tKMeansClassifier) centerOf(samples []IPoint, calc IDistanceCalculator) IPoint { 
  85.     entries := make([]*tPointEntry, len(samples)) 
  86.     for i,src := range samples { 
  87.         distance := 0 
  88.         for _,it := range samples { 
  89.             distance += calc.Calc(src, it) 
  90.         } 
  91.         entries[i] = newPointEntry(src, distance, i) 
  92.     } 
  93.  
  94.     return me.min(entries).point 
  95.  
  96. // 判斷兩組點是否相同 
  97. func (me *tKMeansClassifier) groupEquals(g1, g2 []IPoint) bool { 
  98.     if len(g1) != len(g2) { 
  99.         return false 
  100.     } 
  101.  
  102.     for i,v := range g1 { 
  103.         if g2[i] != v { 
  104.             return false 
  105.         } 
  106.     } 
  107.  
  108.     return true 
  109.  
  110. // 查找距離最小的點 
  111. func (me *tKMeansClassifier) min(entries []*tPointEntry) *tPointEntry { 
  112.     minI := 0 
  113.     minD := gMaxInt 
  114.     for i,it := range entries { 
  115.         if it.distance < minD { 
  116.             minI = i 
  117.             minD = it.distance 
  118.         } 
  119.     } 
  120.  
  121.     return entries[minI] 
  122.  
  123.  
  124. var KMeansClassifier = newKMeansClassifier() 

 

 

 

責任編輯:張燕妮 來源: Go語言中文網
相關推薦

2012-08-09 09:57:54

K-means

2025-05-22 10:06:49

2024-04-18 15:44:20

2020-12-31 05:31:01

數據結構算法

2023-03-08 08:03:09

數據結構算法歸并排序

2017-09-12 16:57:43

機器學習K-means算法Python

2020-10-21 14:57:04

數據結構算法圖形

2023-10-27 07:04:20

2023-04-27 09:13:20

排序算法數據結構

2023-03-10 08:07:39

數據結構算法計數排序

2023-03-02 08:15:13

2021-05-12 09:07:09

Java數據結構算法

2023-03-07 08:02:07

數據結構算法數列

2018-04-25 08:10:50

算法k-means代碼

2023-03-13 10:08:31

數據結構算法

2023-11-06 06:43:23

單鏈表查詢數據結構

2017-08-31 09:45:43

JavaArrayList數據

2023-09-15 10:33:41

算法數據結構

2020-10-12 11:48:31

算法與數據結構

2019-03-29 09:40:38

數據結構算法前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品视频久久久 | 日本a级大片 | 91免费电影 | 久久精品国产一区二区电影 | 九九热在线免费观看 | 久在线 | 国产成人99久久亚洲综合精品 | 亚欧性视频 | 久草.com | 中文字幕在线不卡播放 | 国产91视频一区二区 | 中文字幕第二区 | 超碰人人在线 | 欧美午夜精品 | 成人国产精品久久 | 中文字幕免费观看 | 国产精品一区久久久 | 欧美精品一区二区三区四区五区 | 午夜精品福利视频 | 欧美日韩一区精品 | 在线免费观看视频黄 | 精品成人一区二区 | 天天爽综合网 | 一区二区三区四区在线 | 午夜激情免费 | 久久精品免费一区二区三 | 激情六月丁香婷婷 | 欧美一级免费看 | 高清18麻豆| 欧美理论在线观看 | 亚洲成人中文字幕 | 久久国产精品网 | 中文字幕日韩一区二区 | 午夜影院操 | 欧美日韩国产中文字幕 | 成人免费在线视频 | 成人国产精品久久 | 日韩欧美国产一区二区 | 精品国产黄色片 | 日韩三级在线观看 | 精品国产黄色片 |