1.实验目的
使用SVM进行文本分类
2.理论方法介绍
支持向量机是一种二分类模型。它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;支持向量机还包括核技巧,这使它成为实质上的分线性分类器。支持向量机的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,也等价正则化的合页损失函数的最小化问题。支持向量机的学习算法是求解凸二次规划的最优化算法。
支持向量机学习方法包含构建由简至繁的模型:线性可分支持向量机、线性支持向量机以及非线性支持向量机。简单模型是复杂模型的基础,也是复杂模型的特殊情况。当训练数据线性可分时,通过硬间隔最大化,学习一个线性分类器,即线性可分支持向量机,又称为硬间隔支持向量机;当训练数据近似线性可分时,通过软间隔最大化,也学习一个线性的分类器,即线性支持向量机,又称为软间隔支持向量机;当训练数据线性不可分时,通过使用核技巧及软间隔最大化,学习非线性支持向量机。
当输入空间为欧氏空间或离散集合、特征空间为希尔伯特空间时,核函数表示将输入从输入空间映射到特征空间得到的特征向量之间的内积。通过使用核函数可以学习非线性支持向量机,等价于隐式地在高维的特征空间中学习线性支持向量机。这样的方法称为核技巧。核方法是比支持向量机更为一般的机器学习方法。
Cortes和Vapnik提出线性支持向量机,Boser、Guyon与Vapnik又引入核技巧,提出非线性支持向量机。
非线性支持向量机:
对于输入空间中的非线性分类问题,可以通过非线性变换将它转化为某个高位特种空间中的线性分类问题,在高维特征空间中学习线性支持向量机。由于在线性支持向量机学习的对偶问题里,目标函数和分类决策函数都只涉及实例与实例之间的内积,所以不需要显式地指定非线性变换,二十用核函数来替换当中的内积。核函数表示,通过一个非线性转换后的两个实例间的内积。具体地,
K
(
x
,
z
)
K(x,z)
K(x,z)是一个核函数,或正定核,意味着存在一个从输入空间
χ
\chi
χ到特征空间
H
\Eta
H的映射
ϕ
(
x
)
:
χ
→
χ
\phi(x):\chi \to\chi
ϕ(x):χ→χ,有
K
(
x
,
z
)
=
ϕ
(
x
)
⋅
ϕ
(
z
)
K(x,z)=\phi(x)·\phi(z)
K(x,z)=ϕ(x)⋅ϕ(z)
对称函数
K
(
x
,
z
)
K(x,z)
K(x,z)为正定核的充要条件如下:对任意
x
i
∈
χ
,
i
=
1
,
2
,
.
.
.
,
m
,
x_i\in\chi,i=1,2,...,m,
xi∈χ,i=1,2,...,m,任意正整数m,对称函数
K
(
x
,
z
)
K(x,z)
K(x,z)对应的Gram矩阵是半正定的。所以在线性支持向量机学习的对偶问题中,用核函数
K
(
x
,
z
)
K(x,z)
K(x,z)代替内积,求解得到的就是非线性支持向量机
f
(
x
)
=
s
i
g
n
(
∑
i
=
1
N
α
i
∗
y
i
K
(
x
,
x
i
)
+
b
∗
f(x)=sign(\sum_{i=1}^N\alpha^*_iy_iK(x,x_i)+b^*
f(x)=sign(i=1∑Nαi∗yiK(x,xi)+b∗
3.实验数据及方法
本实验使用数据为中文文本分类数据集
THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档(2.19 GB),均为UTF-8纯文本格式。在原始新浪新闻分类体系的基础上,重新整合划分出14个候选分类类别:财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐。
本实验使用其中家居、彩票、房产、股票、财经5类,各500篇作为数据集。
1.输出目录树
import os
def list_files(startpath):
for root, dirs, files in os.walk(startpath):
level = root.replace(startpath, '').count(os.sep)
dir_indent = "| " * (level-1) + "|-- "
file_indent = "| " * level + "|-- "
if not level:
print('.')
else:
print('{}{}'.format(dir_indent, os.path.basename(root)))
list_files('D:\Working')
'''
.
|-- THUCNews
| |-- 家居
| |-- 彩票
| |-- 房产
| |-- 股票
| |-- 财经
'''
2.导入必要的工具包
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')
3.将文件地址储存到数组
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)
4.储存停用词
# 将停用词记录到列表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())
5.分词、去停用词,将处理后的文本储存到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)
6.统计词频
# 统计词频
vectorizer = CountVectorizer( )
# 计算个词语出现的次数
X = vectorizer.fit_transform(X_list)
# 获取词袋中所有文本关键词
word = vectorizer.get_feature_names()
print('共有多少文本关键字:', len(word))
# 查看词频结果
print('词频矩阵的维度:', X.toarray().shape)
'''
共有多少文本关键字: 16857
词频矩阵的维度: (250, 16857)
'''
7.计算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()
8.使用sklearn中的SVC函数进行分类
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_data, y_list,
test_size=0.33,
random_state=3)
from sklearn.svm import SVC
data = open("data.txt", 'w+')
c_value = [1e3, 5e3, 1e4, 5e4, 1e5]
gamma_value = [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1]
for c in c_value:
for g in gamma_value:
# print(type(c),type(g))
clf = SVC(C=c, gamma=g, kernel='rbf')
clf.fit(X_train, y_train)
# print('score:',clf.score(X_test, y_test))
y_pred = clf.predict(X_test)
y_true = np.array(y_test)
y_pred, y_true = strList2numList(y_pred, y_true)
data.write('C:{},gamma:{:.4f},score:{:.2f}\n'.format(c, g,
clf.score(X_test, y_test)))
data.close()
4.实验结果及分析
在类别为家居的文本中,出现次数前十的汉字词为
词语 | 出现次数 |
---|---|
龟背竹 | 1647 |
龟背 | 1646 |
龙骨 | 1645 |
齐聚 | 1644 |
黑色 | 1643 |
黑白 | 1642 |
黏土砖 | 1641 |
黄色 | 1640 |
鹅绒 | 1639 |
鹅卵石 | 1638 |
在类别为彩票的文本中,出现次数前十的汉字词为
词语 | 出现次数 |
---|---|
龟缩 | 3283 |
齐齐 | 3282 |
齐整 | 3281 |
鼓舞 | 3280 |
黯淡 | 3279 |
默特 | 3278 |
默契 | 3277 |
黑马 | 3276 |
黑山 | 3275 |
黄志杰 | 3274 |
在类别为房产的文本中,出现次数前十的汉字词为
词语 | 出现次数 |
---|---|
龚继 | 6377 |
龙身 | 6376 |
龙脉 | 6375 |
龙湖 | 6374 |
龙岗区 | 6373 |
龙头 | 6372 |
齐聚 | 6371 |
齐全 | 6370 |
鼠标 | 6369 |
鼓励 | 6368 |
在类别为股票的文本中,出现次数前十的汉字词为
词语 | 出现次数 |
---|---|
龙头 | 4348 |
鼓吹 | 4347 |
鼓励 | 4346 |
黑马 | 4345 |
黑化 | 4344 |
黄金分割 | 4343 |
黄金价格 | 4342 |
黄金 | 4341 |
麻烦 | 4340 |
麦肯锡 | 4339 |
在类别为财经的文本中,出现次数前十的汉字词为
词语 | 出现次数 |
---|---|
龙纹 | 6468 |
龙江 | 6467 |
齐白石 | 6466 |
齐全 | 6465 |
鼠年 | 6464 |
鼓励 | 6463 |
默契 | 6462 |
默写 | 6461 |
黑龙江省 | 6460 |
黑龙江 | 6459 |
使用不同的C值和gamma值训练SVM,得到的结果如下
C-Value | gamma-value | Score |
---|---|---|
1000.0 | 0.0001 | 0.66 |
1000.0 | 0.0005 | 0.90 |
1000.0 | 0.0010 | 0.90 |
1000.0 | 0.0050 | 0.90 |
1000.0 | 0.0100 | 0.90 |
1000.0 | 0.1000 | 0.90 |
5000.0 | 0.0001 | 0.90 |
5000.0 | 0.0005 | 0.90 |
5000.0 | 0.0010 | 0.90 |
5000.0 | 0.0050 | 0.90 |
5000.0 | 0.0100 | 0.90 |
5000.0 | 0.1000 | 0.90 |
10000.0 | 0.0001 | 0.90 |
10000.0 | 0.0005 | 0.90 |
10000.0 | 0.0010 | 0.90 |
10000.0 | 0.0050 | 0.90 |
10000.0 | 0.0100 | 0.90 |
10000.0 | 0.1000 | 0.90 |
50000.0 | 0.0001 | 0.90 |
50000.0 | 0.0005 | 0.90 |
50000.0 | 0.0010 | 0.90 |
50000.0 | 0.0050 | 0.90 |
50000.0 | 0.0100 | 0.90 |
50000.0 | 0.1000 | 0.90 |
100000.0 | 0.0001 | 0.90 |
100000.0 | 0.0005 | 0.90 |
100000.0 | 0.0010 | 0.90 |
100000.0 | 0.0050 | 0.90 |
100000.0 | 0.0100 | 0.90 |
100000.0 | 0.1000 | 0.90 |
对该实验来说,C和gamma的变化,对实验结果影响很小。