一.理论方法介绍
SVM(Support Vector Machine)指的是支持向量机,是常见的一种判别方法。在机器学习领域,是一个有监督的学习模型,可以用来进行分类研究。
SVM二分类
SVM二分类的基本思想是在特征空间中寻找间隔最大的分离超平面使数据得到高效的二分类,有三种情况:
- 当训练样本线性可分时,通过硬间隔最大化,学习一个线性分类器,即线性可分支持向量机;
- 当训练数据近似线性可分时,引入松弛变量,通过软间隔最大化,学习一个线性分类器,即线性支持向量机;
- 当训练数据线性不可分时,通过引入核函数技巧及软间隔最大化,学习非线性支持向量机。
svm多分类
svm本身是一个追求类别超平面间支持向量距离最大化的二分类器,本实验的目标是对于三种不同类型文本构造分类器,属于多分类问题。主要是通过组合多个二分类器来实现多分类器的构造,多分类通常有一对多,一对一,多对多等。实验中采取的是one-versus-rest一对多方法,简称OVR SVMs。训练步骤如下:
- 首先A类对应的向量作为正样本,B,C对应的样本作为负样本
- B对应的向量作为正样本,A,C对应的向量作为负样本
- C对应的向量作为正样本,A,B对应的向量作为负样本
- 这3个训练集分别进行训练,得到四个训练结果文件
- 测试时,把对应的测试向量分别利用这三个结果进行文件测试
- 得到三个分类结果:y1(x),y2(x),y3(x),选择三个结果中值最大的一个作为分类结果。
以A为列子,第一次训练,分类器认为它是A,不是负类。第二个分类器会认为他不是B类,第三个分类器会认为它不是C类,这样就得到了它的真正类别。
二. 实验过程
1.数据处理
实验语料为三个类型的文档。分别是:从百度新闻搜集的奥运会报道10篇,从延边大学研究生院官网搜集的研究生通知10篇,从微信公众号搜集的机器学习类文章30篇。
主要思路:
1.加载实验数据:(3个类别50篇文章)
2.分词,去停用词:(载入哈工大停用词表,如果文中词语在停用词表则不存储)
3.按照类别的不同,三种文本标签分别标注为0,1,2
4.返回值:分词后的50篇文章,50个类别标签
# TODO: 初始化LinearSVC模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,使用模型的默认参数。
clf = LinearSVC()
svm = CalibratedClassifierCV(clf)
# 文本处理 --> 生成训练集 测试集 词频集
def text_processor(text_path, test_size=0.2):
folder_list = os.listdir(text_path)
data_list = [] # 每个元素均为一篇文章
class_list = [] # 对应于每篇文章的类别
# 一个循环读取一个类别的文件夹
for folder in folder_list:
new_folder_path = os.path.join(text_path, folder) # 类别列表
#files = random.sample(os.listdir(new_folder_path),10)
files = os.listdir(new_folder_path)
# 一个循环读取一篇文章
for file in files:
#print(file)
with open(os.path.join(new_folder_path, file), 'r', encoding='UTF-8') as fp:
raw = fp.read()
word_cut = jieba.cut(raw, cut_all=True) # 精确模式切分文章
word_list = list(word_cut) # 一篇文章一个 word_list
data_list.append(word_list)
if folder == "机器学习":
class_list.append(0)
elif folder == "奥运咨讯":
class_list.append(1)
else :
class_list.append(2)
data_class_list = list(zip(data_list, class_list))
random.shuffle(data_class_list) # 打乱顺序
index = int(len(data_class_list) * test_size) + 1 # 训测比为 8:2
train_list = data_class_list[index:]
test_list = data_class_list[:index]
train_data_list, train_class_list = zip(*train_list) # (word_list_one[],...), (体育,...)
test_data_list, test_class_list = zip(*test_list)
# 统计词频 all_words_dict{"key_word_one":100, "key_word_two":200, ...}
all_words_dict = {}
for word_list in train_data_list:
for word in word_list:
if all_words_dict.get(word) != None:
all_words_dict[word] += 1
else:
all_words_dict[word] = 1
all_words_tuple_list = sorted(all_words_dict.items(), key=lambda f: f[1], reverse=True) # 按值降序排序
all_words_list = list(list(zip(*all_words_tuple_list))[0]) # all_words_list[word_one, word_two, ...]
#print("测试文本真实标签:",test_class_list)
return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list
all_words_list是所有单词的词典,用于统计词频。train_data_list, test_data_list是训练集和测试集词典, train_class_list, test_class_list是训练集和测试集标签。
2.特征选择,词到向量
主要思路:
1.选择训练集中出现的词频进行排序,频率最高的前10个词,作为特征词
2.在训练集和测试集中,判断这些特征词是否出现过,出现过记为1,没出现过记为0
3.将训练集和测试集文档表示为有01组成的长度为10的向量
# 选取特征词
def words_dict(all_words_list, deleteN, stopwords_set=set()):
feature_words = []
n = 1
for t in range(deleteN, len(all_words_list), 1):
if n > 10: # 维度最大10
break
# 非数字 非停用词 长度 1-4 之间
if not all_words_list[t].isdigit() and all_words_list[t] not in stopwords_set and 1 < len(
all_words_list[t]) < 3:
feature_words.append(all_words_list[t])
n += 1
print("机器学习文本特征:",feature_words)
return feature_words
from sklearn.feature_extraction.text import TfidfVectorizer # 导入sklearn库
# 文本特征
def text_features(train_data_list, test_data_list, feature_words):
def text_feature_(text, feature_words):
text_words = set(text)
features = [1 if word in text_words else 0 for word in feature_words]
return features
train_feature_list = [text_feature_(text, feature_words) for text in train_data_list]
test_feature_list = [text_feature_(text, feature_words) for text in test_data_list]
print("测试文档词频向量:",test_feature_list,"\n")
return train_feature_list, test_feature_list
返回值 train_feature_list, test_feature_list是由长度为10的0,1组成的特征向量,每个向量表示一篇文档。
3.svm进行文本分类
def text_classifier(train_feature_list, test_feature_list, train_class_list, test_class_list):
classifier = svm.fit(train_feature_list, train_class_list)
y_pred = classifier.predict(test_feature_list)
y_true = test_class_list
print("测试文本真实标签:", y_true)
print("测试文本预测标签:", y_pred)
C = confusion_matrix(y_true, y_pred)
print("混淆矩阵:\n",C, end='\n')
实验结果
选取10个最高频词作为特征词,根据特征词是否在测试文本中出现,标记为0或1。这样就将所有的文档根据特征词是否出现表示为了特征向量。
测试文档的测试标签全部等于测试文档的真实标签,svm准确度为1.混淆矩阵如图。
这是由于机器学习所选出现的高频特征词专业性较强,与奥运咨询和通知类文本有较大的区分度。因而取得了很好的分类效果。
总结
- 优点:训练3个分类器,个数较少,其分类速度相对较快。
- 缺点:
-1.每个分类器的训练都是将全部的样本作为训练样本,这样在求解二次规划问题时,训练速度会随着训练样本的数量的增加而急剧减慢;
-2.一旦有新的类别加进来时,需要对所有的模型进行重新训练。