什么是NLP?
答:NLP全名:Natural Language Processing (自然语言处理)。
我们为了让大家更好理解,下面引出第一个实例:马蜂窝评论造假事件。
如此庞大的数据量,那么多评论是如何被发现是重复刷出来的呢?用到的就是我们的NLP中的文本相似度分析。
文本相似度分析:就是从海量数据,文章,评论中,把相似的数据挑选出来。
其步骤为:
我们先对这些步骤中的第一步进行分析:如何将这些评论翻译成机器可以看的懂的语言呢?下面又有以下步骤:
首先来看分词:顾名思义,就是将一句话拆分成词语,就像下面这样:
距离川沙公路较近,但是公交指示不对,如果是"蔡陆线"的话,会非常麻烦.建议用别的路线.房间较为简单.
拆分为:
[‘距离’, ‘川沙’, ‘公路’, ‘较近’, ‘,’, ‘但是’, ‘公交’, ‘指示’, ‘不’, ‘对’, ‘,’, ‘如果’, ‘是’, ‘"’, ‘蔡陆线’, ‘"’, ‘的话’, ‘,’, ‘会’, ‘非常’, ‘麻烦’, ‘.’, ‘建议’, ‘用’, ‘别的’, ‘路线’, ‘.’, ‘房间’, ‘较为简单’, ‘.’]
接下来就是制作词袋模型了:可以理解为装着所有词的袋子,就是对分词完的句子的每一个词加上索引(但是顺序是随机的,并不是按照原来句子的顺序添加索引)。
像这样:
[‘距离’, ‘川沙’, ‘公路’, ‘较近’, ‘,’, ‘但是’, ‘公交’, ‘指示’, ‘不’, ‘对’, ‘,’, ‘如果’, ‘是’, ‘"’, ‘蔡陆线’, ‘"’, ‘的话’, ‘,’, ‘会’, ‘非常’, ‘麻烦’, ‘.’, ‘建议’, ‘用’, ‘别的’, ‘路线’, ‘.’, ‘房间’, ‘较为简单’, ‘.’]
转化为:
{’"’: 0, ‘,’: 1, ‘.’: 2, ‘不’: 3, ‘会’: 4, ‘但是’: 5, ‘公交’: 6, ‘公路’: 7, ‘别的’: 8, ‘如果’: 9, ‘对’: 10, ‘川沙’: 11, ‘建议’: 12, ‘房间’: 13, ‘指示’: 14, ‘是’: 15, ‘用’: 16, ‘的话’: 17, ‘蔡陆线’: 18, ‘距离’: 19, ‘路线’: 20}
注意:其中标点符号也要加上索引。
第三步,就是用词袋模型制作语料库,就是把一个句子都用词袋来进行表示,语料库就是把词袋模型中的索引值当作其对应的词的表示,并且与该词在本句中出现的词数的值构成一个元组存储在一个列表中,就像这样:
[‘距离’, ‘川沙’, ‘公路’, ‘较近’, ‘,’, ‘但是’, ‘公交’, ‘指示’, ‘不’, ‘对’, ‘,’, ‘如果’, ‘是’, ‘"’, ‘蔡陆线’, ‘"’, ‘的话’, ‘,’, ‘会’, ‘非常’, ‘麻烦’, ‘.’, ‘建议’, ‘用’, ‘别的’, ‘路线’, ‘.’, ‘房间’, ‘较为简单’, ‘.’]
就会表示为:
[(0, 2), (1, 3), (2, 3), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), (16, 1), (17, 1), (18, 1), (19, 1), (20, 1), (21, 1), (22, 1), (23, 1), (24, 1)]
最后一步:把上面的评论句子变成词向量:就是新建一个列表,里面存放的就是每个词在该句中出现的次数
[(0, 2), (1, 3), (2, 3), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), (16, 1), (17, 1), (18, 1), (19, 1), (20, 1), (21, 1), (22, 1), (23, 1), (24, 1)]
转化为:
[2,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
以上就是分本相似度分析的第一步的所有步骤了。我们接下来来看第二步:使用机器看的懂的算法轮询去比较每一条和所有评论的相似程度(TF-IDF).
我们来看看什么是TF-IDF:
Corpus = [“我喜欢来中国旅游,中国很好玩”,
“这辆车在中国很受欢迎,我的工作就是在中国出售这辆车”,
“我喜欢喝茶和吃苹果”,
“这份工作是在科学杂志上发几篇论文”]
如何用TF-IDF寻找关键词呢?
不考虑停用词(就是没什么意义的词),找出一句话中出现次数最多的单词,来代表这句话,这个就叫做词频(TF – Term Frequency),相应的权重值就会增高
如果一个词在所有句子中都出现过,那么这个词就不能代表某句话,这个就叫做逆文本频率(IDF – Inverse Document Frequency)相应的权重值就会降低
TF-IDF = TF * IDF。
TF公式:
其中 ni,j是该词在一份文件(或评论)中出现的次数,
分母则是一份文件(或评论)中所有词汇出现的次数总和
IDF公式:
分母之所以要加1,是为了避免分母为0
如何做情感分类呢?
要聊到一个东西叫做:分类
分类就是把已知的信息分到准备好的类别中
需要做的准备:分好类的数据集
当我们有了一定量的数据积累之后,最简单的想法就是:新来的数据集和哪个已知的数据相似,我们就认为他属于哪个类别
方法: 逻辑回归,KNN算法
什么是逻辑回归?
逻辑回归:是一种分类算法
只要我们输入计算机能看得懂的数据,计算机就会自动的进行学习与记录,一旦模型建立,当我们再输入新的数据的时候,模型就会自动识别出相应的类型
那么我们要做的关键就在于:把数据转化成算法能读懂的形式,“喂”给算法,然后等着就行了
[0,1 ,1 ,1, 2, 1] -> 0
[0,1 ,1 ,0, 2, 1] -> 0
[0,1 ,1 ,0, 2, 1] -> 0
[0,1 ,0 ,1, 2, 1] -> 1
[0,1 ,0 ,1, 2, 1] -> 1
[0,1 ,1 ,1, 2, 1] -> 1
机器学习到了某种内在规律
(相当于一个公式,去算
分布在每一个可能性里的概率)
[0,1 ,0 ,1, 0, 1] -> ?
使用NLP和逻辑回归对酒店评论做情感分类:
步骤:
1.把句子向量化(就是把句子翻译成计算机看得懂的语言)
2.把数据喂给算法,生成模型
3.用新值去预测类别
代码实现:
from numpy import *
import csv
import jieba
from gensim import corpora
all_doc_list = []
doc_vec = []
count = 0
label_list = []
with open("./ChnSentiCorp_htl_all.csv", 'r', encoding='UTF-8') as f:
reader = csv.reader(f)
for row in reader:
if count == 0:
count += 1
continue
label_list.append(row[0])
comment = list(jieba.cut(row[1], cut_all=False))
# 分词,将10句话进行分词
count += 1
all_doc_list.append(comment)
# 把分完的句子放入一个列表,制作词袋模型
dictionary = corpora.Dictionary(all_doc_list)
corpus = [dictionary.doc2bow(doc) for doc in all_doc_list]
# 对词袋模型的句子进行向量化
for doc in all_doc_list:
doc_test_vec = dictionary.doc2bow(doc)
print("doc_test_vec: ", doc_test_vec)
list = [0 for x in range(len(dictionary.keys()))]
for dic in doc_test_vec:
list[dic[0]] += dic[1]
doc_vec.append(list)
print(doc_test_vec)
# 词袋模型
# 向量化模型
print("doc_vec: ", doc_vec)
for c in doc_vec:
print("c: ", c)
def classify(inX, dataSet, labels, k):
# shape:输出数组的格式
dataSetSize = dataSet.shape[0] # [1,1] 1
# title复制数组
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
print(diffMat)
sqDiffMat = diffMat ** 2
print(sqDiffMat)
# axis表示需要加和的维度
sqDistances = sqDiffMat.sum(axis=1)
print(sqDistances)
distances = sqDistances ** 0.5
print(distances) #打印出距离
# sortedDistIndicies 是一个排好序的index
sortedDistIndicies = distances.argsort()
print(sortedDistIndicies)
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
print(voteIlabel)
# get 是一个字典dict的方法,它的作用是返回key值对应的value值,如果没有的话,返回默认值
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
print(classCount)
sortedClassCount = sorted(classCount.items(), key=lambda d: float(d[1]), reverse=True)
print(sortedClassCount)
return sortedClassCount
if __name__ == '__main__':
group = array(doc_vec)
labels = label_list
result = classify(doc_vec[9], group, labels, 4)
难点总结(分词部分):
假设我们有两句话,分别是
那么,这两句话的字典就是
dictionary: 0:a 1:b 2:c 3:d
其中key值表示索引,value表示对应的词语;
而且,词语不会重复
通过应用生成好的字典,我们可以重写两句话
然后把这两句话改成列表(list)类型,就变成以下格式
[[{0:1}, {1:1}, {2:1}, {3:0}],
[{0:0}, {1:1}, {2:1}, {3:1}]]
把list中的字典转换成元组,这就是我们在代码里得到的语料库
[[(0,1), (1,1), (2:1), (3:0)],
[(0:0), (1:1), (2:1), (3:1)]]
语料库的两种表现形式:
1.第一种: String类型
[“a b c”,
“b c d”]
2.第二种,词袋类型
[[(0,1), (1,1), (2,1), (3,0)],
[(0,0), (1,1), (2,1), (3,1)]]
如果新得到一组数据,可以把它用两种形式加入到语料库中