分词和词向量是NLP的基础技术。
分词是将连续的文本分割成独立的词汇单元(tokens)的过程。这些单元可以是单词、符号或子词。
中文句子由连续的汉字组成,没有明显的词边界:词与词之间没有分隔符
I love natural language processing.
我喜欢自然语言处理。
为了处理文本信息,须将连续的序列分割成有意义的词汇单元。
大家进行下颗粒度对齐,以保证后续沟通的准确性。
词表,vocab,是指一个NLP系统中所有可能出现的词汇的集合。它是一个有限的列表,包含了模型任务中用到的所有词汇。
词表具备以下特征:
词表通常从大规模语料库中构建,包含所有高频和常见词,并可能经过一定的去除低频词的处理。
Out-of-Vocabulary, OOV。
未登录词是指在测试数据或实际应用中出现,但未包含在训练词表中的词汇。这些词汇对模型来说是未知的。
)表示所有未登录词。词频 ≠ 词频概率,但两者密切相关。
词频,Frequency,指的是一个词在语料库中出现的次数,例如:
"研究"
出现了5000 次"生命"
出现了3000 次词频是一个整数,代表出现次数。
词频概率,Word Probability, 是基于词频计算的相对概率,即:
P ( w ) = 词 w 的出现次数 所有词的总出现次数 P(w) = \frac{\text{词 w 的出现次数}}{\text{所有词的总出现次数}} P(w)=所有词的总出现次数词 w 的出现次数
例如:
假设所有词的总出现次数是1000万次,那么:
P ( " 研究 " ) = 5000 10000000 = 0.0005 P ( " 生命 " ) = 3000 10000000 = 0.0003 P("研究") = \frac{5000}{10000000} = 0.0005 \\ P("生命") = \frac{3000}{10000000} = 0.0003 P("研究")=100000005000=0.0005P("生命")=100000003000=0.0003
如果直接用词频数值(如5000、3000)来计算联合概率,会遇到尺度不统一的问题,导致一些高频词被过度偏好。
所以,更多的我们使用词频概率作为分词的参考值。
Term Frequency-Inverse Document Frequency,TF-IDF,词频-逆文档频率。
词频-逆文档频率是一种常用的文本特征提取方法,用于衡量单词在文档中的重要性,特别适用于关键词提取、搜索引擎排名、文本分类等任务。
词频,Term Frequency,TF,表示一个词在文档中出现的频率,公式:
TF ( t , d ) = 词 t 在文档 d 中出现的次数 文档 d 中所有词的总数 \text{TF}(t, d) = \frac{\text{词 } t \text{ 在文档 } d \text{ 中出现的次数}}{\text{文档 } d \text{ 中所有词的总数}} TF(t,d)=文档 d 中所有词的总数词 t 在文档 d 中出现的次数
逆文档频率,Inverse Document Frequency,用于衡量一个词在整个语料库中的普遍重要性,公式:
IDF ( t , D ) = log ( 语料库中文档总数 包含词 t 的文档数 + 1 ) \text{IDF}(t, D) = \log \left( \frac{\text{语料库中文档总数}}{\text{包含词 } t \text{ 的文档数} + 1} \right) IDF(t,D)=log(包含词 t 的文档数+1语料库中文档总数)
TF-IDF是TF和IDF的乘积,公式:
TF-IDF ( t , d , D ) = TF ( t , d ) × IDF ( t , D ) \text{TF-IDF}(t, d, D) = \text{TF}(t, d) \times \text{IDF}(t, D) TF-IDF(t,d,D)=TF(t,d)×IDF(t,D)
语料库:
文档1:我爱自然语言处理
文档2:自然语言处理很有趣
文档3:我爱编程
计算词“自然语言”在文档1中的 TF-IDF 值:
计算 TF:
计算 IDF:
计算TF-IDF:
优点:
简单有效,易于理解和实现。
能够突出文档中的关键词。
适用于大多数文本挖掘任务。
缺点:
无法捕捉词与词之间的关系(如语义信息)。
对短文本效果较差。
无法处理一词多义和多词一义的问题。
可以使用 sklearn
库计算 TF-IDF:
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
# 示例文档
documents = ["我爱自然语言处理", "自然语言处理很有趣", "我爱编程"]
# 自定义全模式分词函数
jieba.add_word("我爱")
def jieba_tokenizer(text):
return " ".join(jieba.cut(text))
# 使用全模式进行分词
tokenized_documents = [jieba_tokenizer(doc) for doc in documents]
# 初始化 TF-IDF 向量化器
vectorizer = TfidfVectorizer()
# 计算 TF-IDF 值
tfidf_matrix = vectorizer.fit_transform(tokenized_documents)
# 获取词汇表
feature_names = vectorizer.get_feature_names_out()
# 打印 TF-IDF 结果
df = pd.DataFrame(tfidf_matrix.toarray(), columns=feature_names)
print(df)
输出:
处理 我爱 有趣 编程 自然语言
0 0.577350 0.577350 0.000000 0.000000 0.577350
1 0.517856 0.000000 0.680919 0.000000 0.517856
2 0.000000 0.605349 0.000000 0.795961 0.000000
Directed Acyclic Graph,DAG。
有向无环图是图论中的一种数据结构,由顶点Vertices和边Edges组成,其中:
假设字典中包含:"研究"
"研究生"
"生命"
"生"
"命"
"起源"
import jieba
text = "研究生命起源"
dag = jieba.get_DAG(text) # 获取 DAG
print(dag)
示例输出:
{0: [0, 1, 2], 1: [1], 2: [2, 3], 3: [3], 4: [4, 5], 5: [5]}
文本:"研究生命起源"
索引: 0 1 2 3 4 5
字符: 研 究 生 命 起 源
具体解释
0: [0, 1, 2]
0
处的 "研"
可以是一个单独的词 → 0 → 0
("研"
)0
到 1
形成 "研究"
→ 0 → 1
("研究"
)0
到 2
形成 "研究生"
→ 0 → 2
("研究生"
) 1: [1]
1
处的 "究"
只能单独成词 → 1 → 1
("究"
) 2: [2, 3]
2
处的 "生"
可以是一个单独的词 → 2 → 2
("生"
)2
到 3
形成 "生命"
→ 2 → 3
("生命"
) 3: [3]
3
处的 "命"
只能单独成词 → 3 → 3
("命"
) 4: [4, 5]
4
处的 "起"
可以是一个单独的词 → 4 → 4
("起"
)4
到 5
形成 "起源"
→ 4 → 5
("起源"
) 5: [5]
5
处的 "源"
只能单独成词 → 5 → 5
("源"
)可视化 DAG
从 DAG 的角度看,可以画出一张图:
研 → 究 → 生 → 命 → 起 → 源
| | | | | |
v v v v v v
研 究 生 命 起 源 (单字成词)
|____|
研究
|________|
研究生
|____|
生命
|____|
起源
**路径示例:**可能的分词方案
["研究生", "命", "起源"]
["研究", "生命", "起源"]
["研", "究", "生命", "起源"]
分词非常重要,但中文分词面临一些独特的挑战:
中文中存在大量歧义切分问题。例如:
“结婚的和尚未结婚的”可以切分为:
- 结婚/的/和/尚未/结婚/的
- 结婚/的/和尚/未/结婚/的
未登录词(Out-of-Vocabulary, OOV)是指未出现在分词词典中的词汇,如新词、专有名词、网络用语等。
解决思路:
中文分词的标准尚未完全统一,不同任务可能需要不同的分词粒度。例如:
“自然语言处理”可以切分为:
- 细粒度:自然/语言/处理
- 粗粒度:自然语言/处理
分词的方法比较多,我们这里认知一下。
采用人工设定的词典和规则进行匹配,如正向最大匹配法(FMM)、逆向最大匹配(RMM)、双向最大匹配(BMM)。
ForwardMaxMatch
最大匹配法基本步骤如下:
逆向最大匹配法则是从后往前匹配:
双向最大匹配法则是正向、逆向都做一次,选择结果比较好的那个
在减少歧义问题上,逆向最大匹配法是效果比较好的:
“他是研究生物化学的”的不同的匹配法结果:
- FMM:他/是/研究生/物化/学/的
- RMM:他/是/研究/生物/化学/的
RMM更符合汉语的语义结构,因为汉语中心词多在词的右面。
在词典完备、没有任何其它知识的条件下,实验对比如下:
逆向最大匹配法在处理未登录词时表现更好,因为它更倾向于将未登录词切分为已知的右侧词汇。
采用统计模型对文本进行分词,如隐马尔可夫模型(HMM)、最大熵模型(ME)。
Mutual Information,MI
互信息衡量的是两个字符或子词同时出现的概率,可以理解为它们之间的“黏合度”:
M I ( x , y ) = log 2 P ( x , y ) P ( x ) P ( y ) MI(x, y) = \log_2 \frac{P(x, y)}{P(x)P(y)} MI(x,y)=log2P(x)P(y)P(x,y)
其中:
人工智能正在改变世界。
如果统计出的概率如下:
那么:
M I ( 人工 , 智能 ) = log 2 P ( 人工智能 ) P ( 人工 ) × P ( 智能 ) = log 2 0.04 0.05 × 0.04 = log 2 0.04 0.002 = log 2 20 ≈ 4.32 MI(人工, 智能) = \log_2 \frac{P(人工智能)}{P(人工) \times P(智能)} \\ = \log_2 \frac{0.04}{0.05 \times 0.04} = \log_2 \frac{0.04}{0.002} = \log_2 20 \approx 4.32 MI(人工,智能)=log2P(人工)×P(智能)P(人工智能)=log20.05×0.040.04=log20.0020.04=log220≈4.32
M I MI MI 值较高(远大于 0),说明"人工智能"是一个 高关联短语 ,应被合并成一个词。
如果换成随机组合的字:
计算:
M I ( 人工 , 出错 ) = log 2 0.0001 0.05 × 0.01 = log 2 0.2 ≈ − 2.32 MI(人工, 出错) = \log_2 \frac{0.0001}{0.05 \times 0.01} = \log_2 0.2 \approx -2.32 MI(人工,出错)=log20.05×0.010.0001=log20.2≈−2.32
M I MI MI 值较小(接近0或为负),说明 “人工出错” 之间 没有太强的联系,不应分为一个词。
采用神经网络,如LSTM/GRU+CRF、BERT等预训练模型。