机器学习笔记3——聚类

来源:互联网 发布:三只眼 漫画 知乎 编辑:程序博客网 时间:2024/05/01 11:20

整理自Coursera。欢迎交流。

背景

  比方一个人正在阅读一篇文章,你则呢在语料库里面寻找相似的文章来推荐给这个人呢?这是好多公司面临的问题。你在阅读网页内容的时候网站是怎么给你推送你可能喜欢的文章呢?

相似度(Similarity)

  推送的文章肯定是与你正在阅读的文章相似的,因此有必要介绍一下怎么衡量2篇文章的相似度。
  最简单粗暴的办法是把一篇文章打乱,统计每个单词出现的次数。我们把2篇文章出现的同一单词的频数相乘就可以得到衡量相似度的指标。
  举个例子,我们有三篇文章:

No. Content No.1 I love her book, her book is interesting! No.2 He loves her book, her book is fun. No.3 The cat is mine.

统计单词频数:

No. I love her book he loves too the cat is mine interesting fun No.1 1 1 2 2 0 0 0 0 0 1 0 1 0 No.2 0 0 2 2 1 1 0 0 0 1 0 0 1 No.3 0 0 0 0 0 0 0 1 1 1 1 0 0

No.1 和 No.2的相似度:2×2+2×2+1×1=5
No.1 和 No.3的相似度:1×1=1
因此,No.1 和 No.2的相似度更高!

  这里还有一个问题,就是,如果No.3变为“The cat is mine. The cat is mine. The cat is mine. The cat is mine. The cat is mine. The cat is mine. The cat is mine.”[重复七次],则No.1 & No.3的相似度变为1×7=7,我们能说1和3更相似吗?显然不能。为了解决这种问题,我们需要把数据归一化。
  具体怎么归一化呢?我们可以让每一个数字除以方和根。
  这里写图片描述 

关键词和权重

  在介绍关键词之前先来介绍一下语料库的概念,语料库是指我们执行检索是数据库里所有文章包含的所有词汇的集合
  我们在查找一篇文章是否和给定文章相似的时候,希望可以用关键词来描述文章而不是像前面介绍的用一篇文章里的所有词汇,因此强调关键词就显得尤为重要。文章里的词汇可以分为常用词和生僻词,对于整个语料库而言,常用词是指在语料库中出现频率很高的词,生僻词是指在语料库中出现频率比较低的词。语料库的生僻词在某篇具体的文章可能是常用词,或者比较常用的词汇,这种词汇我们称之为局部常见,全局罕见词,这些词才是描述某篇文章的特征词汇,因此我们在计数这些词汇的时候就不能把这些词汇的权重和一般词汇设置的相等。
  那么我们如何降低一般的全局高频词汇(the,a ,it…)这些词汇的权重,提高某篇具体文章的特征词的权重呢?下面我介绍一种TF-IDF (Term Frequency-Inverse Document Frequency)方法,TF-IDF模型的主要思想是:如果词w在一篇文档d中出现的频率高,并且在其他文档中很少出现,则认为词w具有很好的区分能力,适合用来把文章d和其他文章区分开来。该模型主要包含了两个因素:

  1) 词w在文档d中的词频tf (Term Frequency),即词w在文档d中出现次数count(w, d)和文档d中总词数size(d)的比值:
tf(w,d) = count(w, d) / size(d)

  2) 词w在整个文档集合中的逆向文档频率idf (Inverse Document Frequency),即文档总数n与词w所出现文件数docs(w, D)比值的对数:
idf = log(n / docs(w, D))

  tf-idf模型根据tf和idf为每一个文档d和由关键词w[1]…w[k]组成的查询串q计算一个权值,用于表示查询串q与文档d的匹配度:

  tf-idf(q, d)
    = sum { i = 1..k | tf-idf(w[i], d) }
    = sum { i = 1..k | tf(w[i], d) * idf(w[i]) }

聚类

  前面介绍的都是寻找某个给定文本的相似文本,假设我们有一个很大的语料库,并且没有预先给好的标签,我们希望把这些文章分组,这就是一个聚类问题。这是一个非监督学习的例子。
  为了讨论方便,我们家假设有一种只有2个词汇word1&word2的精简语言,我们以word1频数作为横坐标,word2频数作为纵坐标,作出如下的坐标图
  这里写图片描述
  我们可以把聚集在一起的分为一类。(当然,实际上任何一种语言都有很多词汇,我们的到的是一个高维空间)。

K均值算法

  提到聚类,就不得说一下k-means聚类,K-means聚类算法的一般步骤:

  1.初始化。输入基因表达矩阵作为对象集X,输入指定聚类类数N,并在X中随机选取N个对象作为初始聚类中心。设定迭代中止条件,比如最大循环次数或者聚类中心收敛误差容限。
  2.进行迭代。根据相似度准则将数据对象分配到最接近的聚类中心,从而形成一类。初始化隶属度矩阵。
  3.更新聚类中心。然后以每一类的平均向量作为新的聚类中心,重新分配数据对象。
  4.反复执行第二步和第三步直至满足中止条件。

评价标准:
这里写图片描述
  假设有M个数据源,C个聚类中心。µc为聚类中心。该公式的意思也就是将每个类中的数据与每个聚类中心做差的平方和,J最小,意味着分割的效果最好。

python graphlab代码实现

数据文件和ipython notebook文件可以在这里下载。无需积分。

#coding:utf-8import graphlab#导入一些数据people = graphlab.SFrame('people_wiki.gl/')#统计每篇文章每个单词个数people['word_count'] = graphlab.text_analytics.count_words(people['text'])#求取tf-idf并添加到数据中tfidf = graphlab.text_analytics.tf_idf(people['word_count'])people['tfidf']=tfidf#我们可以在这里查看每篇文章特征词汇的tf-idf和词汇频数obama = people[people['name'] == 'Barack Obama']obama_word_count_table = obama[['word_count']].stack('word_count',new_column_name = ['word','count'])obama_word_count_table.head()obama_word_count_table.sort('count',ascending=False)obama[['tfidf']].stack('tfidf',new_column_name=['word','tfidf']).sort('tfidf',ascending=False)#可以求取两篇文章的距离,来比较clinton = people[people['name'] == 'Bill Clinton'] beckham = people[people['name'] == 'David Beckham']graphlab.distances.cosine(obama['tfidf'][0],clinton['tfidf'][0])#输出0.8339854936884276graphlab.distances.cosine(obama['tfidf'][0],beckham['tfidf'][0])#输出0.9791305844747478#我们用的cosine距离,距离越小说明越接近#建立聚类模型knn_model = graphlab.nearest_neighbors.create(people,features=['tfidf'],label='name')#求取与obama最相近的人物,文章knn_model.query(obama)

输出如下:
这里写图片描述

2 0