1.实验目的
学习K-means理论,并使用K-means对文本进行分类
2.理论方法介绍
对于"监督学习"(supervised learning),其训练样本是带有标记信息的,并且监督学习的目的是:对带有标记的数据集进行模型学习,从而便于对新的样本进行分类。而在“无监督学习”(unsupervised learning)中,训练样本的标记信息是未知的,目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律,为进一步的数据分析提供基础。对于无监督学习,应用最广的便是"聚类"(clustering)。
“聚类算法”试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”(cluster),通过这样的划分,每个簇可能对应于一些潜在的概念或类别。
kmeans算法又名k均值算法。其算法思想大致为:先从样本集中随机选取 k 个样本作为簇中心,并计算所有样本与这 k 个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。
根据以上描述,我们大致可以猜测到实现kmeans算法的主要三点:
- 簇个数 k 的选择
- 各个样本点到“簇中心”的距离
- 根据新划分的簇,更新“簇中心”
K-means算法要点
(1) k值得选择
k 的选择一般是按照实际需求进行决定,或在实现算法时直接给定 k 值。
(2) 距离的度量
给定样本
x
(
i
)
=
{
x
1
(
i
)
,
x
2
(
i
)
,
,
.
.
.
,
x
n
(
i
)
,
}
与
x
(
j
)
=
{
x
1
(
j
)
,
x
2
(
j
)
,
,
.
.
.
,
x
n
(
j
)
,
}
x^{(i)} = \lbrace x_1^{(i)},x_2^{(i)},,...,x_n^{(i)}, \rbrace 与 x^{(j)} = \lbrace x_1^{(j)},x_2^{(j)},,...,x_n^{(j)}, \rbrace
x(i)={x1(i),x2(i),,...,xn(i),}与x(j)={x1(j),x2(j),,...,xn(j),},其中 i,j=1,2,…,m,表示样本数,n表示特征数。距离的度量方法主要分为以下几种:
有序属性距离度量:
闵可夫斯基距离(Minkowski distance):
d
i
s
t
m
k
(
x
(
i
)
,
x
(
j
)
)
=
(
∑
u
=
1
n
∣
x
u
(
i
)
−
x
u
(
j
)
∣
p
)
1
p
dist_{mk}(x^{(i)},x^{(j)})=(\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|^p)^{\frac{1}{p}}
distmk(x(i),x(j))=(u=1∑n∣xu(i)−xu(j)∣p)p1
欧氏距离(Euclidean distance),即当 p=2 时的闵可夫斯基距离:
d
i
s
t
e
d
(
x
(
i
)
,
x
(
j
)
)
=
∣
∣
x
(
i
)
−
x
(
j
)
∣
∣
2
=
∑
u
=
1
n
∣
x
u
(
i
)
−
x
u
(
j
)
∣
2
dist_{ed}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||_2=\sqrt{\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|^2}
disted(x(i),x(j))=∣∣x(i)−x(j)∣∣2=u=1∑n∣xu(i)−xu(j)∣2
曼哈顿距离(Manhattan distance),即当 p=1 时的闵可夫斯基距离:
d
i
s
t
m
a
n
(
x
(
i
)
,
x
(
j
)
)
=
∣
∣
x
(
i
)
−
x
(
j
)
∣
∣
1
=
∑
u
=
1
n
∣
x
u
(
i
)
−
x
u
(
j
)
∣
dist_{man}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||_1=\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|
distman(x(i),x(j))=∣∣x(i)−x(j)∣∣1=u=1∑n∣xu(i)−xu(j)∣
无序属性距离度量:
VDM(Value Difference Metric):
V
D
M
p
(
x
u
(
i
)
,
x
u
(
j
)
)
=
∑
z
=
1
k
∣
m
u
,
x
u
(
i
)
,
z
m
u
,
x
u
(
i
)
−
m
u
,
x
u
(
j
)
,
z
m
u
,
x
u
(
j
)
∣
p
VDM_p(x_u^{(i)},x_u^{(j)}) = \sum_{z=1}^k \left|\frac{m_{u,x_u^{(i)},z}}{m_{u,x_u^{(i)}}} - \frac{m_{u,x_u^{(j)},z}}{m_{u,x_u^{(j)}}} \right|^p
VDMp(xu(i),xu(j))=z=1∑k∣∣∣∣∣mu,xu(i)mu,xu(i),z−mu,xu(j)mu,xu(j),z∣∣∣∣∣p
混合属性距离度量
M
i
n
k
o
v
D
M
p
(
x
(
i
)
,
x
(
j
)
)
=
(
∑
u
=
1
n
c
∣
x
u
(
i
)
−
x
u
(
j
)
∣
p
+
∑
u
=
n
c
+
1
n
V
D
M
p
(
x
u
(
i
)
,
x
u
(
j
)
)
)
1
p
MinkovDM_p(x^{(i)},x^{(j)}) = \left( \sum_{u=1}^{n_c} | x_u^{(i)} - x_u^{(j)} | ^p + \sum_{u=n_c +1}^n VDM_p (x_u^{(i)},x_u^{(j)}) \right) ^{\frac{1}{p}}
MinkovDMp(x(i),x(j))=(u=1∑nc∣xu(i)−xu(j)∣p+u=nc+1∑nVDMp(xu(i),xu(j)))p1
Kmeans算法过程
3.实验数据及方法
本实验使用数据为中文文本分类数据集
THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档(2.19 GB),均为UTF-8纯文本格式。在原始新浪新闻分类体系的基础上,重新整合划分出14个候选分类类别:财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐。
本实验使用其中家居、彩票、房产、股票、财经5类,各50篇作为数据集。
1.导入必要的工具包
import os
import jieba
jieba.setLogLevel(20) #使jieba分词不显示日志
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
import warnings
warnings.filterwarnings('ignore')
2.将文件地址储存到数组
import os
path_list_all = []
for a, b, c in os.walk('D:\Working\THUCNews', topdown=False):
path_list = []
for files in c:
path = a+'\\'+files
path_list.append(path)
path_list = path_list[:50]
if path_list != []:
path_list_all.append(path_list)
path_list_all = np.array(path_list_all)
print('包含文件数量:({},{})'.format(len(path_list_all),len(path_list_all[0])))
#包含文件数量:(5,50)
3.储存停用词
# 将停用词记录到列表stopWords中
stopWords = []
infile = open("D:\workspace\机器学习实验(课堂)\基于NBC的文本分类\stop_word_list.txt",
encoding='utf-8')
stopwords_lst = infile.readlines()
for word in stopwords_lst:
stopWords.append(word.strip())
4.分词、去停用词,将处理后的文本储存到X_list中,标签储存到y_list中
X_list = [] # 储存处理好的文本,字符串形式
y_list = [] # 储存标签
for path in path_list_all:
for n in range(len(path)):
with open(path[n],mode='r',encoding='utf-8') as note:
note = note.read()
note_1 = note.replace('\n','')
# print(note_1)
seglist = jieba.lcut(note_1)
# 去停用词
newSent = []
for word in seglist:
word = word.strip()
if word not in stopWords:
if word != '\t' and word != '\n':
newSent.append(word)
label = path[n].split('\\')[-2]
# print(label)
text_str = ' '.join(newSent)
X_list.append(text_str)
y_list.append(label)
5.统计词频
# 统计词频
vectorizer = CountVectorizer( )
# 计算个词语出现的次数
X = vectorizer.fit_transform(X_list)
# 获取词袋中所有文本关键词
word = vectorizer.get_feature_names()
print('共有多少文本关键字:', len(word))
# 查看词频结果
print('词频矩阵的维度:', X.toarray().shape)
'''
共有多少文本关键字: 16857
词频矩阵的维度: (250, 16857)
'''
6.计算TF-IDF值
# 计算tfidf值
from sklearn.feature_extraction.text import TfidfTransformer
# 类调用
transformer = TfidfTransformer()
# 将词频矩阵X统计成TF-IDF值
tfidf = transformer.fit_transform(X)
# 查看数据结构 tfidf[i][j]表示i类文本中的tf-idf权重
X_data = tfidf.toarray()
7.使用K-means进行聚类
from sklearn.cluster import KMeans
estimator = KMeans(n_clusters=5)
estimator.fit(X_data)#聚类
4.实验结果及分析
1.输出分类结果
print(estimator.labels_)
'''
[0 0 3 3 3 3 3 3 3 3 3 3 3 0 3 0 3 3 3 0 3 3 3 0 3 3 3 3 3 3 2 2 2 2 2 2 0
2 2 2 2 2 2 2 2 2 2 2 3 3 0 1 0 0 1 0 2 1 2 1 0 1 0 1 1 1 1 1 1 0 0 1 1 1
1 0 0 1 1 1 2 1 1 1 1 1 1 1 1 1 1 2 1 1 0 1 1 0 0 1 0 3 3 3 3 3 0 0 3 3 0
3 3 0 3 3 3 3 3 3 0 3 0 3 0 0 3 3 3 3 3 0 0 0 0 3 0 0 0 3 0 3 3 3 3 0 3 3
0 0 0 4 4 0 4 0 4 4 0 4 4 4 0 4 4 4 0 4 4 4 0 4 4 4 0 4 4 4 4 4 4 4 4 4 4
4 4 4 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0
0 0 0 0 0 3 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
'''
2.统计一下每类文本个数
from collections import Counter
print(Counter(estimator.labels_))
# Counter({3: 118, 1: 39, 2: 32, 0: 31, 4: 30})
类别 | 数量 |
---|---|
3 | 118 |
1 | 39 |
2 | 32 |
0 | 31 |
4 | 30 |
仅从分类数量上来看,文本聚类的准确度有待增强。在对文本进行聚类时应考虑其他分类方法,以达到更好的分类效果。无监督学习由于其没有标签,也无法较好的评判其分类准确度。