引言
在自然语言处理(NLP)的广阔领域中,计算机面临的一大挑战是理解人类语言的丰富性和复杂性。文本数据对于机器而言,最初只是一连串难以理解的字符。词向量转换便成为了一座关键的桥梁,它将文本中的单词映射为数值向量,使得计算机能够对文本进行高效处理和分析,为众多 NLP 任务,如文本分类、情感分析、机器翻译等,奠定了坚实的基础。
一、为什么需要词向量转换
人类语言丰富多样,单词具有语义、语法和语境等多重信息。但计算机擅长处理数值数据,原始文本无法直接被计算机理解和分析。词向量转换通过将单词转换为数值向量,把语言信息编码成计算机能处理的形式。这样,计算机可以利用这些向量进行计算,从而挖掘文本中的有用信息,实现对文本的理解和处理。
二、常见的词向量转换方法
(一)独热编码(One-Hot Encoding)
- 原理:独热编码为每个单词创建一个唯一的向量。假设词汇表大小为 N,那么每个单词的独热向量长度为 N,其中只有对应单词位置的元素为 1,其余位置均为 0。例如,对于词汇表 ["apple", "banana", "cherry"],"apple" 的独热编码为 [1, 0, 0],"banana" 为 [0, 1, 0],"cherry" 为 [0, 0, 1]。
- 优点:简单直观,易于实现和理解。
- 缺点:向量维度高且极其稀疏,当词汇表很大时,会导致计算量剧增和存储浪费。同时,这种编码方式无法体现单词之间的语义关系,每个向量都是孤立的。
(二)词袋模型(Bag of Words)
- 原理:把文本看作一个无序的单词集合。构建一个词汇表,统计每个单词在文本中出现的次数,生成一个向量。向量长度等于词汇表大小,每个元素对应词汇表中单词在文本中的出现次数。例如,对于文本 "I like apple and I like banana",词汇表为 ["I", "like", "apple", "banana", "and"],词袋模型向量为 [2, 2, 1, 1, 1]。
- 优点:简单有效,能保留文本的基本信息,在一些简单文本分类任务中表现尚可。
- 缺点:完全忽略单词顺序,丢失了句子的语法和语义结构信息,无法捕捉单词间的语义关系。
(三)Word2Vec
- 原理:基于神经网络的方法,旨在学习单词的分布式表示。主要有 Skip - Gram 和 Continuous Bag of Words(CBOW)两种模型架构。Skip - Gram 模型通过一个单词来预测其上下文单词;CBOW 则是通过上下文单词来预测目标单词。在大规模语料库上训练后,语义相近的单词在向量空间中的距离会比较近。例如,"car" 和 "automobile" 的词向量在空间中会很接近。
- 优点:能有效捕捉单词间的语义关系,生成的词向量维度较低且稠密,大大减少计算量和存储空间。相比独热编码和词袋模型,在语义理解任务上有显著提升。
- 缺点:词向量是固定的,对于一词多义的情况,一个单词只有一个固定向量表示,无法根据不同语境动态调整。
(四)GloVe(Global Vectors for Word Representation)
- 原理:基于全局词频统计的方法。通过对语料库中单词共现矩阵进行因式分解得到单词向量表示。它结合了局部上下文窗口和全局统计信息,在训练时考虑了单词在整个语料库中的共现频率。
- 优点:训练速度相对较快,性能较好,在捕捉语义关系方面表现出色,并且能利用全局统计信息更好地学习词向量。
- 缺点:同样存在一词多义问题,对于复杂语义场景的适应性有限。
(五)FastText
- 原理:在 Word2Vec 基础上,考虑了单词的子词信息。它将单词拆分成字符 n - gram,比如对于单词 "unhappiness",会考虑 "un", "hap", "app", "piness" 等子词信息。这样即使遇到未登录词(out - of - vocabulary words),也能根据子词信息生成合理的向量表示。
- 优点:能有效处理未登录词,在一些数据量较小或存在大量生僻词的场景中表现良好,训练速度快。
- 缺点:相较于一些复杂模型,对词向量语义表示的能力稍弱,在对语义理解要求极高的任务上表现可能欠佳。
(六)基于预训练语言模型的向量表示(如 BERT)
- 原理:BERT 是基于 Transformer 的双向预训练语言模型。它通过在大规模语料上进行无监督预训练,学习到丰富的语言知识。在处理文本时,能够根据上下文动态生成词向量,有效解决一词多义问题。例如在句子 "I bank at the river bank" 中,BERT 可以根据不同语境为两个 "bank" 生成不同的词向量。
- 优点:能捕捉极为丰富的语义信息,在各种 NLP 任务上展现出卓越性能,极大推动了 NLP 技术的发展。
- 缺点:计算资源需求巨大,训练和推理时间较长,对硬件设备要求高。
三、如何选择合适的词向量转换方法
选择词向量转换方法时,需综合多方面因素考量:
- 任务类型:对于简单文本分类、关键词提取等任务,词袋模型或 TF - IDF 可能就足够;而对于机器翻译、语义相似度计算、问答系统等对语义理解要求高的任务,Word2Vec、GloVe 或基于预训练模型的方法更合适。
- 数据规模:数据量较小且词汇表不大时,独热编码或简单的词袋模型可能适用;大规模语料库则更适合基于深度学习的方法,如 Word2Vec、BERT 等,它们能充分利用大量数据学习到更好的词向量表示。
- 是否有未登录词:如果数据中存在大量未登录词,FastText 是不错的选择,其基于子词的方法能有效处理这类情况。
- 计算资源和时间:资源有限且对时间要求高时,简单方法如词袋模型或计算效率高的 FastText 更合适;若有充足资源,BERT 等预训练模型能带来更好效果。
四、词向量转换代码实现
下面我们通过词向量转换来对苏宁易购好评差评分词
python
import pandas as pd
#读取文件
cp_content=pd.read_table(r".\差评_1.txt",encoding='gbk')
yzpj_content=pd.read_table(r'.\优质评价_1.txt',encoding='gbk')
import jieba
###################差评分词################
cp_segments=[]
#将cp_content中文件提取出来并转化维list列表
#cp_content是一个pandas的DataFrame对象
#cp_content.content 表示从 cp_content 数据框中选取名为 content 的列
#.values 方法将该列的数据转换为 numpy 数组
#.tolist() 方法将 numpy 数组转换为 Python 列表
contents=cp_content.content.values.tolist()
for content in contents:
#利用jieba库,将content语句按jieba库单词切分,返回一个包含这些词语的列表
results=jieba.lcut(content)
#过滤掉分词结果只有一个词的情况。因为单个词可能不具有足够的信息
if len(results)>1:
cp_segments.append(results)
#使用 pandas 的 DataFrame 构造函数将 cp_segments 列表转换为一个 DataFrame 对象
#{"content": cp_segments} 表示创建一个名为 content 的列,该列的数据来自 cp_segments 列表。
cp_fc_results=pd.DataFrame({"content":cp_segments})
#使用 DataFrame 的 to_excel 方法将 cp_fc_results 数据框保存为 Excel 文件
#文件名为 cp_fc_results.xlsx。index=False 表示不保存行索引,只保存数据内容。
cp_fc_results.to_excel('cp_fc_results.xlsx',index=False)
###################好评分词################
yzpj_segments=[]
contents=yzpj_content.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)
#############################################
#从给定的文本分词结果中去除停用词
def drop_stopwords(contents,stopwords):
segments_clean=[]
for content in contents:
line_clean = []
for word in content:
if word in stopwords:
continue
line_clean.append(word)
segments_clean.append(line_clean)
return segments_clean
stopwords=pd.read_table(r'D:\code\机器学习\pythonProject\11、文本数据学习_词向量转换\StopwordsCN.txt',encoding='utf8',index_col=False)
stopwords = stopwords.stopword.values.tolist()
contents= cp_fc_results.content.values.tolist()
cp_fc_contents_clean_s = drop_stopwords(contents, stopwords)
contents = yzpj_fc_results.content.values.tolist()
yzpj_fc_contents_clean_s = drop_stopwords(contents, stopwords)
############################朴素贝叶斯分类############################
cp_train=pd.DataFrame({'segments_clean':cp_fc_contents_clean_s,'label':1})#构建一个DataFrame表格数据
yzpj_train=pd.DataFrame({'segments_clean':yzpj_fc_contents_clean_s, 'label':0})
#连接表格
pj_train = pd.concat([cp_train,yzpj_train])
#当你设置 index=False 时,to_excel 方法在保存 DataFrame 到 Excel 文件时,不会将 DataFrame 的索引作为一列数据写入 Excel 文件中
pj_train.to_excel('pj_train.xlsx',index=False)
#a的类型为series类型
a=pj_train['segments_clean']
#b的类型为ndarray类型
b=pj_train['segments_clean'].values
from sklearn.model_selection import train_test_split
#.values 方法将该列的数据转换为 numpy 数组
x_train,x_test,y_train,y_test=train_test_split(pj_train['segments_clean'].values,pj_train['label'].values, random_state=0)
#词向量CountVectorizer所能识别的类型有:字符串列表,可迭代的字符串对象,文件对象
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB,ComplementNB
from sklearn import metrics
words =[]
#转换为词向量CountVectorizer所能识别的列表类型
for line_index in range(len(x_train)):
#从x_train 中取出元素并拼接成字符串,然后将该字符串添加到 words列表中。
#''.join(x_train[line_index]):
# join() 是字符串对象的一个方法,它的作用是将可迭代对象中的字符串元素连接成一个字符串。
# '' 是连接符,表示直接将子列表中的字符串依次拼接在一起,中间不插入任何字符。
words.append(''.join(x_train[line_index]))
# print(words)
#CountVectorizer 是 scikit-learn 库中用于将文本数据转换为词频矩阵的工具。
#max_features=4000该参数用于限制词频矩阵中特征(即单词或词组)的最大数量。
# CountVectorizer 会根据词频对所有特征进行排序,只选取词频最高的前 4000 个特征来构建词频矩阵。
#lowercase=False该参数控制是否将所有文本转换为小写。默认值为 True,即会将输入的文本全部转换为小写。
# 当设置为 False 时,CountVectorizer 会保留文本的原始大小写形式。
#ngram_range=(1, 3)该参数用于指定要提取的 n-gram 的范围。
# n-gram 是指文本中连续的 n 个单词或字符组成的序列。
# ngram_range=(1, 3) 表示同时提取 1-gram(单个单词)、2-gram(连续的两个单词)和 3-gram(连续的三个单词)作为特征。
vec = CountVectorizer(max_features=4000,lowercase = False, ngram_range=(1,3))
vec.fit(words)#传入训练集
#创建一个多项式朴素贝叶斯分类器对象
classifier = MultinomialNB(alpha = 0.1)
#使用训练数据对该分类器进行训练
#vec 是之前创建的 CountVectorizer 对象,它用于将文本数据转换为词频矩阵。
#words 是一个字符串列表,每个字符串代表一个文本样本。
#vec.transform(words) 方法会将 words 列表中的文本数据转换为词频矩阵
#该矩阵的每一行对应一个文本样本,每一列对应一个特征(即单词或词组),矩阵中的元素表示该特征在对应样本中出现的次数。
classifier.fit(vec.transform(words),y_train)
#训练数据集自测
train_pr = classifier.predict(vec.transform(words))
print(metrics.classification_report(y_train, train_pr))#分类结果。
test_words =[]
for line_index in range(len(x_test)):
test_words.append(''.join(x_test[line_index]))
#对测试集进行预测
test_pr = classifier.predict(vec.transform(test_words))
print(metrics.classification_report(y_test,test_pr))#分类结果。
五、总结
词向量转换是 NLP 领域的基石,不同方法各有优劣,适用于不同场景。从简单的独热编码到复杂强大的预训练模型,每种方法都在推动 NLP 技术的进步。随着技术不断发展,新的词向量表示方法和改进思路不断涌现。在实际应用中,需深入理解各种方法,根据具体任务和数据特点精心选择,才能充分发挥词向量转换的作用,让计算机更好地理解和处理人类语言,为 NLP 应用的创新和发展注入动力。