897 lines
28 KiB
Markdown
897 lines
28 KiB
Markdown
# 📚 3-2-1 文本数据处理导论
|
||
|
||
---
|
||
|
||
# 🎯 本章学习目标
|
||
|
||
| 目标 | 内容 |
|
||
|------|------|
|
||
| **理解** | 什么是文本数据,以及计算机如何读取文本 |
|
||
| **掌握** | 为什么文本不能直接用于计算机计算 |
|
||
| **理解** | 向量、相似度的基本概念(零基础讲解) |
|
||
| **掌握** | 文本向量化的核心思想与数学原理 |
|
||
| **了解** | 从 BoW → TF-IDF → Embedding 的演进逻辑 |
|
||
|
||
---
|
||
|
||
# 📖 第一部分:什么是文本数据?
|
||
|
||
## 1.1 文本数据的定义
|
||
|
||
**文本数据**是由文字、符号组成的序列信息,是人类语言在计算机中的表示形式。
|
||
|
||
### 文本数据的例子
|
||
|
||
```
|
||
一句话:"今天天气真好"
|
||
一篇文章:一篇新闻报道
|
||
一条评论:"这家餐厅的菜太好吃了!"
|
||
一段对话:"你好,请问这本书多少钱?"
|
||
一首诗:"床前明月光,疑是地上霜"
|
||
```
|
||
|
||
### 文本数据的特征
|
||
|
||
| 特征 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| **离散符号** | 由离散的字符/词组成 | "hello" 由 h,e,l,l,o 这5个字符组成 |
|
||
| **序列性** | 符号按特定顺序排列 | "我爱你" ≠ "你爱我" |
|
||
| **语义丰富** | 同样的词不同场景意思不同 | "苹果"可以是水果或手机品牌 |
|
||
| **上下文相关** | 词的意思依赖上下文 | "他打了猫,猫跑了" 中两个"猫"意思相同 |
|
||
|
||
## 1.2 计算机如何"读取"文本?
|
||
|
||
### 对比:图像 vs 文本
|
||
|
||
**图像数据的读取:**
|
||
|
||
```
|
||
图像文件(.jpg/.png)
|
||
↓
|
||
计算机读取像素值
|
||
↓
|
||
存储为3维矩阵 [高度, 宽度, 通道]
|
||
↓
|
||
一张 1920×1080 的彩色图 = 1920 × 1080 × 3 = 6,220,800 个数字
|
||
```
|
||
|
||
**文本数据的读取:**
|
||
|
||
```
|
||
文本文件(.txt/.md)
|
||
↓
|
||
计算机读取字符编码(ASCII/UTF-8)
|
||
↓
|
||
存储为字符序列(每个字符是一个数字编码)
|
||
↓
|
||
"Python" → [80, 121, 116, 104, 111](ASCII编码)
|
||
```
|
||
|
||
### 字符编码:用数字表示字符
|
||
|
||
计算机并不能直接"认识"字符,它只认识数字。所以需要一种**映射规则**把字符变成数字:
|
||
|
||
```
|
||
ASCII编码(英文):
|
||
'A' → 65, 'B' → 66, ..., 'Z' → 90
|
||
'a' → 97, 'b' → 98, ..., 'z' → 122
|
||
'0' → 48, '1' → 49, ..., '9' → 57
|
||
|
||
UTF-8编码(支持中文):
|
||
'中' → 20013, '文' → 25991, 'P' → 80, 'y' → 121
|
||
```
|
||
|
||
### 文本的"存储形式"
|
||
|
||
```python
|
||
# 文本在计算机中的存储方式
|
||
text = "Hello"
|
||
|
||
# 如果我们看它的"数字形式":
|
||
print([ord(c) for c in text])
|
||
# 输出: [72, 101, 108, 108, 111]
|
||
# 72='H', 101='e', 108='l', 111='o'
|
||
|
||
# 中文例子
|
||
text_cn = "你好"
|
||
print([ord(c) for c in text_cn])
|
||
# 输出: [20320, 22909]
|
||
# 20320='你', 22909='好'
|
||
```
|
||
|
||
## 1.3 计算机擅长什么?不擅长什么?
|
||
|
||
### 计算机擅长的任务
|
||
|
||
```
|
||
✅ 数字计算:1 + 2 = 3
|
||
✅ 逻辑判断:if (a > b) then ...
|
||
✅ 矩阵运算:图像卷积、矩阵乘法
|
||
✅ 精确匹配:字符串完全相同比较
|
||
✅ 模式识别:符合规则的数据查找
|
||
```
|
||
|
||
### 计算机不擅长的任务
|
||
|
||
```
|
||
❌ 语义理解:计算机不知道"今天天气真好"是好心情还是讽刺
|
||
❌ 情感判断:计算机不知道"真是绝了"是夸人还是骂人
|
||
❌ 模糊推理:"大概"、"也许"、"差不多"无法精确处理
|
||
❌ 创意创作:写诗、写小说、编笑话
|
||
❌ 常识理解:"水往低处流"这种常识计算机不懂
|
||
```
|
||
|
||
### 为什么计算机不擅长理解文本?
|
||
|
||
**原因一:文本是"符号",不是"数值"**
|
||
|
||
```
|
||
计算机大脑 = 计算器(专门处理数字)
|
||
文本 = 一堆符号(对计算机来说就像乱码)
|
||
|
||
数字:1, 2, 3, 100.5, -7 → 计算机直接能算
|
||
文本:"好"、"bad"、"hello" → 计算机不知道啥意思
|
||
```
|
||
|
||
**原因二:语义不是显式表达的**
|
||
|
||
```
|
||
文本:"他今天心情不太好,因为下雨了"
|
||
|
||
计算机看到:[他, 今天, 心情, 不, 好, 因为, 下雨, 了]
|
||
↓
|
||
人类理解:他在不开心,因为外面下雨了(影响心情)
|
||
↓
|
||
计算机:???不理解下雨和心情的因果关系
|
||
```
|
||
|
||
**原因三:同样的符号,不同的语境,不同的意思**
|
||
|
||
```
|
||
"苹果真好吃"
|
||
→ 说的是水果
|
||
|
||
"苹果手机真贵"
|
||
→ 说的是手机品牌
|
||
|
||
计算机怎么知道?因为有上下文!
|
||
但计算机理解上下文的能力很弱
|
||
```
|
||
|
||
---
|
||
|
||
# 📖 第二部分:向量基础入门(零基础科普)
|
||
|
||
## 2.1 什么是向量?
|
||
|
||
### 向量的直观理解
|
||
|
||
**向量 = 有方向的量**
|
||
|
||
```
|
||
在日常生活中:
|
||
・速度:每小时60公里,向北走
|
||
・力:10牛顿,向右推
|
||
・风向:东南风,每秒5米
|
||
|
||
这些都是有"方向"和"大小"的量,就是向量!
|
||
```
|
||
|
||
### 向量在数学中的表示
|
||
|
||
**一维向量(数轴上的点):**
|
||
|
||
```
|
||
←———————————|———————————→
|
||
-3 -2 -1 0 1 2 3
|
||
|
||
点A在位置 2 → 向量A = [2]
|
||
点B在位置 -3 → 向量B = [-3]
|
||
```
|
||
|
||
**二维向量(平面上的点):**
|
||
|
||
```
|
||
y
|
||
↑
|
||
|
|
||
3 | * A(2,3)
|
||
|
|
||
2 |
|
||
|
|
||
1 | * B(4,1)
|
||
|
|
||
0---+—————————————→ x
|
||
0 1 2 3 4 5
|
||
|
||
向量A = [2, 3] (横坐标2,纵坐标3)
|
||
向量B = [4, 1]
|
||
```
|
||
|
||
**三维向量(立体空间):**
|
||
|
||
```
|
||
z
|
||
↑ * C(1,2,3)
|
||
| /
|
||
| /
|
||
| /
|
||
|/__________→ y
|
||
/
|
||
/
|
||
/_________→ x
|
||
(0,0,0)
|
||
|
||
向量C = [1, 2, 3]
|
||
```
|
||
|
||
### Python中创建向量
|
||
|
||
```python
|
||
import numpy as np
|
||
|
||
# 一维向量
|
||
v1 = np.array([3]) # 只有1个数字
|
||
print(f"v1 = {v1}")
|
||
|
||
# 二维向量
|
||
v2 = np.array([2, 3]) # 2个数字,表示平面上的一个点
|
||
print(f"v2 = {v2}")
|
||
|
||
# 三维向量
|
||
v3 = np.array([1, 2, 3]) # 3个数字,表示立体空间的一个点
|
||
print(f"v3 = {v3}")
|
||
|
||
# 更多维向量(机器学习中常用)
|
||
v100 = np.array([0.1, 0.5, -0.3, 0.8, ...]) # 100维!
|
||
print(f"v100有 {len(v100)} 个元素")
|
||
```
|
||
|
||
## 2.2 向量的基本运算
|
||
|
||
### 加法和减法
|
||
|
||
```python
|
||
import numpy as np
|
||
|
||
# 向量加法:对应位置相加
|
||
a = np.array([1, 2, 3])
|
||
b = np.array([4, 5, 6])
|
||
c = a + b # [1+4, 2+5, 3+6] = [5, 7, 9]
|
||
|
||
print(f"a + b = {c}") # [5, 7, 9]
|
||
|
||
# 直观理解:
|
||
# a = [1, 2, 3] 从原点出发走1步、再走2步、再走3步
|
||
# b = [4, 5, 6] 从原点出发走4步、再走5步、再走6步
|
||
# a + b = 从原点走完a再走b = [5, 7, 9]
|
||
```
|
||
|
||
### 数乘(标量乘法)
|
||
|
||
```python
|
||
# 向量乘以一个数字(标量)
|
||
v = np.array([1, 2, 3])
|
||
result = v * 2 # [1*2, 2*2, 3*2] = [2, 4, 6]
|
||
|
||
print(f"v * 2 = {result}") # [2, 4, 6]
|
||
|
||
# 直观理解:
|
||
# v = [1, 2, 3] 表示"方向"
|
||
# v * 2 = [2, 4, 6] 方向不变,长度变成2倍
|
||
```
|
||
|
||
### 向量的长度(模/范数)
|
||
|
||
```python
|
||
# 向量的长度 = 从原点到终点的距离
|
||
v = np.array([3, 4])
|
||
|
||
# 用勾股定理:3² + 4² = 25,√25 = 5
|
||
length = np.linalg.norm(v)
|
||
print(f"向量 [3, 4] 的长度 = {length}") # 5.0
|
||
|
||
# 另一个例子
|
||
v2 = np.array([1, 1])
|
||
length2 = np.linalg.norm(v2)
|
||
print(f"向量 [1, 1] 的长度 = {length2:.2f}") # 1.41
|
||
```
|
||
|
||
## 2.3 点积(Dot Product)— 最重要的运算
|
||
|
||
### 什么是点积?
|
||
|
||
**点积 = 对应位置相乘,再求和**
|
||
|
||
```python
|
||
# 两个向量对应位置相乘,然后加起来
|
||
a = np.array([1, 2, 3])
|
||
b = np.array([4, 5, 6])
|
||
|
||
# 点积计算过程:
|
||
# 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
|
||
|
||
dot = np.dot(a, b)
|
||
print(f"点积 = {dot}") # 32
|
||
|
||
# 或者用 @ 运算符
|
||
print(f"a @ b = {a @ b}") # 32
|
||
```
|
||
|
||
### 点积的直观理解
|
||
|
||
```
|
||
点积 = a的长度 × b的长度 × cos(夹角)
|
||
|
||
如果 a 和 b 方向相同:夹角 = 0°,cos(0) = 1,点积 = |a|×|b|(最大)
|
||
如果 a 和 b 垂直: 夹角 = 90°,cos(90) = 0,点积 = 0(最小)
|
||
如果 a 和 b 相反: 夹角 = 180°,cos(180) = -1,点积 = -|a|×|b|(负最大)
|
||
```
|
||
|
||
## 2.4 余弦相似度 — 用点积判断"像不像"
|
||
|
||
### 什么是相似度?
|
||
|
||
**相似度 = 两个向量有多"像"**
|
||
|
||
```
|
||
相似度高的例子:
|
||
・"猫"和"狗":都是动物,都四只脚,都会叫
|
||
・"红色"和"黄色":都是颜色,都是暖色调
|
||
・"跑步"和"游泳":都是运动
|
||
|
||
相似度低的例子:
|
||
・"猫"和"石头":一个是动物,一个不是
|
||
・"热"和"冷":意思相反
|
||
・"太阳"和"细菌":几乎没有共同点
|
||
```
|
||
|
||
### 余弦相似度公式
|
||
|
||
```
|
||
A · B
|
||
cos(θ) = ──────────
|
||
|A| × |B|
|
||
|
||
・A · B = 向量A和B的点积
|
||
・|A| = 向量A的长度
|
||
・|B| = 向量B的长度
|
||
・cos(θ) = 相似度,范围是 [-1, 1]
|
||
```
|
||
|
||
### 余弦相似度的值代表什么?
|
||
|
||
| cos(θ) 值 | 夹角 θ | 相似程度 | 示例 |
|
||
|----------|--------|---------|------|
|
||
| 1.0 | 0° | 完全相同 | 同一向量 |
|
||
| 0.8~0.99 | 0~37° | 非常相似 | "猫" vs "狗" |
|
||
| 0.5~0.8 | 0~60° | 比较相似 | "跑步" vs "运动" |
|
||
| 0.3~0.5 | 60~72° | 有些相似 | "苹果" vs "水果" |
|
||
| 0 | 90° | 毫不相关 | "猫" vs "石头" |
|
||
| -1.0 | 180° | 完全相反 | "高" vs "矮" |
|
||
|
||
### Python计算余弦相似度
|
||
|
||
```python
|
||
import numpy as np
|
||
|
||
def cosine_similarity(a, b):
|
||
"""计算余弦相似度"""
|
||
dot = np.dot(a, b) # 点积
|
||
norm_a = np.linalg.norm(a) # 向量a的长度
|
||
norm_b = np.linalg.norm(b) # 向量b的长度
|
||
return dot / (norm_a * norm_b)
|
||
|
||
# 例子1:方向完全相同的向量
|
||
a = np.array([1, 2, 3])
|
||
b = np.array([2, 4, 6]) # b是a的两倍,方向完全相同
|
||
print(f"相似度 = {cosine_similarity(a, b):.3f}") # 1.000
|
||
|
||
# 例子2:方向完全相反的向量
|
||
a = np.array([1, 2, 3])
|
||
b = np.array([-1, -2, -3]) # b是a的相反方向
|
||
print(f"相似度 = {cosine_similarity(a, b):.3f}") # -1.000
|
||
|
||
# 例子3:垂直的向量
|
||
a = np.array([1, 0])
|
||
b = np.array([0, 1])
|
||
print(f"相似度 = {cosine_similarity(a, b):.3f}") # 0.000
|
||
|
||
# 例子4:日常生活中的"相似"
|
||
print("\n=== 语义相似度示例 ===")
|
||
# 假设这些是词的"意义向量"(简化版)
|
||
# 维度:[是否是动物, 是否有生命, 是否能移动]
|
||
cat = np.array([0.9, 0.9, 0.8]) # 猫:动物,有生命,能移动
|
||
dog = np.array([0.8, 0.9, 0.8]) # 狗:动物,有生命,能移动
|
||
apple = np.array([0.1, 0.3, 0.0]) # 苹果:植物,略有生命,不能移动
|
||
|
||
print(f"猫 vs 狗: {cosine_similarity(cat, dog):.3f}") # 非常接近1
|
||
print(f"猫 vs 苹果: {cosine_similarity(cat, apple):.3f}") # 接近0
|
||
```
|
||
|
||
---
|
||
|
||
# 📖 第三部分:文本向量化的核心思想
|
||
|
||
## 3.1 核心目标:把所有文本变成"向量"
|
||
|
||
```
|
||
文本(符号) → 数值向量 → 计算机可以计算 → AI模型处理
|
||
```
|
||
|
||
**为什么必须是向量?**
|
||
|
||
```
|
||
因为计算机擅长:
|
||
・向量加减:v1 + v2 = ?
|
||
・向量点积:v1 · v2 = ?
|
||
・向量距离:||v1 - v2|| = ?
|
||
・余弦相似度:cos(θ) = ?
|
||
|
||
但计算机不擅长:
|
||
・字符串比较:"Python" == "Java" ?
|
||
・词语推理:"猫" 类似于 "狗" ?
|
||
```
|
||
|
||
**文本向量化的意义:**
|
||
|
||
```
|
||
"猫"和"狗"在文本中可能完全不相关
|
||
但如果我们知道它们都是"动物",向量就会接近
|
||
计算机就能"理解"它们的相似性了!
|
||
```
|
||
|
||
## 3.2 向量化示例:从"词"到"数"
|
||
|
||
### 简单例子:把词变成向量(位置编码)
|
||
|
||
```python
|
||
# 假设我们有一个很小的词汇表(只有5个词)
|
||
vocab = ["猫", "狗", "鱼", "苹果", "香蕉"]
|
||
|
||
# 位置编码:每个词对应一个位置
|
||
# "猫" → [1, 0, 0, 0, 0] # 第1个位置是1,其他是0
|
||
# "狗" → [0, 1, 0, 0, 0] # 第2个位置是1,其他是0
|
||
# "苹果" → [0, 0, 0, 1, 0] # 第4个位置是1,其他是0
|
||
```
|
||
|
||
**问题**:这只是"位置编码",没有语义信息!
|
||
|
||
```
|
||
"猫" = [1, 0, 0, 0, 0]
|
||
"狗" = [0, 1, 0, 0, 0]
|
||
|
||
余弦相似度 = 0 (完全不相似)
|
||
|
||
但实际上"猫"和"狗"都是动物,应该很相似!
|
||
```
|
||
|
||
### 更智能的例子:语义向量
|
||
|
||
```python
|
||
# 语义编码:每个词用"含义"来表示
|
||
# 维度:[动物性, 植物性, 可食用性, 宠物性]
|
||
|
||
cat = np.array([0.9, 0.1, 0.7, 0.9]) # 猫:动物性高,可食用(猫肉?),是宠物
|
||
dog = np.array([0.8, 0.2, 0.6, 0.9]) # 狗:动物性高,可食用(狗肉?),是宠物
|
||
apple = np.array([0.1, 0.9, 0.9, 0.0]) # 苹果:植物性高,可食用,不是宠物
|
||
|
||
# 计算相似度
|
||
print(f"猫 vs 狗: {cosine_similarity(cat, dog):.3f}") # ≈ 0.97(很相似!)
|
||
print(f"猫 vs 苹果: {cosine_similarity(cat, apple):.3f}") # ≈ 0.15(不太相似)
|
||
```
|
||
|
||
**这就是文本向量化的威力:把"语义"变成"可计算的数值"!**
|
||
|
||
## 3.3 向量化方法演进
|
||
|
||
### 演进概览
|
||
|
||
```
|
||
文本向量化的三种主要方法:
|
||
|
||
[BoW] ───→ [TF-IDF] ───→ [Word Embedding]
|
||
(词袋模型) (词频权重) (词向量嵌入)
|
||
|
||
简单粗暴 加入词重要性 蕴含语义信息
|
||
无语义 部分语义 深度语义
|
||
```
|
||
|
||
### BoW(词袋模型)—— 最简单的方法
|
||
|
||
**原理**:把文本看成"一袋词",不考虑顺序,只管词出现了几次。
|
||
|
||
```
|
||
文本1: "Python 是 编程 语言"
|
||
文本2: "Java 是 编程 语言"
|
||
|
||
词表: [Python, Java, 是, 编程, 语言]
|
||
```
|
||
|
||
**向量化:**
|
||
|
||
```python
|
||
from sklearn.feature_extraction.text import CountVectorizer
|
||
|
||
# 文档集合
|
||
docs = [
|
||
"Python 是 编程 语言",
|
||
"Java 是 编程 语言",
|
||
]
|
||
|
||
# BoW 向量化
|
||
vectorizer = CountVectorizer()
|
||
bow_matrix = vectorizer.fit_transform(docs)
|
||
|
||
print("词表:", vectorizer.get_feature_names_out())
|
||
# 输出: ['Python', 'Java', '是', '编程', '语言']
|
||
|
||
print("BoW矩阵:")
|
||
print(bow_matrix.toarray())
|
||
# 输出:
|
||
# [[1 0 1 1 1] # Python文档: Python=1, Java=0, 是=1, 编程=1, 语言=1
|
||
# [0 1 1 1 1]] # Java文档: Python=0, Java=1, 是=1, 编程=1, 语言=1
|
||
```
|
||
|
||
### BoW 的优缺点
|
||
|
||
| 优点 | 缺点 |
|
||
|------|------|
|
||
| 简单直观 | 忽略词序 |
|
||
| 容易实现 | "我爱你"和"你爱我"向量完全相同 |
|
||
| 计算速度快 | 所有词同等重要 |
|
||
| 适合基线模型 | 无法捕捉语义 |
|
||
|
||
### TF-IDF —— 加入词的重要性
|
||
|
||
**问题**:BoW 中"Python"和"的"权重相同,这不合理!
|
||
|
||
**TF-IDF = 词频(TF) × 逆文档频率(IDF)**
|
||
|
||
```
|
||
TF = 这个词在本文中出现了多少次
|
||
IDF = 这个词在所有文档中多不多(越多越不重要)
|
||
|
||
TF-IDF = TF × IDF
|
||
```
|
||
|
||
**为什么有效?**
|
||
|
||
```
|
||
・高频出现 ≠ 重要
|
||
"的"在所有文章都出现 → TF高, IDF低 → TF-IDF低 ❌ 停用词
|
||
|
||
・罕见词 ≠ 不重要
|
||
"TensorFlow"只在AI文章出现 → TF低, IDF高 → TF-IDF高 ✅ 重要词
|
||
|
||
・既高频又独特 = 真正重要的词
|
||
```
|
||
|
||
**TF-IDF 示例:**
|
||
|
||
```python
|
||
from sklearn.feature_extraction.text import TfidfVectorizer
|
||
|
||
docs = [
|
||
"Python 编程 语言",
|
||
"Python Python Python", # Python出现3次
|
||
"Java 编程 语言",
|
||
]
|
||
|
||
tfidf_vectorizer = TfidfVectorizer()
|
||
tfidf_matrix = tfidf_vectorizer.fit_transform(docs)
|
||
|
||
print("词表:", tfidf_vectorizer.get_feature_names_out())
|
||
print("\nTF-IDF矩阵:")
|
||
print(tfidf_matrix.toarray())
|
||
|
||
# 观察:Python在第2篇文档中出现3次,但TF-IDF值不是最高的
|
||
# 因为"Python"在所有文档都出现了,IDF值较低
|
||
```
|
||
|
||
### Word Embedding(词嵌入)—— 蕴含语义
|
||
|
||
**BoW 和 TF-IDF 的根本问题**
|
||
|
||
```
|
||
"猫" → [1, 0, 0, ...] # 只是"位置编码"
|
||
"狗" → [0, 1, 0, ...] # 猫和狗的位置不同
|
||
"小猫" → [0, 0, 1, ...] # 但它们语义相近,向量却正交!
|
||
```
|
||
|
||
**问题**:无法表达语义相似性!
|
||
|
||
**Embedding 的思想**
|
||
|
||
```
|
||
不再用"位置"表示词,而是用"语义空间"表示词
|
||
|
||
语义空间中的位置:
|
||
↑
|
||
动物 植物
|
||
| ↑ 猫 ↑ 狗 ↑ 苹果
|
||
| ↗ ↗ ↑
|
||
| ↗ ↗ ← 语义相近的词距离近 →
|
||
| ↗ ↗ →
|
||
|——————————————————————————————————————→
|
||
0 抽象 具体
|
||
```
|
||
|
||
**词嵌入的效果**
|
||
|
||
```python
|
||
# 假设我们用预训练模型得到了词的语义向量
|
||
# 实际中向量通常是 50/100/300 维,这里用3维举例
|
||
|
||
word_vectors = {
|
||
"猫": [0.9, 0.1, 0.2], # 动物属性高
|
||
"狗": [0.8, 0.3, 0.1], # 动物属性高
|
||
"苹果": [0.1, 0.2, 0.9], # 水果属性高
|
||
"Python": [0.1, 0.0, 0.9], # 编程属性高
|
||
"Java": [0.1, 0.0, 0.85], # 编程属性高
|
||
}
|
||
|
||
print("=== 语义相似度 ===")
|
||
print(f"猫 vs 狗: {cosine_similarity(word_vectors['猫'], word_vectors['狗']):.3f}")
|
||
# 输出: 猫 vs 狗: 0.972(非常相似!都是动物)
|
||
|
||
print(f"猫 vs 苹果: {cosine_similarity(word_vectors['猫'], word_vectors['苹果']):.3f}")
|
||
# 输出: 猫 vs 苹果: 0.149(不太相似!)
|
||
|
||
print(f"Python vs Java: {cosine_similarity(word_vectors['Python'], word_vectors['Java']):.3f}")
|
||
# 输出: Python vs Java: 0.998(非常相似!都是编程语言)
|
||
```
|
||
|
||
---
|
||
|
||
# 📖 第四部分:文本处理的完整流程
|
||
|
||
## 4.1 流程图
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 文本数据 │
|
||
│ "今天天气真不错!" │
|
||
└─────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 1. 文本预处理 │
|
||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||
│ │ 分词 │→ │ 去停用词│→ │ 统一大小│→ │ 去除标点│ │
|
||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||
│ "今天/天气/真/不错" → "今天/天气/不错" │
|
||
└─────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 2. 文本向量化 │
|
||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||
│ │ BoW │ │ TF-IDF │ │ Embedding│ │ 预训练模型│ │
|
||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||
│ ↓ ↓ ↓ ↓ │
|
||
│ [1,0,2,0,1] [0.5,0,0.8] [0.9,0.3] [BERT向量] │
|
||
└─────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 3. 下游任务 │
|
||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||
│ │ 分类 │ │ 相似度 │ │ 聚类 │ │ 生成 │ │
|
||
│ │ 情感分析│ │ 文本匹配│ │ 主题分组│ │ 聊天机器人│ │
|
||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 4.2 各环节详解
|
||
|
||
### 环节1:文本预处理
|
||
|
||
**为什么需要预处理?**
|
||
|
||
```
|
||
原始文本:
|
||
"今天天气真不错!!Python是一门很棒的语言,python也很重要!!!"
|
||
|
||
预处理后:
|
||
["今天", "天气", "不错", "Python", "语言"]
|
||
```
|
||
|
||
**预处理步骤:**
|
||
|
||
| 步骤 | 输入 | 输出 | 作用 |
|
||
|------|------|------|------|
|
||
| 分词 | "今天天气不错" | ["今天", "天气", "不错"] | 把文本切成词 |
|
||
| 去停用词 | ["今天", "天气", "不错"] | ["天气", "不错"] | 去掉"的、了、在"等无意义词 |
|
||
| 统一大小写 | ["Python", "python"] | ["python", "python"] | 归一化 |
|
||
| 去标点 | ["语言!!!"] | ["语言"] | 清理噪音 |
|
||
|
||
### 环节2:文本向量化
|
||
|
||
**选择向量化方法的原则:**
|
||
|
||
| 方法 | 适用场景 | 不适用场景 |
|
||
|------|---------|-----------|
|
||
| BoW | 基线模型、快速原型 | 需要语义理解 |
|
||
| TF-IDF | 文本分类、关键词提取 | 同义词识别 |
|
||
| Embedding | 语义相似度、推荐系统 | 需要精确匹配 |
|
||
| 预训练模型 | 通用NLP任务 | 计算资源有限 |
|
||
|
||
### 环节3:下游任务
|
||
|
||
```
|
||
分类任务:
|
||
"这部电影太好看了!" → [正面, 0.95] → 正面情感 ✅
|
||
|
||
相似度任务:
|
||
"如何学习Python?" → 找到相似的:"Python入门教程" ✅
|
||
|
||
生成任务:
|
||
"今天天气" → 续写:"今天天气真好,适合出去玩" ✅
|
||
```
|
||
|
||
---
|
||
|
||
# 📖 第五部分:工具生态概览
|
||
|
||
## 5.1 Python NLP 工具箱
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ 中文分词工具 │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ jieba(结巴) ・最流行的中文分词库 │
|
||
│ ・支持精确/全/搜索引擎模式 │
|
||
│ ・pip install jieba │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ HanLP ・功能强大,支持词性标注、命名实体识别 │
|
||
│ SnowNLP ・简单好用,专注文本处理 │
|
||
│ LTP ・哈工大出品,准确率高 │
|
||
└─────────────────────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ 英文NLP工具 │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ NLTK ・经典NLP库,教学首选 │
|
||
│ spaCy ・速度快,工业级 │
|
||
│ Stanford NLP ・学术标准,准确性高 │
|
||
└─────────────────────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ 文本向量化工具 │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ scikit-learn ・BoW、TF-IDF 实现 │
|
||
│ Gensim ・Word2Vec、Doc2Vec │
|
||
│ TensorFlow/PyTorch ・深度学习文本处理 │
|
||
│ transformers ・BERT、GPT 等预训练模型 │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 5.2 本课程使用的工具
|
||
|
||
| 工具 | 用途 | 安装命令 |
|
||
|------|------|---------|
|
||
| jieba | 中文分词 | `pip install jieba` |
|
||
| sklearn | TF-IDF、向量化 | `pip install scikit-learn` |
|
||
| numpy | 数值计算 | `pip install numpy` |
|
||
| matplotlib | 可视化 | `pip install matplotlib` |
|
||
|
||
---
|
||
|
||
# 📖 第六部分:本章知识地图
|
||
|
||
## 6.1 核心概念
|
||
|
||
```
|
||
文本数据处理
|
||
│
|
||
├── 核心问题:文本(符号) → 向量(数字)
|
||
│
|
||
├── 向量化方法
|
||
│ ├── BoW(词袋模型)
|
||
│ │ └── 核心:统计词频,忽略顺序
|
||
│ │
|
||
│ ├── TF-IDF(词频-逆文档频率)
|
||
│ │ └── 核心:词的重要性 × 词的独特性
|
||
│ │
|
||
│ └── Word Embedding(词嵌入)
|
||
│ └── 核心:用语义空间表示词
|
||
│
|
||
└── 处理流程
|
||
├── 文本预处理(分词、去停用词)
|
||
├── 向量化
|
||
└── 下游任务(分类、相似度、生成)
|
||
```
|
||
|
||
## 6.2 数学公式速查
|
||
|
||
| 方法 | 公式 | 含义 |
|
||
|------|------|------|
|
||
| 向量加法 | [1,2] + [3,4] = [4,6] | 对应位置相加 |
|
||
| 向量数乘 | 2 × [1,2] = [2,4] | 每个元素乘以标量 |
|
||
| 向量点积 | [1,2] · [3,4] = 11 | 对应相乘再求和 |
|
||
| 向量长度 | |[3,4]| = 5 | √(3²+4²) |
|
||
| 余弦相似度 | cos(θ) = (A·B) / (\|A\|×\|B\|) | 向量相似程度 |
|
||
|
||
---
|
||
|
||
# 📝 课后作业
|
||
|
||
## 第一部分:文本数据基础(1-2道)
|
||
|
||
### 题目1
|
||
在Python中,用两种方式表示"Hello":
|
||
1. 用 `ord()` 函数打印每个字符的ASCII码
|
||
2. 用 `chr()` 函数验证:字符65对应的是大写字母A
|
||
|
||
### 题目2
|
||
思考题:为什么计算机擅长处理图像矩阵,却不擅长处理文本?请从"数据的表示形式"和"语义理解"两个角度说明原因。
|
||
|
||
---
|
||
|
||
## 第二部分:向量基础(1-2道)
|
||
|
||
### 题目3
|
||
已知向量 A = [3, 4],B = [1, 2]:
|
||
1. 计算 A + B 的结果
|
||
2. 计算 2 × A 的结果
|
||
3. 计算 A 的长度(模)
|
||
|
||
### 题目4
|
||
有两个向量:A = [1, 2, 3],B = [4, 5, 6]
|
||
1. 计算它们的点积 A · B
|
||
2. 计算它们的余弦相似度
|
||
3. 如果 A = [1, 0],B = [0, 1],它们的余弦相似度是多少?为什么?
|
||
|
||
---
|
||
|
||
## 第三部分:文本向量化(1-2道)
|
||
|
||
### 题目5
|
||
假设有以下3个文档:
|
||
- Doc1: "Python 是 编程 语言"
|
||
- Doc2: "Java 是 编程 语言"
|
||
- Doc3: "Python Python Python"
|
||
|
||
使用BoW模型,词表是什么?每个文档的向量表示是什么?
|
||
|
||
### 题目6
|
||
思考题:BoW模型有哪些缺点?请至少列出2个,并说明为什么这些缺点在某些场景下会成为问题。
|
||
|
||
---
|
||
|
||
## 附加题(选做)
|
||
|
||
### 题目7
|
||
阅读以下代码,理解TF-IDF的工作原理:
|
||
|
||
```python
|
||
from sklearn.feature_extraction.text import TfidfVectorizer
|
||
|
||
docs = ["Python 编程", "Java 编程", "Python Python"]
|
||
tfidf = TfidfVectorizer()
|
||
matrix = tfidf.fit_transform(docs)
|
||
|
||
print("词表:", tfidf.get_feature_names_out())
|
||
print("TF-IDF矩阵:")
|
||
print(matrix.toarray())
|
||
```
|
||
|
||
运行代码并回答:
|
||
1. 为什么"Python"在Doc3中的TF-IDF值不是最高(假设Doc1和Doc2的值更小)?
|
||
2. "Java"在Doc2中的TF-IDF值是多少?解释原因。
|
||
|
||
---
|
||
|
||
# 🚀 下节预告
|
||
|
||
下一节我们将进入 **3-2-2:分词与文本清洗**,
|
||
学习:
|
||
- 如何用 jieba 进行中文分词
|
||
- 停用词的作用与过滤方法
|
||
- 代码实战:清洗豆瓣评论数据
|
||
|
||
---
|
||
|
||
> 🎯 **记住:文本向量化的核心目标是把"符号"变成"可计算的数值向量"!**
|