avatar

目录
python K-means聚类尝试

最近有一个需求,需要从 42W 左右的用户搜索词中提取比较重要的 1000 个词作为我们的关键字。
实在不知道怎么提取这1000 个关键字,于是考虑针对 42W 次做一个聚类,聚类出 1000 个组,然后提取每个组的主题词作为最终结果。

流程

  1. 结合自定义词典,针对 42W 结巴分词
  2. 去除停用词
  3. 去重
  4. 生成 tf-idf 矩阵
  5. K-means 聚类
  6. 提取每个类的词频最高的次作为主题词

代码实现

1.分词

加上了自己整理的简单的一点自定义词典,用结巴分词的精准模式分词。
word.txt 中是整理的自定义词典
keyword-1.txt 是需要分词的数据,一行一个
keyword.txt 是分词后的数据

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_jiebaword():
jieba.load_userdict('word.txt')
# with open('keyword.txt') as fr:
with open('keyword-1.txt') as fr:
lines = fr.readlines()

jiebaword = []
for line in lines:
line = line.strip('\n')
# 默认精确模式
seg_list = jieba.cut(line, cut_all=False)
word = "/".join(seg_list)
jiebaword.append(word)
return jiebaword

avatar

2.去除停用词

加载停用词列表,(因为我这边的搜索词,基本都是一些技术相关类词,且都不长,发现加了停用词后效果并不好,最终版就没有加)
stop-words.txt是停用词文档。

python
1
2
3
4
5
6
7
8
9
10
# 拿到停用词
def get_stopword():
stopword = []
with open('stop-words.txt') as fr:
stopwords = fr.readlines()

for line in stopwords:
line = line.strip('\n')
stopword.append(line)
return stopword

去除停用词的逻辑是如果这个词(分词后的词)有停用词中的某一个,则摒弃这个词。
将结果写入clean-word.txt

python
1
2
3
4
5
6
7
8
9
10
11
# 去除停用词
def clean_stopword(jiebaword,stopword):
fw = open('clean-word.txt','a+',encoding='utf-8')
for words in jiebaword:
words = words.split('/')
for word in words:
if word not in stopword:
fw.write(word+'\t')

fw.write('\n')
fw.close()

3. 文档去重

这一步骤是因为发现,原本已经去重后的搜索词,再去除停用词后可能会出现重复的词。比方说停用词是“的”,原本两个词分别是“七牛服务器”,
和“七牛的服务器”,分词再去除停用词后都变成了“七牛/服务器”,就再需要去重一遍。

去重后写入到clean-word-2.txt 文件中

python
1
2
3
4
5
6
7
8
9
10
def de_duplication():
outfile = open('clean-word-2.txt','a+',encoding='utf-8')
with open('clean-word.txt') as fr:
words = fr.readlines()
result = set()
for line in words:
if line not in result:
result.add(line)
outfile.write(line)
outfile.close()

4. 生成tf-idf矩阵

我们只有把文章词语转化成数字,才能进行计算。转化成tf-idf矩阵是一个不错的选择,具体而言tf-idf是体现文档相似度的,关于它的解释很多。

简单理解:同一个词语,如果在文章A和文章B中都出现了很多次,那说明这两篇文章很相似,这就是tf

相反地,同一个词语,在所有文章中极少出现,而恰恰在文章A和文章B中出现过,也可以说明这两篇文章相似,这就是idf

同时考虑这两个维度,就是我们常说的tf-idf

python
1
2
3
4
5
6
7
8
9
# 生成 tf-idf 矩阵
def get_tfidf():
with open('clean-word-2.txt','r') as fr:
lines = fr.readlines()
transformer = TfidfVectorizer()
tfidf = transformer.fit_transform(lines)
# 转为数组形式
tfidf_arr = tfidf.toarray()
return tfidf_arr

5. K-means 聚类

接下来我们就可以进行聚类了, 把加过写进k-means.txt 文件

python
1
2
3
4
5
6
7
8
9
def get_cluster(tfidf_arr,k):
kmeans = KMeansClusterer(num_means=k, distance=cosine_distance) # 分成k类,使用余弦相似分析
kmeans.cluster(tfidf_arr)
# 获取分类
kinds = pd.Series([kmeans.classify(i) for i in tfidf_arr])
fw = open('k-means.txt', 'a+', encoding='utf-8')
for i, v in kinds.items():
fw.write(str(i) + '\t' + str(v) + '\n')
fw.close()

结果是两列数字,前一个数字代表文本的下标,后一个数字代表分类的编号。

6. 获取主题词 / 主题词团

分完类之后,还需要找出这个类的主题词,所以按照分类结果,把同类的文本写入同一个文件中。

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def cluster_text():
index_cluser = []
with open('k-means.txt', "r", encoding='utf-8') as fr:
lines = fr.readlines()

for line in lines:
line = line.strip('\n')
line = line.split('\t')
index_cluser.append(line)
# index_cluser[i][j]表示第i行第j列
with open('clean-word-2.txt', "r", encoding='utf-8') as fr:
lines = fr.readlines()

for index,line in enumerate(lines):
for i in range(len(lines)):
if str(index) == index_cluser[i][0]:
fw = open('title' + index_cluser[i][1] + '.txt', 'a+', encoding='utf-8')
fw.write(line)
fw.close()

然后基本就完成了分类的工作,把上述流程一次完成,就可以实现文本的分类功能。

但是自测下来,基本十万的数据,结果还可以。但数据量一旦过大,比方说 20W 分 1000 类,就很难跑出来了。所以最后其实我的数据也没有用上述方法得出结果。

文章作者: Viola Tangxl
文章链接: https://violatangxl.github.io/2021/11/15/python-K-means/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 椰子是只猫
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论