【LLM】第二章:文本表示:词袋模型、小案例:基于文本的推荐系统(酒店推荐)
【LLM】第二章文本表示词袋模型、小案例基于文本的推荐系统(酒店推荐)一、文本表示上一个章节我们讲了如何分词分完词下一步就是如何把这些词(tokens)转化为计算机可以读懂的词向量这个步骤也叫文本表示。看过我其他系列文章的同学对文本表示不会陌生其实很多地方一直在反反复复讨论这个话题及相关算法比如在图神经网络专栏中的https://blog.csdn.net/friday1203/article/details/146009277https://blog.csdn.net/friday1203/article/details/146187876https://blog.csdn.net/friday1203/article/details/146572210还有NLP专栏中的embedding层、transformer的编码器等等这些都是用来做文本特征的也就是进行文本表示或者说是生成词向量的。本章节可以看作是对前面知识点的查漏补缺本篇讲词袋模型。最后补充一句为什么会有这么多眼花缭乱的文本表示方法(算法)呢自然是适用场景不一样喽不同任务、不同语料、不同场景都需要其对应的文本表示方法比如有的任务是需要对词进行向量化有的是对句子向量化有的是对文档向量化因此需要对应的文本表示方法而且这些方法从思路到解决方案都是大不相同的所以我们也有必要都了解一下。本篇的词袋模型适用于将整段文本编码成一个向量的需求其思路也是极其精妙的是前人的智慧结晶。二、提取文本特征sklearn.feature_extraction模块详解在NLP领域文本表示的最简单、最直观方法就是用词袋来表示。Bag of words(词袋)统计每个词在文档中出现的次数。sklearn.feature_extraction是scikit-learn库中用于特征提取的模块它包含了各种用于从文本和图像数据中提取特征的工具。其中文本特征提取有CountVectorizer、TfidfVectorizer、HashingVectorizer、DicVectorizer四个类是不同算法的词袋模型。本部分详细讲解这四个类。一CountVectorizer先分词--统计词频--根据词频生成词向量。1、下面用一个小例子来说明CountVectorizer的使用方法这里重点强调一下CountVectorizer类中的几个参数1stop_words移除常见词、停用词等。一是使用CountVectorizer类自带的停用词表。当你实例化CountVectorizer类的时候加上参数stop_wordsenglish第一次使用CountVectorizer这个类就会自动帮你下载一个停用词表到你的本地这样你就可以使用这个词表了。你也可以直接修改这个词表中的词。二是自定义停用词表。不管是中文还是英文你都可以用一个list来装你的所有停用词。还可以把你自己定义的停用词和CountVectorizer类提供的停用词表合并。2ngram_range设置单词对儿的范围。比如ngram_range(1,2)表示一个单词和两个单词的都可以做为特征词也就是都要放入字典中。ngram_range(2,2)表示只要两两单词对儿的。这个参数就是n-gram算法的思想。3max_features仅保留出现频率最高的单词。4analyzer如果我们分析古诗、文言文这类的文本我们希望单个单子汉字的分析此时把这个参数设为char就可以了。from sklearn.feature_extraction.text import CountVectorizer corpus [This is the first document., This document is the second document., And this is the third one., Is this the first document?] vectorizer CountVectorizer(stop_words[is, the], ngram_range(1,2)) vectorizer type(vectorizer) X vectorizer.fit_transform(corpus) X X.toarray() print(X) vectorizer.get_feature_names() vectorizer.vocabulary_2、中文处理要更复杂一些直接用CountVectorizer处理中文语料效果非常不好。一是因为CountVectorizer本身不直接处理中文分词它默认按空格或标点分割文本而中文句子没有天然空格分隔因此不能直接使用原始中文文本还需结合中文分词工具如jieba进行预处理。二是CountVectorizer的参数token_pattern默认是保留2个或2个以上字母数字字符的词所以对中文来说单个的字就又被丢弃了所以还得用正则表达式来定义token_pattern参数保留单个字。下面展示一个中文的小李子from sklearn.feature_extraction.text import CountVectorizer corpus [我爱北京天安门天安门很壮观, 我经常在广场拍照] import jieba corpus_tokenized [ .join(jieba.lcut(s)) for s in corpus] corpus_tokenized vectorizer CountVectorizer(stop_words[在], token_pattern[\u4e00-\u9fa5_a-zA-Z0-9]{1,}) vectorizer X vectorizer.fit_transform(corpus_tokenized) X X.toarray() print(X) vectorizer.vocabulary_ vectorizer.get_feature_names()二TfidfVectorizerTF-IDF(词频-逆文档频率),是一种用于衡量文本中词语重要性的方法特别适用于信息检索和文本挖掘任务。TF-IDF的计算过程可以分为两个主要部分词频(TF)和逆文档频率(IDF):如果一个词至于它所在的文档经常出现那tf计算出来它的重要性就越大但是如果这个词在文档库中的其他文档中也经常出现那这个词的idf值就会越小如此以来tf x idf的结果就不会很大说明这个词不是这个文档的典型代表。如果这个词只在这个文档中出现而且几乎没有在其他文档中出现那这个词的idf就会很大那tf x idf的结果就会很大也就是这个词就是这个文档的典型代表。下面还是用前面的例子展示一下TfidfVectorizer的用法from sklearn.feature_extraction.text import TfidfVectorizer import jieba corpus [我爱北京天安门天安门很壮观, 我经常在广场拍照] corpus_tokenized [ .join(jieba.lcut(s)) for s in corpus] corpus_tokenized tfidf TfidfVectorizer(token_pattern[\u4e00-\u9fa5_a-zA-Z0-9]{1,}) tfidf_vec tfidf.fit_transform(corpus_tokenized) tfidf_vec tfidf_vec.toarray() print(tfidf_vec) tfidf.vocabulary_ tfidf.get_feature_names()三HashingVectorizerHashingVectorizer算法是借鉴计算机底层的一种数据结构的思路而诞生的具体说就是借鉴了哈希数据结构的思路所以我们从哈希数据结构讲起可见Hash函数是一种典型的多对一映射正向快速给定明文和hash算法在有限时间和有限资源内能计算出hash值。逆向困难给定若干hash值在有限时间内很难(基本不可能)逆推出明文。输入敏感原始输入信息修改一点信息产生的hash值看起来应该都有很大不同。碰撞避免很难找到两段内容不同的明文使得它们的hash值一致(发生碰撞)。即对于任意两个不同的数据块其hash值相同的可能性极小对于一个给定的数据块找到和它hash值相同的数据块极为困难。HashingVectorizer类在sklearn.feature_extraction.text.HashingVectorizer下它就是通过哈希技巧进行特征提取它的内存非常低适用大型数据集。比如分词后的词汇字典表非常大100万此时如果直接使用CountVectorizer或Tf-idf方法那对内存来说就是灾难在这种场景下我们可以将文本进行hash编码。from sklearn.feature_extraction.text import HashingVectorizer corpus [smart boy, ate, bacon, a cat] # Hashingvectorizer是无状态的你不需要fit它 # Hash向量化时这里指定向量长度为6 vectorizer HashingVectorizer(n_features6) # 进行hash转换 counts vectorizer.transform(corpus).todense() counts counts.shape说明1不管输入文本的长度如何不管输入文本中包含多少个“词”输出词向量都会被hash成长度为6的词向量。2归一化每个向量的分量值都会被限制在[0,1]之间。#多行文本 corpus [UNC played Duke in basketball, Duke lost the basketball game,game over, I ate a sandwich] vectorizer HashingVectorizer(n_features 3) ## 生成转换对象 counts vectorizer.transform(corpus).todense() # 进行转换 counts counts.shape说明1因为不知道hash应用了什么函数输出的结果很难知道什么意思。2Hash表达长度N越小Hash冲突的可能性越大。四DicVectorizerDictVectorizer类用于将dict对象列表为表示形式的数组转换为scikit-learn估计器使用的NumPy/ciPy形式。例子可以看出DictVectorizer把Python的Dict类型数据提取自动转化为Onehot的编码。from sklearn.feature_extraction import DictVectorizer dic [{城市:广州, 温度:33}, {城市:北京, 温度:12}, {城市:上海, 温度:18}] vectorizer DictVectorizer() vec vectorizer.fit_transform(dic) vec.toarray() print(vec) vectorizer.vocabulary_ vectorizer.get_feature_names()三、案例基于酒店文本数据创建一个内容推荐系统一推荐算法介绍待续。。。补充画词云# 画词云 from wordcloud import WordCloud import jieba.posseg as pseg import jieba corpus [我爱北京天安门天安门很壮观, 我经常在广场拍照] corpus_tokenized [ .join(jieba.lcut(s)) for s in corpus] corpus_tokenized keywords_str .join(corpus_tokenized) keywords_str font_path rC:/Windows/Fonts/simhei.ttf wordcloud WordCloud(width400, height200, background_colorblack,font_pathfont_path).generate(keywords_str) _ plt.figure(figsize(10, 5)) _ plt.imshow(wordcloud, interpolationbilinear) _ plt.axis(off) _ plt.title(fwordcloud) plt.show()