阿里灵杰_Task01_环境配置与实践数据下载

0x00 Abstract

  • 任务内容:
    • 从比赛官网下载数据集,并使用 Python 读取数据
    • 使用 jieba 对文本进行分词
    • 使用 TFIDF 对文本进行编码
    • 思考如何使用 TFIDF 计算文本相似度?
  • 学习资料: https://coggle.club/blog/tianchi-open-search

0x01 读取数据

这里只用 train.query.txt 中的前十条数据。同整个数据集的数据处理同理。

首先导入需要用到的包:

import pandas as pd 
import jieba  # 分词
from gensim import corpora, models, similarities  # TF-IDF

读取数据:

with open('data/train.query.txt', encoding="utf-8") as f:
    train_querys = f.readlines()

train_query = {}
for line in train_querys:
    line = line.strip().split('\t')
    query_id = line[0]
    query = line[1]
    train_query[int(query_id)] = query

取字典 train_query 的前十条数据:

# 字典切片
def dict_slice(adict, start, end):
    keys = adict.keys()
    dict_slice = {}
    for k in list(keys)[start:end]:
        dict_slice[k] = adict[k]
    return dict_slice

wordListTop10 = dict_slice (train_query, 0, 10)
wordListTop10

{1: '美赞臣亲舒一段', 2: '慱朗手动料理机', 3: '電力貓', 4: '掏夹缝工具', 5: '飞推 vip', 6: '多功能托地把', 7: '充气浮力袖', 8: '盒马花胶鸡汤锅', 9: '塞塞乐', 10: '广汽传祺 gs5 挡风遮雨条子'}

0x02 使用 jieba 对文本进行分词

使用 jieba 中的搜索引擎模式对文本分词。关于 jieba 的更多信息可以参考 GitHub - fxsjy/jieba: 结巴中文分词

有三种分词模式,这里使用默认的精确模式。

seg_list = []
for i in range(1,11):
    seg = list(jieba.cut(wordListTop10[i],HMM=True))
    seg_list.append(seg)  # 把前10个数据的所有分词放进一个列表中
seg_list

[['美赞臣', '亲舒', '一段'], ['慱', '朗', '手动', '料理', '机'], ['電力貓'], ['掏', '夹缝', '工具'], ['飞', '推', 'vip'], ['多功能', '托地', '把'], ['充气', '浮力', '袖'], ['盒马花胶', '鸡汤', '锅'], ['塞塞', '乐'], ['广汽传祺', 'gs5', '挡风遮雨', '条子']]

0x03 使用 TF-IDF 对文本进行编码

什么是 TF-IDF 检索

可以查看 矢量语义与嵌入之 TF-IDF 检索 进行学习。

使用 TF-IDF 对我们的数据集编码

models.tfidfmodel – TF-IDF model — gensim

# 制作字典
dictionary = corpora.Dictionary(seg_list)

# 可以通过 token2id 得到特征数字
print(dictionary.token2id)

{'一段': 0, '亲舒': 1, '美赞臣': 2, '慱': 3, '手动': 4, '料理': 5, '朗': 6, '机': 7, '電力貓': 8, '夹缝': 9, '工具': 10, '掏': 11, 'vip': 12, '推': 13, '飞': 14, '多功能': 15, '托地': 16, '把': 17, '充气': 18, '浮力': 19, '袖': 20, '盒马花胶': 21, '锅': 22, '鸡汤': 23, '乐': 24, '塞塞': 25, 'gs5': 26, '广汽传祺': 27, '挡风遮雨': 28, '条子': 29}

将所有的词存入一个字典,上面打印出了每个词对应的 id。所以上面这一步其实就是将词语都映射为数字,因为机器只能理解数字呀。

然后首先将这十条数据放入词袋模型,之后再对词袋模型中的数据使用 TF-IDF 计算权值,得到 TF-IDF 编码。

# Convert corpus to BoW format
# 制作数字向量类型的语料库(doc2bow)
# ----> 将字符串转换成数字向量类型的词袋模型(稀疏向量)
# 源文件不做处理是一个字符串类型的语料库
corpus = [dictionary.doc2bow (doc) for doc in seg_list]  
corpus

[[(0,1), (1,1), (2,1)], [(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), (25,1)], [(26,1), (27,1), (28,1), (29,1)]]

这里是将十条数据转为词袋模型,下面贴出之前这十条数据的分词结果:

[['美赞臣', '亲舒', '一段'], ['慱', '朗', '手动', '料理', '机'], ['電力貓'], ['掏', '夹缝', '工具'], ['飞', '推', 'vip'], ['多功能', '托地', '把'], ['充气', '浮力', '袖'], ['盒马花胶', '鸡汤', '锅'], ['塞塞', '乐'], ['广汽传祺', 'gs5', '挡风遮雨', '条子']]

以第一条数据为例: 第一条数据的词袋模型:[(0,1), (1,1), (2,1)] 第一条数据的分词结果:['美赞臣', '亲舒', '一段'] 第一条数据的 token2id'一段': 0, '亲舒': 1, '美赞臣': 2 词袋中第一个词 (0,1) 对应着:“一段”(编码为 0),数据中出现一次,所以 (0,1)。第一个数字代表哪一个词,第二个数字代表出现了几次(词频)。后面的两个词同理。三个词放一起,组成词袋,来代表整个第一条数据。

可以发现,不存在的词是不放入每条数据的词袋的,通过这样的方式来节约内存。这种技术叫稀疏矩阵(Sparse Matrix):只存储有内容的值,而忽略无内容的值。

最后得到 TF-IDF 编码(以 corpus 中第一条数据为例 ):

tfidf = models.TfidfModel(corpus)  # fit model
vector = tfidf[corpus[0]]  # apply model to the first corpus document
vector

[(0, 0.5773502691896257), (1, 0.5773502691896257), (2, 0.5773502691896257)]

你也可以自己动手,看看后面的几条数据编码是什么样子的。

0x04 使用 TF-IDF 计算文本相似度

def semblance(text, corpus):
    # 对测试文本分词
    dic_text_list = list(jieba.cut(text))
 
    # 制作测试文本的词袋
    doc_text_vec = dictionary.doc2bow(dic_text_list)
 
    # 获取语料库每个文档中每个词的tfidf值,即用tfidf模型训练语料库
    tfidf = models.TfidfModel(corpus)
 
    # 对稀疏向量建立索引
    index = similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=len(dictionary.keys()))
    sim = index[tfidf[doc_text_vec]]  # 相当于sim = index.get_similarities(tfidf[doc_text_vec])
    print("相似度评估:")
    print(sim)
    # 按照相似度来排序
    sim_sorted = sorted(enumerate(sim, 1), key=lambda x: -x[1])  # enumerate(x, 1) 代表从1开始设立索引
    # 相当于sorted(enumerate(sim), key=lambda x: x[1], reverse=True
    print("相似度排序:")
    print(sim_sorted)
text = '想喝鸡汤'
semblance (text, corpus)

Output:

相似度评估:
[0.         0.         0.         0.         0.         0.
 0.         0.81649655 0.         0.        ]
10
相似度排序:
[(8, 0.81649655), (1, 0.0), (2, 0.0), (3, 0.0), (4, 0.0), (5, 0.0), (6, 0.0), (7, 0.0), (9, 0.0), (10, 0.0)]

Conclusion

没有做过 NLP 的东西,趁着做今天的任务大概了解了分词,文本向量化表示之类的内容。

References

jieba 分词: GitHub - fxsjy/jieba: 结巴中文分词 Chinese Word Segmentation (jieba) — Python Notes for Linguistics 中文分词工具 jieba 的简介|自然语言处理 jieba 分词-强大的 Python 中文分词库

Gensim: https://gensim.apachecn.org/#/blog/tutorial/README

TF-IDF: 自然语言处理(NLP)之使用 TF-IDF 模型计算文本相似度 你天天用的搜索引擎是怎么工作的 - 自然语言处理 | 莫烦 Python 统计学让搜索速度起飞 - 自然语言处理 | 莫烦 Python