本文主要讲述使用NB和SVM算法来实现NLP的小例子,当然目前使用neural network等深度学习的算法会比较多。本文文件集: https://www.kaggle.com/hellogxp/corpus#corpus.csv
1. 类库
import pandas as pd
import numpy as np
from nltk.tokenize import word_tokenize
from nltk import pos_tag
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.preprocessing import LabelEncoder
from collections import defaultdict
from nltk.corpus import wordnet as wn
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import model_selection, naive_bayes, svm
from sklearn.metrics import accuracy_score
2. 设置随机种子,保证每次运行结果相同
np.random.seed(500)
3. Add the Corpus 添加语料库
Corpus = pd.read_csv(r"../input/corpus.csv",encoding='latin-1', nrows=5)
4. Data pre-processing 数据预处理
主要包括Tokenization和Word Stemming/Lemmatization,Tokenization可以叫令牌化,把字符串拆分成单词,标点符号,短语等元素,称之为tokens.
Word Stemming和Lemmatization,两者差不多,但是词干stemmer操作一个单词,是不知道其上下文的,所以就不能区分不同含义的词,但是它实现简单切比较快,有的应用就效率换质量。
预处理的主要步骤如下:
1. 除去空行
2. 字母改小写
3. 单词令牌化
4. 删除stop words, 主要是针对英文,也叫common words,比如a,the,or等使用频率很多的字或词
5. 除去字符不全是字母的单词
6. Word Lemmatization 将单词的不同形式简化为一种形式的过程,例如,”builds”, “building”, or “built” to the lemma “build”
#删除空白行
Corpus['text'].dropna(inplace=True)
#全部小写
for index, row in Corpus.iterrows():
Corpus.loc[index]['text'] = Corpus.loc[index]['text'].lower()
# Step - b : 全部小写
for label, row in Corpus.iterrows():
Corpus.loc[[label], ['text']] = Corpus.loc[label]['text'].lower()
# Step - c : 令牌化操作,会将一个字符串拆分成单个单词的集合,包括标点符号
Corpus['text']= [word_tokenize(entry) for entry in Corpus['text']]
# Step - d : 删除停止符号, 非数值,对单词进行Stemming/Lemmenting,也就是词干和词法化
# WordNetLemmatizer 需要 Pos tags来了解单词是名词,动词还是其它,默认是名词
tag_map = defaultdict(lambda : wn.NOUN)
tag_map['J'] = wn.ADJ
tag_map['V'] = wn.VERB
tag_map['R'] = wn.ADV
for index,entry in enumerate(Corpus['text']):
# 声明一个数组来存储最终处理过的单词
Final_words = []
# 初始化 WordNetLemmatizer()
word_Lemmatized = WordNetLemmatizer()
# pos_tag 函数将给每个单词打一个'tag',比如说单词是Noun(N)或者Verb(V)抑或其他
for word, tag in pos_tag(entry):
# 检查是否是Stop words或者全是字符的字符
if word not in stopwords.words('english') and word.isalpha():
word_Final = word_Lemmatized.lemmatize(word,tag_map[tag[0]])
Final_words.append(word_Final)
# 在DF种在新加一列text_final来存储最终处理好的字符串
Corpus.loc[index,'text_final'] = str(Final_words)
5. 准备训练集和测试集
我们会将词库分成训练集和测试集两部分,训练集是为了拟合模型,预测将在测试集上进行,我们可以使用sklearn库的train_test_spli函数来实现词库的拆分,训练集将占70%,测试集将占据30%,也就是说我们将test_size参数设置为0.3
6. Encoding
主要是将目标变量标签编码,将字符串类型的类别数据转换成数字类型,以使得模型可以理解
7. 词向量化
这一步将文本文档集合转化为数字特征向量,有很多种方法可供选择比如TF-IDF,是一种用于信息检索与数据挖掘的常用加权技术,常用于挖掘文章中的关键词,而且算法简单高效,常被工业用于最开始的文本数据清洗。
假设我们现在有一片长文叫做《量化系统架构设计》词频高在文章中往往是停用词,“的”,“是”,“了”等,这些在文档中最常见但对结果毫无帮助、需要过滤掉的词,用TF可以统计到这些停用词并把它们过滤。当高频词过滤后就只需考虑剩下的有实际意义的词。
但这样又会遇到了另一个问题,我们可能发现”量化”、”系统”、”架构”这三个词的出现次数一样多。这是不是意味着,作为关键词,它们的重要性是一样的?事实上系统应该在其他文章比较常见,所以在关键词排序上,“量化”和“架构”应该排在“系统”前面,这个时候就需要IDF,IDF会给常见的词较小的权重,它的大小与一个词的常见程度成反比。
当有TF(词频)和IDF(逆文档频率)后,将这两个词相乘,就能得到一个词的TF-IDF的值。某个词在文章中的TF-IDF越大,那么一般而言这个词在这篇文章的重要性会越高,所以通过计算文章中各个词的TF-IDF,由大到小排序,排在最前面的几个词,就是该文章的关键词。
Tfidf_vect = TfidfVectorizer(max_features=5000)
Tfidf_vect.fit(Corpus['text_final'])
Train_X_Tfidf = Tfidf_vect.transform(Train_X)
Test_X_Tfidf = Tfidf_vect.transform(Test_X)
可以通过
print(Tfidf_vect.vocabulary_)
来打印,有类似的输出
{'stun': 141, 'even': 39, 'sound': 134, 'track': 153, 'beautiful': 9, 'paint': 102, 'senery': 129, 'mind': 91, 'well': 164......}
也可通过
print(Train_X_Tfidf)
直接打印向量数据
(0, 175) 0.11054398869597175
(0, 163) 0.1783723880767145
(0, 160) 0.11054398869597175
(0, 158) 0.11054398869597175
以第一行为例
0是‘Train_X_Tfidf’的行号,175是第一行中单词的唯一的整数值,后面的小数值是TF-IDF Vectorizer计算的分数。
现在数据处理好了,可以输入到不同的算法种了
7. 使用机器学习算法预测输出
首先我们使用朴素贝叶斯算法
# 使得训练集合适合NB classifier
Naive = naive_bayes.MultinomialNB()
Naive.fit(Train_X_Tfidf,Train_Y)
# 预测测试数据集的标签
predictions_NB = Naive.predict(Test_X_Tfidf)
# 使用accuracy_score函数获得准确度
print("Naive Bayes Accuracy Score -> ",accuracy_score(predictions_NB, Test_Y)*100)
输出
Naive Bayes Accuracy Score -> 83.1%
我们还可以使用SVM,也就是支持向量机
# 使训练数据集适合分类器
SVM = svm.SVC(C=1.0, kernel='linear', degree=3, gamma='auto')
SVM.fit(Train_X_Tfidf,Train_Y)
# 预测验证数据集上的标签
predictions_SVM = SVM.predict(Test_X_Tfidf)
# 使用accuracy_score函数获得准确性
print("SVM Accuracy Score -> ",accuracy_score(predictions_SVM, Test_Y)*100)
输出
SVM Accuracy Score -> 84.7%