输出结果
先看输出结果
实现代码
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import nltk
from bs4 import BeautifulSoup
import re
import os
import codecs
from sklearn import feature_extraction
#import three lists: titles, links and wikipedia synopses
titles = open('document_cluster_master/title_list.txt').read().split('\n')
#ensures that only the first 100 are read in
titles = titles[:100]
links = open('document_cluster_master/link_list_imdb.txt').read().split('\n')
links = links[:100]
synopses_wiki = open('document_cluster_master/synopses_list_wiki.txt').read().split('\n BREAKS HERE')
synopses_wiki = synopses_wiki[:100]
synopses_clean_wiki = []
for text in synopses_wiki:
text = BeautifulSoup(text, 'html.parser').getText()
#strips html formatting and converts to unicode
synopses_clean_wiki.append(text)
synopses_wiki = synopses_clean_wiki
genres = open('document_cluster_master/genres_list.txt').read().split('\n')
genres = genres[:100]
print(str(len(titles)) + ' titles')
print(str(len(links)) + ' links')
print(str(len(synopses_wiki)) + ' synopses')
print(str(len(genres)) + ' genres')
synopses_imdb = open('document_cluster_master/synopses_list_imdb.txt').read().split('\n BREAKS HERE')
synopses_imdb = synopses_imdb[:100]
synopses_clean_imdb = []
for text in synopses_imdb:
text = BeautifulSoup(text, 'html.parser').getText()
#strips html formatting and converts to unicode
synopses_clean_imdb.append(text)
synopses_imdb = synopses_clean_imdb
synopses = []
for i in range(len(synopses_wiki)):
item = synopses_wiki[i] + synopses_imdb[i]
synopses.append(item)
# generates index for each item in the corpora (in this case it's just rank) and I'll use this for scoring later
#为语料库中的每一个项目生成索引
ranks = []
for i in range(0,len(titles)):
ranks.append(i)
#定义一些函数对剧情简介进行处理。首先,载入 NLTK 的英文停用词列表。停用词是类似“a”,“the”,或者“in”这些无法传达重要意义的词。我相信除此之外还有更好的解释。
# load nltk's English stopwords as variable called 'stopwords'
stopwords = nltk.corpus.stopwords.words('english')
print (stopwords[:10]) #可以查看一下
#接下来我导入 NLTK 中的 Snowball 词干分析器(Stemmer)。词干化(Stemming)的过程就是将词打回原形,其实就是把长得很像的英文单词关联在一起。
# load nltk's SnowballStemmer as variabled 'stemmer'
from nltk.stem.snowball import SnowballStemmer
stemmer = SnowballStemmer("english")
# tokenize_and_stem:对每个词例(token)分词(tokenizes)(将剧情简介分割成单独的词或词例列表)并词干化
# tokenize_only: 分词即可
# 这里我定义了一个分词器(tokenizer)和词干分析器(stemmer),它们会输出给定文本词干化后的词集合
def tokenize_and_stem(text):
# 首先分句,接着分词,而标点也会作为词例存在
tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
filtered_tokens = []
# 过滤所有不含字母的词例(例如:数字、纯标点)
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
stems = [stemmer.stem(t) for t in filtered_tokens]
return stems
def tokenize_only(text):
# 首先分句,接着分词,而标点也会作为词例存在
tokens = [word.lower() for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
filtered_tokens = []
# 过滤所有不含字母的词例(例如:数字、纯标点)
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
return filtered_tokens
# 使用上述词干化/分词和分词函数遍历剧情简介列表以生成两个词汇表:经过词干化和仅仅经过分词后。
# 非常不 pythonic,一点也不!
# 扩充列表后变成了非常庞大的二维(flat)词汇表
totalvocab_stemmed = []
totalvocab_tokenized = []
for i in synopses:
allwords_stemmed = tokenize_and_stem(i) #对每个电影的剧情简介进行分词和词干化
totalvocab_stemmed.extend(allwords_stemmed) # 扩充“totalvocab_stemmed”列表
allwords_tokenized = tokenize_only(i)
totalvocab_tokenized.extend(allwords_tokenized)
#一个可查询的stemm词表,以下是词干化后的词变回原词例是一对多(one to many)的过程:词干化后的“run”能够关联到“ran”,“runs”,“running”等等。
vocab_frame = pd.DataFrame({'words': totalvocab_tokenized}, index = totalvocab_stemmed)
print ('there are ' + str(vocab_frame.shape[0]) + ' items in vocab_frame')
print (vocab_frame.head())
#利用Tf-idf计算文本相似度,利用 tf-idf 矩阵,你可以跑一长串聚类算法来更好地理解剧情简介集里的隐藏结构
from sklearn.feature_extraction.text import TfidfVectorizer
# 定义向量化参数
tfidf_vectorizer = TfidfVectorizer(max_df=0.8, max_features=200000,
min_df=0.2, stop_words='english',
use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3))
tfidf_matrix = tfidf_vectorizer.fit_transform(synopses) # 向量化剧情简介文本
print(tfidf_matrix.shape) #(100, 563),100个电影记录,每个电影后边有563个词
terms = tfidf_vectorizer.get_feature_names() #terms” 这个变量只是 tf-idf 矩阵中的特征(features)表,也是一个词汇表
#dist 变量被定义为 1 – 每个文档的余弦相似度。余弦相似度用以和 tf-idf 相互参照评价。可以评价全文(剧情简介)中文档与文档间的相似度。被 1 减去是为了确保我稍后能在欧氏(euclidean)平面(二维平面)中绘制余弦距离。
# dist 可以用以评估任意两个或多个剧情简介间的相似度
from sklearn.metrics.pairwise import cosine_similarity
dist = 1 - cosine_similarity(tfidf_matrix)
#2、采用H-Clustering算法进行Hierarchical document clustering
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import ward, dendrogram
linkage_matrix = ward(dist) # 聚类算法处理之前计算得到的距离dist(之前计算的余弦距离矩阵dist),用 linkage_matrix 表示
fig, ax = plt.subplots(figsize=(15, 20)) # 设置大小
ax = dendrogram(linkage_matrix, orientation="right", labels=titles);
plt.tick_params(
axis= 'x', # 使用 x 坐标轴
which='both', # 同时使用主刻度标签(major ticks)和次刻度标签(minor ticks)
bottom='off', # 取消底部边缘(bottom edge)标签
top='off', # 取消顶部边缘(top edge)标签
labelbottom='off')
plt.tight_layout() # 展示紧凑的绘图布局
# 注释语句用来保存图片
plt.savefig('ward_clusters.png', dpi=200) # 保存图片为 ward_clusters