纯因兴趣!!不主要学习这个哈!就学的很浅!!
主要途径:【莫烦Python】机器要说话 NLP 自然语言处理教程
感想:我觉得莫烦讲的超级好!主要经常通过一些具体事例和一些生动的动画把抽象的东西变得非常好理解!
可以自己学习的主页:莫烦自然语言处理学习(代码和学习的文本都在这!超棒!)
1.NLP可以干啥呢?
①对文本进行语义分析(分析文本的情感啊之类的 比如搜索引擎可以更加快速的找到你想要的东西
②对文本进行纠错
③挖掘商品的卖点 。。更好捕捉消费者的喜好。促进国家GDP发展哈~
④对文本进行分类
⑤文本续写,多轮对话等等(什么?以后小说都不用人写了哈哈哈哈哈哈
当然还有更多的应用。。发现的 没发现的 还有无限未来 = =
2.搜索引擎是咋工作的?
如果直接用深度学习的算法的话,其实效率很低的啦,因为数据实在是太多啦,所以搜索引擎分成了三层算法。
①最底层:批量召回。采用倒序索引算法。计算机将每个材料内容都通读一遍以后提取出重要的内容,比如时间 标题 正文等按照一定权重存取下来 将其存成索引,使得搜索的时候只需要查询索引就可以了。当某个材料有所改变的时候,我们的搜索引擎的小蜘蛛就开始工作,将更改的信息爬取回来。
②中层:粗排。最有名的的是词的相似度的筛选——TF-IDF算法。分成两部分,TF是词频,按照一定公式计算词在本文中的频率,但有时候光看频率是不够的,比如啊 哦 这些词在每一篇文章中可能出现的都很多,于是需要结合IDF算法,即逆文本频率指数,用各种公式计算每个词在所有文章中的(逆频率?)(就是一个词在所有文章中用的越多,计算出来的结果越小) TF-IDF就是将TF 与 IDF 相乘,由此得到每个词对每篇文章的重要程度。你在搜索一个句子的时候,计算这个句子与每篇文章的cosine距离。代码如下。参考TF-IDF莫烦代码 加上一些自己的理解
import numpy as np
from collections import Counter
import itertools
docs = [
"it is a good day, I like to stay here",
"I am happy to be here",
"I am bob",
"it is sunny today",
"I have a party today",
"it is a dog and that is a cat",
"there are dog and cat on the tree",
"I study hard this morning",
"today is a good day",
"tomorrow will be a good day",
"I like coffee, I like book and I like apple",
"I do not like it",
"I am kitty, I like bob",
"I do not care who like bob, but I like kitty",
"It is coffee time, bring your cup"
]
#说实话我没有很懂这个safe_log的话 就是看得懂代码但是为啥要在x[1]才计算log??
def safe_log(x):
mask = x != 0
x[mask] = np.log(x[mask])
return x
#tf计算的四种公式
tf_methods = {
"log": lambda x: np.log(1+x),
"augmented": lambda x: 0.5 + 0.5 * x / np.max(x, axis=1, keepdims=True),
"boolean": lambda x: np.minimum(x, 1),
"log_avg": lambda x: (1 + safe_log(x)) / (1 + safe_log(np.mean(x, axis=1, keepdims=True)))
}
#idf计算的三种公式
idf_methods = {
"log": lambda x: 1 + np.log(len(docs) / (x + 1)),
"prob": lambda x: np.maximum(0, np.log((len(docs) - x) / (x + 1))),
"len_norm": lambda x: x / (np.sum(np.square(x))+1),
}
# 将文档中的词语全部取出来, 按照每个文档来存取,犹如下面一样的列表
# >>> [['it', 'is', 'a', 'good', 'day', 'I', 'like', 'to', 'stay', 'here'], ['I', 'am', 'happy', 'to', 'be', 'here']...
doc_words = [d.replace(",", "").split(" ") for d in docs]
# 列表中的词语去重=>集合
# >>> {'a', 'are', 'study', 'morning', 'day', 'do', 'good', 'like', 'today', 'will', 'not'...
vocab = set(itertools.chain(*doc_words))
# 将每个词进行编号 存成两种字典,一种是编号索引词i2v / 一种是词索引编号v2i
v2i = {v : i for i, v in enumerate(vocab)}
i2v = {i : v for v, i in v2i.items()}
# print(doc_words)
# print(vocab)
# print(v2i)
# print(i2v)
# 获得tf值的函数 _tf[i, j]代表i2v中编号为i的词在第j个文档中 计算 => 它出现的次数 / 该文档中出现次数最多的词的次数
# 然后采用上面的公式 最传统的方法是log 计算每个词在每个文档中出现的相对频率的多少
def get_tf(method="log"):
_tf = np.zeros((len(vocab), len(docs)), dtype=np.float64)
for i, d in enumerate(doc_words):
counter = Counter(d)
for v in counter.keys():
_tf[v2i[v], i] = counter[v] / counter.most_common(1)[0][1]
weighted_tf = tf_methods.get(method, None)
return weighted_tf(_tf)
# 获取idf的函数 df[i,0]存取在i2v中编号为i的在所有文档中出现的次数
# 最传统的idf计算公式 log(文档数 / 每个词出现的个数 + 1)
def get_idf(method = "log"):
df = np.zeros((len(i2v), 1))
for i in range(len(i2v)):
d_count = 0
for d in doc_words:
d_count += 1 if i2v[i] in d else 0
df[i, 0] = d_count
idf_fn = idf_methods.get(method, None)
return idf_fn(df)
在会计算tf-idf后我们就可以把搜索问题向量化,然后在将这个向量与文档向量计算cosine距离,选取出距离最近的几个文档。可能有些抽象哈!还是看代码!代码依然参考TF-IDF莫烦代码
中间补充一个小知识:cosine simliarity 即 余弦相似度 公式如下
#计算文档向量跟问题tf_idf向量的余弦相似度
def cosine_similarity(q, _tf_idf):
#q代表问题向量 _tf_idf代表文档向量tf-idf矩阵
unit_q = q / np.sqrt(np.sum(np.square(q), axis=0, keepdims=True))
unit_ds = _tf_idf / np.sqrt(np.sum(np.square(_tf_idf), axis=0, keepdims=True))
#其实不是很懂最后raval()这个数组扁平化的意义
similarity = unit_ds.T.dot(unit_q).ravel()
return similarity
#计算文档向量
def docs_score(q, len_norm=False):
q_words = q.replace(",", "").split(" ")
#加入搜索向量中没有的词
unknown_words = 0
for v in set(q_words):
if v not in v2i:
v2i[v] = len(v2i)
i2v[len(i2v) - 1] = v
unknown_words += 1
if unknown_words > 0:
_idf = np.concatenate((idf, np.zeros((unknown_words ,1), dtype=np.float)), axis=0)
_tf_idf = np.concatenate((tf_idf, np.zeros((unknown_words, tf_idf.shape[1]), dtype=np.float)), axis=0)
else:
_idf = idf
_tf_idf = tf_idf
counter = Counter(q_words)
q_tf = np.zeros((len(_idf), 1), dtype=np.float)
for v in counter.keys():
q_tf[v2i[v], 0] = counter[v]
q_vec = q_tf * _idf
q_scores = cosine_similarity(q_vec, _tf_idf)
if len_norm:
len_docs = [len(d) for d in doc_words]
q_scores = q_scores / np.array(len_docs)
return q_scores
啊啊啊啊啊其实今天看起来 我不懂为什么q_vec要这么算!!q_tf为什么就说问题词语中每个出现的词的个数了呢!!还是我在钻牛角尖??
# 忘了还有一个函数 获得整个文档的关键词
# n表示获取的关键词数
def get_keywords(n=2):
#3表示三个文档
for c in range(3):
col = tf_idf[:, c]
#获取相似度最大的n个词的下标
idx = np.argsort(col)[-n:]
print("doc{},top{} keywords{}".format(c, n, [i2v[i] for i in idx]))
然后计算一下文档们的tf-idf矩阵
# 计算tf-idf矩阵 n表示所有文档一共有n个词 t表示文档数
# idf返回的维度是 n * 1,tf返回的维度是 t * n
tf = get_tf()
idf = get_idf()
tf_idf = tf * idf
然后我们来测试一下!!!
get_keywords()
q = "I get a coffee cup"
#算一下问题跟各个文档的相似度分数
scores = docs_score(q)
#选出最匹配的三个文档 并存取她们的id
d_ids = scores.argsort()[-3:][::-1]
print("\ntop 3 docs for '{}':\n{}".format(q, [docs[i] for i in d_ids]))
莫名觉得好有趣!!于是我拿自己的文档跟问题试了一下!!!
#输出
>>> doc0,top2 keywords['common', "Let's"]
>>> doc1,top2 keywords['happy', 'today']
>>> doc2,top2 keywords['Lu', 'baby']
>>> top 3 docs for 'Do you like mayday':
>>> ['Everyday is mayday', 'I like coffee, I like ice-cream', 'You are so stupid, aren't you']
虽然问的问题根本没有对上回答 因为我文档里没写回答!!但还是好有趣!!
哦哦对了!!计算TF-IDF其实可以直接调库!!但是算法还是要学的!!
以下补充直接用sklearn库里的tf-idf
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
docs = [
"it is a common day, Let's listen to mayday's song",
"I am happy today",
"I like ChenRan Lu though he is a fat baby",
"I like to stay the same every day",
"The tacky dog is cute",
"There is a idiot here can you see her",
"I love my family although they are noisy",
"My fisrt computer game I played is Paopaotang, I miss it very much",
"Everyday is mayday",
"tomorrow will also be a good day",
"I like coffee, I like ice-cream",
"I am ashamed to express some emotions",
"We can go very slowly, but we will arrive to our destionation one day",
"I will always stay here",
"You are so stupid, aren't you"
]
q = "Do you want to listen to music"
vector = TfidfVectorizer()
tf_idf = vector.fit_transform(docs)
qtf_idf = vector.transform([q])
res = cosine_similarity(tf_idf, qtf_idf)
res = res.ravel().argsort()[-3:][::-1]
print("top 3 for {}:\n{}".format(q, [docs[i] for i in res]))
输出就不看啦!!