• 欢迎大家分享资料!前往留言板评论即可!

Python机器学习快速入门2

合宙 模组资料网 5个月前 (05-15) 72次浏览 已收录 0个评论 扫描二维码
文章目录[隐藏]

Python机器学习快速入门2

chapter03.聚类-寻找类似的帖子

上一章学习了分类的方法。用一定量数据按照某个模型去训练,就可以对新的数据进行分类了。这称作监督式学习,因为我们已经事先得到了数据确切的种类和属性(注意收集这些数据可能是非常费时费力的,比如测量全球范围某种植物叶子的尺寸?_?),并在这个框架下进行计算。

如果没有条件得到这种清晰的数据怎么办,那么只能从数据本身找出一些能自我描述的属性了。比如寻找相似的帖子,帖子标题千奇百怪,很难得出类似长宽高这样明确、意义重大的属性。聚类(Clustering)可以按某种标准把相似的数据聚成一类,从而把数据分成几类。标准需根据不同的数据类型和需求来制定。

1.预处理

对于寻找相似主题这个问题,一个比较基本的分类标准就是tfidf。
tfidf(https://en.wikipedia.org/wiki/Tf%E2%80%93idf)
tfidf用来给一个单词打分,反映出它在某个文集中对于某个句子的重要程度。这一章的知识也是搜索引擎的基础。

sklearn.feature_extraction.text.TfidfVectorizer
用这个来进行向量化并计算tfidf值
文档见http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer

python有个著名的自然语言处理包,http://nltk.org。
我们要用到nltk的词干化工具。因为在某些场合有些词的意义可以认为相同,但如果比较字符串的话程序会认为这个两个完全不同的词。
如buys和buying,birds和bird。
可以从TfidfVectorizer派生一个类,重载build_analyzer函数,返回之前求一下词干,这样analyzer返回的就统一都是词干了。

获取tfidf值的步骤:
1.提供min_df、max_df、stop_words等tfidf参数来生成vectorizer。
2.用build_analyzer函数返回一个analyzer,其中可插入入预处理,比如生成词干。
3.用fit学习数据。
4.用transform获取tfidf值(fit_transform可以把这两步合起来,并且更高效)。

到这预处理已经做好了,可以以tfidf来比较两个句子的’距离’了。代码中把两个由transform得出的tfidf向量相减(同一个词干的tfidf值相减)得出结果向量,最后取其norm值。越是相似(同一个词干的重要程度也就是tfidf值接近)的句子得到的结果也就是距离就越小。

代码见rel_post_01.py。

其中的问题:
1.单词间的关系得不到体现
2.无法检测反话,例如加个not,它会认为两句话很相似,但实际上意义完全相反
3.处理不了拼写错误

我们先忽略这些往下看。


2.聚类

https://en.wikipedia.org/wiki/Cluster_analysis
聚类算法主要分为两种,扁平类聚,层级类聚。扁平类聚把数据分割成若干组,所有组不相互联系,区别明显。多数算法需要用户指定组数。
层级类聚不需要指定组数,它会建立一个树状的层级结构。
scikit-learn的聚类文档:http://scikit-learn.org/dev/modules/clustering.html

k-means是最常用的一个扁平类聚算法。https://en.wikipedia.org/wiki/K-means_clustering

假设有一组数据,那么我们可以算出他们的质心,然后求出所有数据到质心的距离的和x。
k-means要做的是找到一种分法,把所有数据分成k组,并且所有组的x的总和在所有分法中最小。
最常见的实现方法是迭代算法,思想是先挑出k个数据作为k个组的初始质心,然后每次迭代时遍历每个数据,并把每个数据重新归到离它最近的那个质心所在的组,这样所有数据处理完后,质心可能发生了变化,那么下次迭代时,就以新的质心再做重新分配。就这样不断迭代,直到达到事先设定的收敛条件。初始质心的选择也有讲究,可以随机选,可以用户指定,还有k-means++等方法。具体请自行google。

动态演示:http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/AppletKM.html
感谢http://coolshell.cn/articles/7779.html
http://www.cnblogs.com/leoo2sk/archive/2010/09/20/k-means.html这个不错,按照近年的势头,应该把k设大一点,让国足冲击末流独占。

scikit-learn的KMeans文档和例子见http://scikit-learn.org/dev/modules/generated/sklearn.cluster.KMeans.html。
初始化KMeans类时可指定分类数量n_clusters,最大迭代次数max_iter,初始化方法init,还有一些收敛控制参数等等,具体请看源码和例子。
可以逐渐增加max_iter来对比每次迭代后的分类变化。代码见plot_kmeans_example.py。

Python机器学习快速入门2

Python机器学习快速入门2

Python机器学习快速入门2

Python机器学习快速入门2

可以看到迭代时质心和分类的变化。

聚类评估
http://scikit-learn.org/stable/modules/clustering.html#clustering-evaluation

提一个词ground truth(https://en.wikipedia.org/wiki/Ground_truth),文档中经常出现,可以理解为实际值或者正确答案。

一致性和完整性(homogeneity, completeness)
一致性指预测完后,每个聚类中,所有的数据点必须来源于同一个事实上的类。
完整性指预测完后,所有事实上在同个类中的数据点必须落在同一个聚类中。
这两个性质大概呈一个矛盾,往往是一个强另一个弱。具体得研究这个paper:http://aclweb.org/anthology/D/D07/D07-1043.pdf

文档见http://scikit-learn.org/stable/modules/clustering.html#homogeneity-completeness
代码见sklearn.metrics.homogeneity_score函数,最终会求到两个list的香农熵(https://en.wikipedia.org/wiki/Entropy_%28information_theory%29)和MI(https://en.wikipedia.org/wiki/Mutual_information)。

这两个值的调和平均数(https://en.wikipedia.org/wiki/Harmonic_mean)又形成另一个评估值v-measure。

还有几种评估,以及各种评估的优缺点,请看文档。

最后看一下帖子分类的代码(rel_post_20news.py):

import sklearn.datasets
import scipy as sp

new_post = \
    """Disk drive problems. Hi, I have a problem with my hard disk.
After 1 year it is working only sporadically now.
I tried to format it, but now it doesn't boot any more.
Any ideas? Thanks.
"""

print("""\
Dear reader of the 1st edition of 'Building Machine Learning Systems with Python'!
For the 2nd edition we introduced a couple of changes that will result into
results that differ from the results in the 1st edition.
E.g. we now fully rely on scikit's fetch_20newsgroups() instead of requiring
you to download the data manually from MLCOMP.
If you have any questions, please ask at http://www.twotoreal.com
""")

# 取原始数据
all_data = sklearn.datasets.fetch_20newsgroups(subset="all")
print("Number of total posts: %i" % len(all_data.filenames))
# Number of total posts: 18846

groups = [
    'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware',
    'comp.sys.mac.hardware', 'comp.windows.x', 'sci.space']

# 取训练数据
train_data = sklearn.datasets.fetch_20newsgroups(subset="train",
                                                 categories=groups)
print("Number of training posts in tech groups:", len(train_data.filenames))
# Number of training posts in tech groups: 3529

labels = train_data.target
print("labels = {0}".format(labels))
print("len(labels) = {0}".format(len(labels)))

# 定为50个聚类,在这个应用中就是把要把原始帖子归到50个组里,打破了原始数据的类别。
# 例如这里从原始数据取了6组,原始的labels为0到5,而k定为50训练完以后,labels为0到49。
num_clusters = 50  # sp.unique(labels).shape[0]

import nltk.stem
english_stemmer = nltk.stem.SnowballStemmer('english')

from sklearn.feature_extraction.text import TfidfVectorizer

class StemmedTfidfVectorizer(TfidfVectorizer):

    def build_analyzer(self):
        analyzer = super(TfidfVectorizer, self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

# 生成vectorizer,将滤去词频排名的前50%和出现小于10次的词。
# stop_words设为'english'滤去英语中常见的对区分句子来说意义不大的词。可跟踪vectorizer.get_stop_words()。
# 同时忽略解码错误。
vectorizer = StemmedTfidfVectorizer(min_df=10, max_df=0.5,
                                    stop_words='english', decode_error='ignore'
                                    )

# 向量化和学习train_data,得到结果vectorized。
vectorized = vectorizer.fit_transform(train_data.data)
num_samples, num_features = vectorized.shape # 这里num_samples是数据个数也就是帖子总数,num_features是词干总数。
print("#samples: %d, #features: %d" % (num_samples, num_features))
# samples: 3529, #features: 4712
print("len(vectorizer.get_feature_names()) = {0}".format(len(vectorizer.get_feature_names())))

from sklearn.cluster import KMeans
# 生成KMeans实例km
km = KMeans(n_clusters=num_clusters, n_init=1, verbose=1, random_state=3)
# 以vectorized来训练
clustered = km.fit(vectorized)

# 训练完以后,km的labels_就储存了聚类的结果。
print("km.labels_=%s" % km.labels_)
# km.labels_=[ 6 34 22 ...,  2 21 26]

print("km.labels_.shape=%s" % km.labels_.shape)
# km.labels_.shape=3529

# 各种打分
from sklearn import metrics
print("Homogeneity: %0.3f" % metrics.homogeneity_score(labels, km.labels_))
# Homogeneity: 0.400
print("Completeness: %0.3f" % metrics.completeness_score(labels, km.labels_))
# Completeness: 0.206
print("V-measure: %0.3f" % metrics.v_measure_score(labels, km.labels_))
# V-measure: 0.272
print("Adjusted Rand Index: %0.3f" %
      metrics.adjusted_rand_score(labels, km.labels_))
# Adjusted Rand Index: 0.064
print("Adjusted Mutual Information: %0.3f" %
      metrics.adjusted_mutual_info_score(labels, km.labels_))
# Adjusted Mutual Information: 0.197
print(("Silhouette Coefficient: %0.3f" %
       metrics.silhouette_score(vectorized, labels, sample_size=1000)))
# Silhouette Coefficient: 0.006

# 根据对原始文档的学习结果,向量化测试帖子。
new_post_vec = vectorizer.transform([new_post])
# 这里可以看到向量化一个帖子得到的数据
print("new_post_vec = {0}".format(new_post_vec))
print("new_post_vec.shape = {0}".format(new_post_vec.shape))
print("new_post_vec.data = {0}".format(new_post_vec.data))

# 用km预测
new_post_label = km.predict(new_post_vec)[0]

print("new_post_label = {0}".format(new_post_label))

# 获取训练结果中与预测结果同类的帖子
similar_indices = (km.labels_ == new_post_label).nonzero()[0]

similar = []
for i in similar_indices:
    # 计算距离(相似度)
    dist = sp.linalg.norm((new_post_vec - vectorized[i]).toarray())
    similar.append((dist, train_data.data[i]))

# 排序 打印前三个最相似的帖子
similar = sorted(similar)
print("Count similar: %i" % len(similar))

show_at_1 = similar[0]
show_at_2 = similar[int(len(similar) / 10)]
show_at_3 = similar[int(len(similar) / 2)]

print("=== #1 ===")
print(show_at_1)
print()

print("=== #2 ===")
print(show_at_2)
print()

print("=== #3 ===")
print(show_at_3)

转载请注明原文链接:Python机器学习快速入门2
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址