机械学习---词向量转化评价,附代码实例
一、词向量原理介绍
在自然语言处理(NLP)领域,词向量(Word Embedding) 是将文本中的词语转换为数值向量的技术,它解决了传统文本表示方法的局限性,为机器学习模型理解语言语义提供了基础。以下从概念、发展历程、核心原理、主流模型、应用场景等方面详细介绍词向量。
一、词向量的核心概念
词向量是词语的数值化表示,其核心思想是:将每个词语映射到一个低维稠密的实数向量空间中,使得向量之间的距离(如余弦相似度)能够反映词语的语义关联 ——语义相近的词语,其向量表示也相近。
例如:
- “国王” 和 “女王” 的向量差异,可能与 “男人” 和 “女人” 的向量差异相似;
- “猫” 和 “狗” 的向量距离,会比 “猫” 和 “汽车” 的距离更近。
二、传统文本表示的局限性
在词向量出现之前,主流的文本表示方法存在明显缺陷,这也凸显了词向量的必要性:
-
独热编码(One-Hot Encoding)
- 原理:为每个词语分配一个唯一索引,向量中仅对应索引位置为 1,其余为 0。
- 缺陷:
- 维度灾难:词汇表大小为 N 时,向量维度为 N(十万级),计算效率极低。
- 语义鸿沟:向量之间是正交关系(相似度为 0),无法体现词语间的关联(如 “苹果” 和 “水果”)。
-
词袋模型(Bag of Words)
- 原理:用词语的出现频率表示文本,忽略语序和语法。
- 缺陷:丢失语义和上下文信息,高频无意义词(如 “的”“是”)会干扰模型。
-
TF-IDF
- 原理:通过词频(TF)和逆文档频率(IDF)加权,突出重要词语。
- 缺陷:仍未解决语义表示问题,无法捕捉词语的多义性(如 “银行” 可指金融机构或河岸)。
三、词向量的核心原理
词向量的本质是通过上下文学习词语的语义表示,其理论基础是分布式假设(Distributional Hypothesis):
“A word is characterized by the company it keeps”(词语的语义由其上下文环境决定)。
例如,“苹果” 常出现在 “吃”“水果”“甜” 等词语附近,而 “华为” 常出现在 “手机”“科技”“品牌” 附近,通过学习这些上下文关联,模型能区分两者的语义。
四、主流词向量模型
1. Word2Vec(2013,Mikolov et al.)
Word2Vec 是最经典的词向量模型,通过简化神经网络结构实现高效训练,包含两种架构:
(1)CBOW(Continuous Bag-of-Words)
-
原理:用上下文词语预测中心词。例如,输入 “[我] [爱] [吃] [水果]”,预测中心词 “苹果”。
-
优势:训练速度快,适合大规模语料。
(2)Skip-gram
-
原理:用中心词预测上下文词语。例如,输入 “苹果”,预测上下文 “我”“爱”“吃”“水果”。
-
优势:对低频词更友好,语义表示更精准。
Word2Vec 的优化技巧
-
负采样(Negative Sampling):通过抽样负例(非上下文词语)简化损失计算,替代传统的 softmax。
-
层次 softmax(Hierarchical Softmax):用哈夫曼树减少输出层计算量,提升效率。
2. GloVe(Global Vectors for Word Representation,2014)
-
原理:结合全局词共现统计和局部上下文预测,通过构建词共现矩阵,用最小二乘损失优化向量表示。
-
优势:同时利用全局统计信息和局部上下文,在语义相似度任务上表现优于 Word2Vec。
3. FastText(2016,Facebook)
-
原理:将词语拆分为n-gram 子词(Subword),例如 “apple” 拆分为 “<ap”“app”“ppl”“ple”“le>”(< 和 > 表示边界)。
-
优势:
-
解决未登录词(OOV,Out-of-Vocabulary)问题:通过子词组合表示新词。
-
对形态丰富的语言(如德语、法语)更友好。
-
4. 上下文相关词向量模型
传统模型(如 Word2Vec、GloVe)生成的是静态词向量(一个词对应一个向量),无法处理多义词。而上下文相关模型能根据语境动态生成向量:
(1)ELMo(Embeddings from Language Models,2018)
-
原理:基于双向 LSTM 的预训练语言模型,为每个词语生成上下文相关向量(同一词在不同句子中向量不同)。
-
例如:“他坐在银行边” 和 “他去银行取钱” 中,“银行” 的向量不同。
(2)BERT 及后续模型(2018 - 至今)
-
原理:基于 Transformer 架构的预训练模型,通过 “掩码语言模型(MLM)” 和 “下一句预测(NSP)” 任务学习深层语义。
-
优势:能捕捉更复杂的上下文依赖和语义细微差别,是当前 NLP 任务的主流基础模型。
五、词向量的训练流程
- 语料准备:收集大规模文本数据(如新闻、书籍、网页),进行预处理(分词、去停用词、 lowercase 等)。
- 词汇表构建:统计语料中出现的词语,过滤低频词,建立词汇表。
- 模型训练:选择 Word2Vec、GloVe 等模型,设置向量维度(通常 50-300)、窗口大小(上下文范围)等超参数,用语料训练模型。
- 向量应用:训练完成后,每个词语对应一个向量,可直接用于下游任务(如文本分类、相似度计算)。
六、词向量的应用场景
- 语义相似度计算:通过向量余弦相似度衡量词语 / 句子的语义关联(如搜索引擎中的 “相关推荐”)。
- 文本分类与聚类:将词向量作为特征输入分类模型(如情感分析:判断 “这部电影很棒” 为正面情绪)。
- 机器翻译:词向量帮助模型对齐不同语言的语义(如 “狗” 和 “dog” 的向量在空间中接近)。
- 问答系统与对话机器人:通过词向量理解用户问题的语义,匹配最相关的答案。
- 推荐系统:基于用户评论的词向量分析偏好,实现个性化推荐(如 “喜欢科幻电影的用户可能也喜欢科幻小说”)。
七、词向量的局限性与发展
局限性
-
静态词向量无法处理多义性(如 “苹果” 既指水果也指公司)。
-
依赖大规模高质量语料,低资源语言(如小语种)表现较差。
-
难以捕捉复杂语义关系(如因果关系、隐喻)。
发展趋势
-
上下文相关向量:BERT、GPT 等预训练模型成为主流,动态生成词语向量。
-
多模态词向量:融合文本、图像、语音等信息,提升语义表示的丰富性(如 “猫” 的向量同时关联图片特征)。
-
低资源语言优化:通过迁移学习(如用英语模型初始化小语种模型)提升效果。
总结
词向量是自然语言处理的核心技术,它将离散的词语转换为连续的向量空间表示,使机器学习模型能够 “理解” 语义。从早期的 Word2Vec 到如今的 BERT,词向量的发展推动了 NLP 任务的性能飞跃。尽管存在局限性,但词向量仍是连接文本与机器学习的重要桥梁,在各类实际应用中发挥着关键作用。
二、代码实现和实战案例
1、代码API详解
sklearn.feature_extraction.text.CountVectorizer
是 scikit-learn 库中用于将文本数据转换为词频矩阵(词向量)的核心工具,它能将一系列文本文档转换为一个基于词频计数的数值特征矩阵,是文本分类、情感分析等自然语言处理任务的基础预处理工具。
以下是其主要 API 参数和方法的详细介绍:
1、核心参数(初始化时设置)
1. 词汇表相关参数
input
:指定输入数据的类型,默认为'content'
(直接处理文本内容),可选'filename'
(处理文件路径)或'file'
(处理文件对象)。encoding
:文本编码格式,默认为'utf-8'
,用于读取文本时解析字符。decode_error
:处理编码错误的方式,默认为'strict'
(报错),可选'ignore'
(忽略错误)或'replace'
(替换错误字符)。strip_accents
:是否去除字符的重音符号,可选None
(不处理)、'ascii'
(仅对 ASCII 字符有效)或'unicode'
(对所有 Unicode 字符有效)。lowercase
:是否将所有文本转换为小写,默认为True
,有助于统一词汇格式(如 "Hello" 和 "hello" 视为同一词)。preprocessor
:自定义预处理函数,用于在分词前对文本进行处理(如去除特殊符号),默认为None
(使用内置处理)。tokenizer
:自定义分词函数,默认为None
(使用内置的空格分词),中文场景中常需替换为jieba.lcut
等分词工具。stop_words
:指定停用词表,默认为None
,可选'english'
(使用内置英文停用词),或传入自定义停用词列表(如中文停用词)。token_pattern
:分词的正则表达式模式,默认为r"(?u)\b\w\w+\b"
(匹配至少 2 个字符的单词),中文场景中通常需要修改或禁用。ngram_range
:提取 n-gram 的范围,默认为(1, 1)
(仅提取单个词),如(1, 2)
表示同时提取 1-gram(单个词)和 2-gram(连续两个词)。analyzer
:指定分析单位,默认为'word'
(按词分析),可选'char'
(按字符分析)或'char_wb'
(按字符分析但不跨越词边界)。max_df
:词的最大文档频率阈值,默认为1.0
(所有文档),可设为浮点数(比例)或整数(绝对数量),过滤在过多文档中出现的词(如通用词汇)。min_df
:词的最小文档频率阈值,默认为1
,过滤在过少文档中出现的词(如稀有词)。max_features
:词汇表的最大规模,默认为None
(不限制),若设为整数 N,则只保留词频最高的前 N 个词。vocabulary
:自定义词汇表,默认为None
,若传入字典({词:索引}),则仅使用该词汇表中的词。binary
:是否将词频转换为二进制指示(1 表示出现,0 表示未出现),默认为False
(保留实际计数)。dtype
:输出矩阵的数据类型,默认为numpy.int64
,可改为numpy.float32
等节省内存。
2、核心方法
-
fit(raw_documents)
- 功能:根据输入的文本数据(
raw_documents
)构建词汇表,统计词频并确定最终保留的词。 - 输入:文本列表(如
["我喜欢python", "python很强大"]
)。 - 输出:返回对象本身(可链式调用)。
- 功能:根据输入的文本数据(
-
transform(raw_documents)
- 功能:使用已构建的词汇表,将输入文本转换为词频矩阵(稀疏矩阵)。
- 输入:与
fit
相同格式的文本列表。 - 输出:形状为
(n_samples, n_features)
的稀疏矩阵,其中n_samples
为文本数量,n_features
为词汇表大小,矩阵值为词在文本中的出现次数(或二进制指示)。
-
fit_transform(raw_documents)
- 功能:合并
fit
和transform
步骤,先构建词汇表,再直接转换文本,效率高于单独调用。
- 功能:合并
-
get_feature_names_out()
- 功能:返回词汇表中的所有词(按索引顺序),用于查看构建的词汇表内容。
- 输出:数组形式的词列表(如
array(['python', '喜欢', '强大'], dtype=object)
)。
-
inverse_transform(X)
- 功能:将词频矩阵转换回文本形式(仅保留出现的词)。
- 输入:由
transform
生成的词频矩阵。 - 输出:文本列表,每个元素为对应文档中出现的词(用空格连接)。
-
get_params(deep=True)
- 功能:获取当前
CountVectorizer
的所有参数配置。
- 功能:获取当前
-
set_params(**params)
- 功能:修改
CountVectorizer
的参数配置(如动态调整max_features
)。
- 功能:修改
3、注意事项
- 中文处理:
CountVectorizer
默认按空格分词,中文需先使用jieba
等工具分词,再用空格连接(如"我 喜欢 机器学习"
),并设置tokenizer=lambda x: x.split()
。 - 内存问题:文本量大时,词频矩阵可能非常稀疏,建议保留稀疏矩阵格式(避免用
toarray()
转换为稠密矩阵)。 - 词汇表规模:通过
max_df
、min_df
、max_features
控制词汇表大小,避免维度灾难。
2、实战案例(好评差评的判断)
现在需要用词向量的方法来训练一个好评差评的分析模型,
数据就用爬虫爬取的苏宁易购的数据
教程:看爬取的第二个案例
如果不想麻烦可以直接下载,数据已经上传(完整的工程文件也已经上传)
代码详解:
1. 导入库
import pandas as pd
这行代码导入了pandas
库,并将其别名为pd
。pandas
是一个用于数据处理和分析的强大库,在后续代码中用于读取文件、数据处理和构建数据框等操作。
2. 读取数据并分词
cp = pd.read_table("差评.txt", encoding='gbk')
yzpj = pd.read_table("优质评价.txt", encoding='gbk')import jieba
cp_segments = []
contents = cp.content.values.tolist()
for content in contents:results = jieba.lcut(content)if len(results)>1:cp_segments.append(results)
cp_fc_results = pd.DataFrame({'content':cp_segments})
cp_fc_results.to_excel('cp_fc_results.xlsx',index = False)yzpj_segments = []
contents = yzpj.content.values.tolist()
for content in contents:results = jieba.lcut(content)if len(results)>1:yzpj_segments.append(results)
yzpj_fc_results = pd.DataFrame({'content':yzpj_segments})
yzpj_fc_results.to_excel('yzpj_fc_results.xlsx',index = False)
- 首先使用
pd.read_table
函数分别读取了名为 “差评.txt” 和 “优质评价.txt” 的文件,文件编码为gbk
,并将数据存储在cp
和yzpj
两个数据框中。 - 然后导入
jieba
库,这是一个中文分词工具。 - 接下来通过循环遍历
cp
数据框中content
列的值,使用jieba.lcut
对每个评价内容进行分词,将分词结果长度大于 1 的添加到cp_segments
列表中,最后将cp_segments
列表转换为数据框cp_fc_results
并保存为cp_fc_results.xlsx
文件。 - 对
yzpj
数据框进行同样的操作,得到分词后的结果并保存为yzpj_fc_results.xlsx
文件。
3. 去除停用词
stopwords = pd.read_csv('StopwordsCN.txt',encoding='utf-8',engine='python',sep='\t')
def drop_stopwords(contents,stopwords):segments_clean = []for content in contents:line_clean = []for word in content:if word in stopwords:continueline_clean.append(word)segments_clean.append(line_clean)return segments_cleancontents = cp_fc_results.content.values.tolist()
stopwords = stopwords.stopword.values.tolist()
cp_fc_content_clean_s = drop_stopwords(contents,stopwords)contents = yzpj_fc_results.content.values.tolist()
yzpj_fc_content_clean_s =drop_stopwords(contents,stopwords)
- 首先使用
pd.read_csv
函数读取了名为 “StopwordsCN.txt” 的停用词文件,文件编码为utf - 8
,使用python
引擎,分隔符为制表符\t
。 - 定义了
drop_stopwords
函数,该函数接受两个参数,contents
是包含分词结果的列表,stopwords
是停用词列表。函数内部通过嵌套循环遍历contents
中的每个分词结果和其中的每个单词,如果单词在停用词列表中则跳过,否则将其添加到line_clean
列表中,最后将line_clean
列表添加到segments_clean
列表中并返回。 - 分别将
cp_fc_results
和yzpj_fc_results
数据框中content
列的值转换为列表,然后调用drop_stopwords
函数去除停用词,得到cp_fc_content_clean_s
和yzpj_fc_content_clean_s
两个去除停用词后的列表。
4. 朴素贝叶斯分类
4.1 给每个数据添加数字标签
cp_train = pd.DataFrame({'segments_clean': cp_fc_content_clean_s, 'label': 1})
yzpj_train = pd.DataFrame({'segments_clean': yzpj_fc_content_clean_s, 'label': 0})
pj_train = pd.concat([cp_train, yzpj_train])
pj_train.to_excel('pj_train.xlsx', index=False)
- 将去除停用词后的差评数据
cp_fc_content_clean_s
和标签1
(表示差评)构建成数据框cp_train
,将优质评价数据yzpj_fc_content_clean_s
和标签0
(表示优质评价)构建成数据框yzpj_train
。 - 使用
pd.concat
函数将cp_train
和yzpj_train
两个数据框合并成一个数据框pj_train
,并将其保存为pj_train.xlsx
文件。
4.2 数据切分
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = \train_test_split(pj_train['segments_clean'].values, pj_train['label'].values, random_state=0)
从sklearn.model_selection
模块中导入train_test_split
函数,该函数用于将数据集划分为训练集和测试集。这里将pj_train
数据框中的segments_clean
列的值作为特征数据,label
列的值作为标签数据,按照默认的测试集比例将数据划分为训练集特征x_train
、测试集特征x_test
、训练集标签y_train
和测试集标签y_test
,random_state = 0
用于设置随机种子,确保每次运行代码时数据划分结果一致。
4.3 将所有的词转换为词向量
words = []
for line_index in range(len(x_train)):words.append(' '.join(x_train[line_index]))from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer(max_features=10000, lowercase=False, ngram_range=(1, 3))
vec.fit(words)
x_train_vec = vec.transform(words)
- 首先创建一个空列表
words
,通过循环将训练集特征x_train
中的每个分词结果列表转换为以空格分隔的字符串,并添加到words
列表中。 - 从
sklearn.feature_extraction.text
模块中导入CountVectorizer
类,该类用于将文本数据转换为词向量。创建CountVectorizer
对象vec
,设置max_features = 10000
表示只提取词频最高的前 10000 个词作为词库,lowercase = False
表示不将所有词转换为小写,ngram_range=(1, 3)
表示考虑 1 - 3 元组的词。 - 使用
vec.fit(words)
根据words
列表构建词向量模型,然后使用vec.transform(words)
将words
列表转换为词向量矩阵x_train_vec
。
4.4 训练朴素贝叶斯分类器并进行预测
from sklearn.naive_bayes import MultinomialNB, ComplementNB
classifier = MultinomialNB(alpha=0.1)
classifier.fit(x_train_vec, y_train)train_pr = classifier.predict(x_train_vec)from sklearn.metrics import accuracy_scoretest_words = []
for line_index in range(len(x_test)):test_words.append(' '.join(x_test[line_index]))
x_test_vec = vec.transform(test_words)test_pr = classifier.predict(x_test_vec)
print("测试集准确率:", accuracy_score(y_test, test_pr))
test_predicted = classifier.predict(x_test_vec)
print("测试集分类报告:")
print(metrics.classification_report(y_test, test_predicted, digits=4))
- 从
sklearn.naive_bayes
模块中导入MultinomialNB
和ComplementNB
类,这里选择MultinomialNB
类创建朴素贝叶斯分类器对象classifier
,设置alpha = 0.1
。 - 使用
classifier.fit(x_train_vec, y_train)
对分类器进行训练,将训练集词向量x_train_vec
和训练集标签y_train
作为训练数据。 - 使用
classifier.predict(x_train_vec)
对训练集进行预测,得到训练集预测结果train_pr
。 - 对测试集数据进行同样的处理,先将测试集特征
x_test
转换为以空格分隔的字符串列表test_words
,然后转换为词向量矩阵x_test_vec
,使用classifier.predict(x_test_vec)
对测试集进行预测,得到测试集预测结果test_pr
。 - 使用
accuracy_score
函数计算测试集的准确率并打印,使用classification_report
函数生成测试集的分类报告并打印,digits = 4
表示保留四位小数。
4.5 交互式预测
while True:text_something = input('请输入一段评价(输入exit退出):')if text_something == 'exit':breakseg_list = jieba.lcut(text_something)seg_clean = [word for word in seg_list if word not in stopwords]text_processed = [' '.join(seg_clean)]text_vec = vec.transform(text_processed)predict = classifier.predict(text_vec)if predict[0] == 1:print("预测结果:差评")else:print("预测结果:优质评价")
- 使用
while True
创建一个无限循环,在循环内部使用input
函数获取用户输入的评价文本。 - 如果用户输入的是
exit
,则使用break
跳出循环。 - 否则,对用户输入的文本进行分词、去除停用词处理,将处理后的结果转换为符合要求的格式并转换为词向量,最后使用训练好的分类器进行预测,并根据预测结果打印 “预测结果:差评” 或 “预测结果:优质评价”。