KNN算法的ruby實現

原文鏈接:nicholasren.github.com/2013/02/17/knn.html

背景

KNN,全稱K-nearest-neighbour,是機器學習中最簡單的一個分類算法,它的原理是通過對樣本數據的學習,對於給定的新的數據,找出與其距離最近的K個樣本數據,根據這K個最近樣本數據的類別,來確定這個給定數據的類別。

Coolshell上有對這個算法的講解,我的同事邱俊濤也寫了一篇關於KNN算法python實現的文章。本文講解一個KNN算法的ruby實現。

輸入

程序輸入格式如下:

x0,x1,x2,…xn|v0
y0,y1,y2,…yn|v1
z0,z1,z2,…zn|v2

每行爲一個數據樣本,以第一行爲例,x0,x1...xn爲一個向量,v0爲該數據的類別。

學習

從給定文件加載樣本數據:

def train file_path
  @samples = from_file(file_path)
end

@sample的格式如下:

[
    {:vector => [x0, x1, x2, …xn], :value => v0},
    {:vector => [y0, y1, y2, …yn], :value => v1},
    …
    {:vector => [z0, z1, z2, …zn], :value => vn},
]

分類

對於給定的數據,要判斷其屬於樣本數據中的哪一類,需解決如下幾個問題:

  1. 計算給定數據和樣本數據之間的距離
  2. 找出與給定數據距離最小的K個樣本數據
  3. 從這K個樣本數據中找出樣本多的那個分類,即爲給定數據的分類。
1. 計算距離

給定兩個向量[x0, x1,…xn][y0, y1,...yn]計算兩個向量之間的距離如下:

(x0 - y0)^2 + (x1 - y1)^2 + … + (xn - yn)^2

因此,對於給定的兩個向量a,b,其距離計算邏輯如下:

#a and b are two vectors
def distance_between a, b
  a.zip(b).map {|x| x[0] - x[1]}.inject(0){|sum, x| sum += x*x}
end
2. 找出與給定數據距離最小的K個樣本數據

可以採用計算給定數據與所有樣本數據的距離,然後採用最大堆來找出top k個樣本數據。

def nearest_neighbours candidate, k
  heap = MaxHeap.new
  @samples.each do |sample|
    distance = distance_between(sample[:vector], candidate)
    heap.insert Node.new(distance, sample)
  end
  heap.take_top(k).compact.map(&:sample)
end
3. 從這K個樣本數據中找出樣本多的那個分類,即爲給定數據的分類。

對得到的樣本根據其類別進行分組,組內元素多的那個類別,即爲該給定數據的分類

def value_with_max_vote xs
  value_with_votes = xs.group_by{|x| x[:value]}.map{|value, group| {:value => value, :votes => group.length}}
  value_with_votes.max_by{|x| x[:votes] }[:value]
end

綜合上面的幾個小任務,我們得到KNN分類算法的實現:

def categorize candidate, k
  neighbours = nearest_neighbours_for candidate, k
  value_with_max_vote neighbours
end

代碼的完整版本可以在這裏找到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章