1.搜索引擎的原理----TF-IDF
网页变成索引,存到搜索引擎的数据库里,等待被搜索
多模态搜索: 用文字搜索视频,用图片搜索视频,用图片搜索文字,等等
将图片,视频转化为数字,与其他转化为数字的视频,文字,视频进行匹配
BigData --> 批量召回 --> 粗排 --> 精排
层层筛选过滤,使用时间消耗较少的方法
将深度学习放在最后精排,使其时间消耗更短
TF-IDF: TF词频(Term Frequency) IDF逆文本频率指数(Inverse Document Frequency)
词频,就是词在文章中出现的频率,次数。 文章信息的局部信息
逆文本频率指数,指一个词在文本中的区分力大小,避免了常用词,如你我他词频太高带来的影响。 系统的全局信息
一般用TF * IDF来表示文章,表示文章的关键内容
使用IDF时,可以在专一的某一个领域下训练出一个特定的IDF值,比范领域下的IDF精确度要好。
把文章或者视频,语句转化为向量,用向量的相似性来匹配最相似的文章,cos距离计算。
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
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 cups",
]
vectorizer = TfidfVectorizer()
# 直接调用TfidfVectorizer的fit_transformer方法就可以得到tf-idf值了
tf_idf = vectorizer.fit_transform(docs)
print("idf: ",[(n,idf) for idf,n in zip(vectorizer.idf_,vectorizer.get_feature_names())])
计算出来idf如下所示:

idf也可以单独提取出来,用去其他的操作和使用,如果有相同类型的文章集合也可以不用再去训练idf了
然后打印出每个单词对应的索引print("v2i:",vectorizer.vocabulary_)

那如果再来一个文本,就可以通过它的tf-idf向量与文本库里面的向量进行比对,找出最适合的向量
qtf_idf = vectorizer.transform([q])
res = cosine_similarity(tf_idf,qtf_idf)
把匹配结果按照分数高低进行排序
res = res.ravel().argsort()[-3:] # 只取最匹配的前三名
print("\ntop 3 docs for '{}':\n{}".format(q,[docs[i] for i in res[::-1]]))


tf-idf匹配流程:
1.实例化TfidfVectorizer()对象
2.输入若干条文本,transform成tf-idf向量
3.用cosin距离进行计算最匹配的文本
可以看到这里每个文本都变成了一个44维的向量


为什么都是44维呢,因为每个词有一个tf,有一个idf,那这总共的文本就一共有44维向量
BERT 注意力机制
集群版搜索引擎 ElasticSearch
搜索引擎流程:
Query --> 分词、敏感词过滤、纠错、拼音识别、查询改写、查询补全…–>ElasticSearch、热度召回、地理信息召回、…–>搜索结果
2.词向量训练方法----CBOW,skip-gram
深度学习的技术CBOW,非深度学习的技术TF-IDF,一个精度更高,一个更快。
中性词:区分力不大的词,“在”,“是”… 这些
One-hot represention 将词汇用二进制向量表示,这个向量表示的词汇,仅仅在词汇表中的索引位置处为1,其他地方都为0。

这样的缺点其实是很多的,所以有一种embedding的方法:

Word Embedding得到的向量维度远小于词汇表的个数,通过词向量之间的距离可以度量他们之间的关系。
训练词向量
非监督学习,取一小段文本,计算词向量,用整个向量预测最中间的那个词,依次类推,计算机就能搞清楚前后文关系,距离越近的词,关系越亲密。
如
输入[‘我’][‘中国’]
输出[‘爱’]
同样也可以用中间词预测前后文
CBOW(Continuous Bag of Words)
tf-idf算法是通过一种统计学的方式来用文章中的词的重要程度,转化成向量来表示一篇文章的。速度较快,但是准确率不如深度学习的方法
CBOW就是挑一个要预测的词,来学习这个词前后文中词语和预测词的关系,那每个词都可以在一个空间中表示出来,可以通过空间位置知道词语之间的对应关系,理论上,语义越相近的词语将会距离更近
corpus = [
# numbers
"5 2 4 8 6 2 3 6 4",
"4 8 5 6 9 5 5 6",
"1 1 5 2 3 3 8",
"3 6 9 6 8 7 4 6 3",
"8 9 9 6 1 4 3 4",
"1 0 2 0 2 1 3 3 3 3 3",
"9 3 3 0 1 4 7 8",
"9 9 8 5 6 7 1 2 3 0 1 0",
# alphabets, expecting that 9 is close to letters
"a t g q e h 9 u f",
"e q y u o i p s",
"q o 9 p l k j o k k o p",
"h g y i u t t a e q",
"i k d q r e 9 e a d",
"o p d g 9 s a f g a",
"i u y g h k l a s w",
"o l u y a o g f s",
"o p i u y g d a s j d l",
"u k i l o 9 l j s",
"y g i s h k j l f r f",
"i o h n 9 9 d 9 f a 9",
]
例如这里又字母也有数字,假设他们都是单词,那根据前后文关系,其实应该是学到字母们在向量空间上的位置更相近,而数字的位置更相近,对于数字9这个与字母也前后文关系密切,与数字也前后文关系密切的,应该空间上离两者都很近
构造模型的训练集,这里是将一句话中滑动移动5个单词的窗口,以前后两个,共四个单词作为训练数据的特征,中间那个词作为训练数据的标签
# 3.定义产生训练数据的方法
class Dataset:
def __init__(self, x, y, v2i, i2v):
self.x, self.y = x, y
self.v2i, self.i2v = v2i, i2v
self.vocab = v2i.keys()
def sample(self, n):
b_idx = np.random.randint(0, len(self.x), n) # 产生随机数
bx, by = self.x[b_idx], self.y[b_idx] # 使顺序打散训练,这样每一次调用,都会产生shuffle的数据
return bx, by
@property
def num_word(self):
return len(self.v2i)
def process_w2v_data(corpus, skip_window=2, method="skip_gram"):
all_words = [sentence.split(" ") for sentence in corpus]
all_words = np.array(list(itertools.chain(*all_words))) # 连成一条
# vocab sort by decreasing frequency for the negative sampling below (nce_loss).
vocab, v_count = np.unique(all_words, return_counts=True) # 统计有多少种不同的词,以及个数
vocab = vocab[np.argsort(v_count)[::-1]] # 按照个数从多到少排序
print("all vocabularies sorted from more frequent to less frequent:\n", vocab)
v2i = {
v: i for i, v in enumerate(vocab)} # 单词即对应的索引,从大到小拍多少号
i2v = {
i: v for v, i in v2i.items()} # 从索引找到单词
# pair data
pairs = []
js = [i for i in range(-skip_window, skip_window + 1) if i != 0]
# -2到2一共五个单词,去掉最中间的,窗口大小为5
for c in corpus:
words = c.split(" ")
w_idx = [v2i[w] for w in words] # 把每一行文本的单词都换成索引放在列表里
if method == "skip_gram":
for i in range(len(w_idx)):
for j in js:
if i + j < 0 or i + j >= len(w_idx):
continue
pairs.append((w_idx[i], w_idx[i + j])) # (center, context) or (feature, target)
elif method.lower() == "cbow":
for i in range(skip_window, len(w_idx) - skip_window): # 在这一行列表上开始滑动窗口,每一次华东都包含5个单词
context = [] # 装每个窗口的五个单词的索引,context里面装的是前后共四个
for j in js:
context.append(w_idx[i + j])
pairs.append(context + [w_idx[i]]) # (contexts, center) or (feature, target)
else:
raise ValueError
pairs = np.array(pairs)
print("5 example pairs:\n", pairs[:5])
if method.lower() == "skip_gram":
x, y = pairs[:, 0], pairs[:, 1]
elif method.lower() == "cbow":
x, y = pairs[:, :-1], pairs[:, -1]
else:
raise ValueError
return Dataset(x, y, v2i, i2v)
首先是把所有的单词进行一个词频的统计以及排序,为他们安排一个索引

所有的单词排序从出现词频最多的到最低的,同时每个词具有了一个索引,把上述的整段文本,用索引来转化

然后对每一句话开始以窗口为5划窗,中间的摘出来作为标签,那么特征就是:
[16, 14, 12, 3]
[14, 9, 3, 14]
[9, 12, 14, 1]
[12, 3, 1, 3]
[3, 14, 3, 9]
[9, 12, 3, 0]
[12, 16, 0, 16]
[16, 3, 16, 16]
[3, 0, 16, 3]
[5, 5, 14, 1]
[5, 16, 1, 1]
[16, 14, 1, 12]
[1, 3, 3, 12]
[3, 0, 12, 25]
[0, 3, 25, 9]
[3, 12, 9, 3]
[12, 25, 3, 1]
[12, 0, 3, 5]
[0, 0, 5, 9]
[0, 3, 9, 1]
[3, 5, 1, 9]
[5, 23, 23, 14]
[23, 14, 14, 5]
[14, 23, 5, 1]
[23, 14, 1, 1]
[14, 5, 1, 1]
[5, 1, 1, 1]
[1, 1, 1, 1]
[0, 1, 23, 5]
[1, 1, 5, 9]
[1, 23, 9, 25]
[23, 5, 25, 12]

本文深入探讨了搜索引擎的工作原理,重点介绍了TF-IDF算法如何将文本转化为向量表示。同时,讲解了词向量训练方法CBOW和Skip-Gram,它们利用上下文关系学习词的向量表示,以提高精度。通过实例展示了如何使用Python实现这些技术,并讨论了它们在速度和准确性上的权衡。

3076

被折叠的 条评论
为什么被折叠?



