聚类算法之k-means算法图像像素重新处理

前言:

机器学习----聚类算法的应用很广泛,属于非监督学习的它在无法提前定义标签的前提下将训练数据聚类。我们今天讨论其中比较简单的一种算法k-means算法。

k-means算法

每当你观察某些数据源时,很可能会发现数据会以某种形式形成聚类(cluster) 。如下图:

我们很容易看出来这些数据点可以聚成三类,但具体怎么聚,中心点在哪,数据多了以后还会出现聚几类的问题。这时我们就改用k-means算法了。

我们先举几个生活中的例子:

例如,每个输入可以是博客文章的标题(我们可以设法用数字向量来表示它) ,那么在这种情况下,我们的目标可能是对相似的文章进行聚类,也可能是了解用户都在写什么博客内容。或者,假设我们有一张包含数千种(红、绿、蓝)颜色的图片,但是我们需要一个5 色版本来进行丝网印刷。这时,聚类分析不仅可以帮助我们选出 5 种颜色,并且还能将“色差”控制在最小的范围之内。

k-均值算法(k-means)是一种最简单的聚类分析方法,它通常需要首先选出聚类 k 的数目,然后把输入划分为集合 S 1 ,…,S k ,并使得每个数据到其所在聚类的均值(中心对象)的距离的平方之和(即欧式距离)最小化。由于将 n 个点分配到 k 个聚类的方法非常多,所以寻找一个最优聚类方法是一件非常困难的事情。一般情况下,为了找到一个好的聚类方法,我们可以借助于迭代算法。

具体步骤:

1.首先从 d 维空间中选出选择 k 个数据点作为初始聚类的均值(即中心)。
2.计算每个数据点到这些聚类的均值(即聚类中心)的距离,然后把各个数据点分配给离它最近的那个聚类。
3.如果所有数据点都不再被重新分配,那么就停止并保持现有聚类。
4.如果仍有数据点被重新分配,则重新计算均值,并返回到第 2 步。

写具体的代码之前,我们先自己写个计算向量的工具类,方便以后使用:


from __future__ import division 
import re, math, random

# 
# functions for working with vectors
#

def vector_add(v, w):
    return [int(v_i) + int(w_i) for v_i, w_i in zip(v,w)]

def vector_subtract(v, w):
    return [int(v_i) - int(w_i) for v_i, w_i in zip(v,w)]

def vector_sum(vectors):
    return reduce(vector_add, vectors)

def scalar_multiply(c, v):
    return [c * v_i for v_i in v]

def vector_mean(vectors):
    n = len(vectors)
    return scalar_multiply(1/n, vector_sum(vectors))

def dot(v, w):
    """v_1 * w_1 + ... + v_n * w_n"""
    return sum(int(v_i) * int(w_i) for v_i, w_i in zip(v, w))

def sum_of_squares(v):
    """v_1 * v_1 + ... + v_n * v_n"""
    return dot(v, v)

def magnitude(v):
    return math.sqrt(sum_of_squares(v))

def squared_distance(v, w):
    return sum_of_squares(vector_subtract(v, w))

def distance(v, w):
   return math.sqrt(squared_distance(v, w))

def shape(A):
    num_rows = len(A)
    num_cols = len(A[0]) if A else 0
    return num_rows, num_cols

def get_row(A, i):
    return A[i]
    
def get_column(A, j):
    return [A_i[j] for A_i in A]

def make_matrix(num_rows, num_cols, entry_fn):
    return [[entry_fn(i, j) for j in range(num_cols)]
            for i in range(num_rows)]  

def is_diagonal(i, j):
    return 1 if i == j else 0

这样我们计算欧氏距离显得方便了很多。

class KMeans:
    def __init__(self, k):
        self.k = k          
        self.means = None  
    def classify(self, input):
        #求input的值里那个cluster最近,返回下标
        return min(range(self.k),
                   key=lambda i: vector.squared_distance(input, self.means[i]))
                   
    def train(self, inputs):
        self.means = random.sample(inputs, self.k)
        assignments = None
        while True:
            new_assignments = map(self.classify, inputs)
            #结束条件
            if assignments == new_assignments:                
                return
            #继续训练
            assignments = new_assignments
            for i in range(self.k):
                i_points = [p for p, a in zip(inputs, assignments) if a == i ]
                if i_points:                                
                    self.means[i] = vector.vector_mean(i_points)

图片的重新分配底色

有了k-means,我们来简单实现下上文提到的丝网印刷(5),

def recolor_image(input_file, k=5):
    img = mpimg.imread(input_file)
    pixels = [pixel for row in img 
            for pixel in row]
    clusterer = KMeans(k)
    clusterer.train(pixels)

    def recolor(pixel):
        cluster = clusterer.classify(pixel)
        return clusterer.means[cluster]

    new_img = [[recolor(pixel) for pixel in row]
               for row in img]
    plt.imshow(new_img)
    plt.axis('off')
    plt.show()

if __name__ == '__main__':
    input_file = "image/test.jpg"
    recolor_image(input_file, k=5)

我们来看看效果:

![](http://upload-images.jianshu.io/upload_images/2199772-78ae90909b6b8112.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

效果还行,有点像照片底片~

  • tips:测试时不要上传太大的图片哦,我这个是500 X 500的,跑了大概1min30s(4核CPU),笔记本风扇嗡嗡的~ - _ -

结束语

还有很多聚类的算法,这里只写出一个,欢迎留言给我,求告知除k-means和knn以外的算法哦~共同学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容