Ruby简单实现Kmeans聚类算法

http://fuliang.iteye.com/blog/891991

K-means是一个简单容易实现的聚类算法,我们以对一个图片的颜色的RGB值进行聚类为例, 
实现这个算法。 
K-means算法是一个EM的迭代过程: 
1.随机选择k个作为聚类中心 
2.E step: 
对每一个点,计算它到每一个聚类中心的距离,把这个点分配到最近的聚类中心代表的 
聚类中。 
3.M step: 
重新计算每个聚类的中心:每个聚类中心为该聚类所有点的均值。 

重复2~3直到达到最大的迭代次数或者聚类不再发生变化。 

Ruby代码  收藏代码
  1. #!/usr/bin/ruby  
  2. # autor: fuliang http://fuliang.iteye.com/  
  3.   
  4. class RGB  
  5.     attr_accessor :r,:g,:b  
  6.   
  7.     def initialize(r=0,g=0,b=0)  
  8.         @r,@g,@b = r,g,b  
  9.     end  
  10.   
  11.     def +(rgb)  
  12.         @r += rgb.r  
  13.         @g += rgb.g  
  14.         @b += rgb.b  
  15.         self  
  16.     end  
  17.   
  18.     def /(n)  
  19.         @r /= n  
  20.         @g /= n  
  21.         @b /= n  
  22.         self  
  23.     end  
  24. end  
  25.   
  26. def random_k_centers(instances,k)  
  27.     rand_indxes = (0...instances.size).sort_by{rand}[0...k]  
  28.     instances.values_at(*rand_indxes)  
  29. end  
  30.   
  31. def distance(ins1,ins2)#采用余弦值,因为255,255,255和200,200,200颜色基本类似  
  32.     dot_product = ins1.r * ins2.r + ins1.g * ins2.g + ins1.b * ins2.b  
  33.     mod1 = Math.sqrt(ins1.r * ins1.r + ins1.g * ins1.g + ins1.b * ins1.b)  
  34.     mod2 = Math.sqrt(ins2.r * ins2.r + ins2.g * ins2.g + ins2.b * ins2.b)  
  35.     return 1 - dot_product / (mod1 * mod2)  
  36. end  
  37.   
  38. def k_means_cluster(instances,k,max_iter=100)  
  39.     random_centers = random_k_centers(instances,k)  
  40.     p random_centers  
  41.     instance_cluster_map = {}  
  42.     change_count = 0  
  43.     clusters = []  
  44.     0.upto(max_iter) do |iter_num|  
  45.         clusters = []  
  46.         puts "iterate #{iter_num} ..."  
  47.         change_count = 0  
  48.         # E-step  
  49.         instances.each do |instance|  
  50.             min_distance = 1.0/0  
  51.             min_indx = 0  
  52.             random_centers.each_with_index do |center,index|  
  53.                 current_distance = distance(center,instance)  
  54.                 if min_distance > current_distance then  
  55.                     min_indx = index  
  56.                     min_distance = current_distance  
  57.                 end  
  58.             end  
  59.             if instance_cluster_map[instance] != min_indx then#trace the change  
  60.                 change_count += 1  
  61.                 instance_cluster_map[instance] = min_indx  
  62.             end  
  63.             clusters[min_indx] ||= []  
  64.             clusters[min_indx] << instance  
  65.         end  
  66.         puts "change_count=#{change_count}"  
  67.         break if change_count.zero?  
  68.         #M-step  
  69.         clusters.each_with_index do |cluster,index|  
  70.             center = RGB.new  
  71.             cluster.each do |instance|  
  72.                 center += instance  
  73.             end  
  74.             center /= cluster.size  
  75.             random_centers[index] = center # update center  
  76.         end  
  77.     end  
  78.     return clusters  
  79. end  
  80.   
  81. instances = []  
  82. File.open("rgbs.txt").each_line do |line|  
  83.     line.split(/\t/).each do | rgb |  
  84.         r,g,b = rgb.split(/,/).collect{|e| e.to_i}  
  85.         instances << RGB.new(r,g,b)  
  86.     end  
  87. end  
  88.   
  89. clusters = k_means_cluster(instances,5,100)  
  90. k_candidates = []  
  91. clusters.each do |cluster|  
  92.     sum = cluster.inject(RGB.new) {|sum,ins| sum + ins}  
  93.     candidate = sum / cluster.size  
  94.     k_candidates << candidate  
  95. end  
  96.   
  97. p k_candidates  


可以使用聚类算法对这个图片进行有损压缩。

原文地址:https://www.cnblogs.com/lexus/p/2265948.html