更新3-2-1文本数据处理导论(v2版本)

This commit is contained in:
2026-04-20 21:23:55 +08:00
parent 6698a3ac64
commit 35110a9522

756
README.md
View File

@@ -6,100 +6,414 @@
| 目标 | 内容 | | 目标 | 内容 |
|------|------| |------|------|
| **理解** | 什么文本不能直接用于计算机计算 | | **理解** | 什么文本数据,以及计算机如何读取文本 |
| **掌握** | 为什么文本不能直接用于计算机计算 |
| **理解** | 向量、相似度的基本概念(零基础讲解) |
| **掌握** | 文本向量化的核心思想与数学原理 | | **掌握** | 文本向量化的核心思想与数学原理 |
| **了解** | 从 BoW → TF-IDF → Embedding 的演进逻辑 | | **了解** | 从 BoW → TF-IDF → Embedding 的演进逻辑 |
| **认识** | 文本处理的完整流程框架 |
--- ---
# 📖 第一部分:什么文本处理这么难 # 📖 第一部分:什么文本数据
## 1.1 计算机的"语言障碍" ## 1.1 文本数据的定义
**计算机擅长什么?** **文本数据**是由文字、符号组成的序列信息,是人类语言在计算机中的表示形式。
### 文本数据的例子
``` ```
数字计算: 1 + 2 = 3 ✅ 一句话:"今天天气真好"
图像处理: 像素矩阵运算 ✅ 一篇文章:一篇新闻报道
逻辑判断: if A > B then ... ✅ 一条评论:"这家餐厅的菜太好吃了!"
一段对话:"你好,请问这本书多少钱?"
一首诗:"床前明月光,疑是地上霜"
``` ```
**计算机不擅长什么?** ### 文本数据的特征
| 特征 | 说明 | 示例 |
|------|------|------|
| **离散符号** | 由离散的字符/词组成 | "hello" 由 h,e,l,l,o 这5个字符组成 |
| **序列性** | 符号按特定顺序排列 | "我爱你" ≠ "你爱我" |
| **语义丰富** | 同样的词不同场景意思不同 | "苹果"可以是水果或手机品牌 |
| **上下文相关** | 词的意思依赖上下文 | "他打了猫,猫跑了" 中两个"猫"意思相同 |
## 1.2 计算机如何"读取"文本?
### 对比:图像 vs 文本
**图像数据的读取:**
``` ```
文本理解: 图像文件(.jpg/.png
"今天天气真好!" → ??? → 计算机无法直接"理解"
"Python是世界上最好的语言" → ??? → 计算机不知道这是什么意思 计算机读取像素值
存储为3维矩阵 [高度, 宽度, 通道]
一张 1920×1080 的彩色图 = 1920 × 1080 × 3 = 6,220,800 个数字
``` ```
**核心问题** **文本数据的读取**
> 计算机只能处理数字,**文本是符号**,符号不能直接用于计算。
## 1.2 文本 vs 图像:本质区别
``` ```
┌─────────────────────────────────────────────────────────┐ 文本文件(.txt/.md
│ 图像数据 │
├─────────────────────────────────────────────────────────┤ 计算机读取字符编码ASCII/UTF-8
📐 空间结构化数据 │
│ ・像素 = 数字0-255 存储为字符序列(每个字符是一个数字编码)
│ ・位置关系 = 空间关系(上下左右) │
│ ・相邻像素通常相关 │ "Python" → [80, 121, 116, 104, 111]ASCII编码
│ ・直接可以用矩阵表示 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 文本数据 │
├─────────────────────────────────────────────────────────┤
│ 📝 序列符号化数据 │
│ ・词语/字符 = 离散符号 │
│ ・位置关系 = 逻辑顺序(不是物理位置) │
│ ・符号本身无"数值含义" │
│ ・无法直接用数字运算 │
└─────────────────────────────────────────────────────────┘
``` ```
## 1.3 文本处理的核心挑战 ### 字符编码:用数字表示字符
### 挑战1符号到数字的转换 计算机并不能直接"认识"字符,它只认识数字。所以需要一种**映射规则**把字符变成数字:
``` ```
"Python" → ??? → [?, ?, ?, ...] 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
``` ```
### 挑战2一词多义 ### 文本的"存储形式"
``` ```python
"苹果" 可以指: # 文本在计算机中的存储方式
・一种水果(营养丰富) text = "Hello"
・一家公司Apple Inc.
・手机品牌(苹果手机) # 如果我们看它的"数字形式"
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='好'
``` ```
### 挑战3词序敏感 ## 1.3 计算机擅长什么?不擅长什么?
### 计算机擅长的任务
``` ```
"我爱你" vs "你爱我" ✅ 数字计算1 + 2 = 3
・词语完全相同 ✅ 逻辑判断if (a > b) then ...
・顺序不同 ✅ 矩阵运算:图像卷积、矩阵乘法
・意思完全相反 ✅ 精确匹配:字符串完全相同比较
✅ 模式识别:符合规则的数据查找
``` ```
### 挑战4同义表达 ### 计算机不擅长的任务
``` ```
"电脑" vs "计算机" vs "计算机器" ❌ 语义理解:计算机不知道"今天天气真好"是好心情还是讽刺
・不同符号 ❌ 情感判断:计算机不知道"真是绝了"是夸人还是骂人
・相同含义 ❌ 模糊推理:"大概"、"也许"、"差不多"无法精确处理
❌ 创意创作:写诗、写小说、编笑话
❌ 常识理解:"水往低处流"这种常识计算机不懂
```
### 为什么计算机不擅长理解文本?
**原因一:文本是"符号",不是"数值"**
```
计算机大脑 = 计算器(专门处理数字)
文本 = 一堆符号(对计算机来说就像乱码)
数字1, 2, 3, 100.5, -7 → 计算机直接能算
文本:"好"、"bad"、"hello" → 计算机不知道啥意思
```
**原因二:语义不是显式表达的**
```
文本:"他今天心情不太好,因为下雨了"
计算机看到:[他, 今天, 心情, 不, 好, 因为, 下雨, 了]
人类理解:他在不开心,因为外面下雨了(影响心情)
计算机:???不理解下雨和心情的因果关系
```
**原因三:同样的符号,不同的语境,不同的意思**
```
"苹果真好吃"
→ 说的是水果
"苹果手机真贵"
→ 说的是手机品牌
计算机怎么知道?因为有上下文!
但计算机理解上下文的能力很弱
``` ```
--- ---
# 📖 第二部分:文本向量化的核心思想 # 📖 第二部分:向量基础入门(零基础科普)
## 2.1 核心目标:把所有文本变成"向量" ## 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模型处理 文本(符号) → 数值向量 → 计算机可以计算 → AI模型处理
@@ -112,78 +426,66 @@
・向量加减v1 + v2 = ? ・向量加减v1 + v2 = ?
・向量点积v1 · v2 = ? ・向量点积v1 · v2 = ?
・向量距离:||v1 - v2|| = ? ・向量距离:||v1 - v2|| = ?
矩阵运算A × B = ? 余弦相似度cos(θ) = ?
但计算机不擅长: 但计算机不擅长:
・字符串比较:"Python" == "Java" ? ・字符串比较:"Python" == "Java" ?
・词语推理:"猫" 类似于 "狗" ? ・词语推理:"猫" 类似于 "狗" ?
``` ```
## 2.2 向量化示例:从"词"到"数" **文本向量化的意义:**
### 简单例子:把词变成向量 ```
"猫"和"狗"在文本中可能完全不相关
但如果我们知道它们都是"动物",向量就会接近
计算机就能"理解"它们的相似性了!
```
假设我们只有一个很小的词汇表: ## 3.2 向量化示例:从"词"到"数"
### 简单例子:把词变成向量(位置编码)
```python ```python
# 假设我们有一个很小的词汇表只有5个词
vocab = ["猫", "狗", "鱼", "苹果", "香蕉"] vocab = ["猫", "狗", "鱼", "苹果", "香蕉"]
# "猫" → [1, 0, 0, 0, 0] # 猫在这个词表中的位置 # 位置编码:每个词对应一个位置
# "" → [0, 1, 0, 0, 0] # 狗在这个词表中的位置 # "" → [1, 0, 0, 0, 0] # 第1个位置是1其他是0
# "苹果" → [0, 0, 0, 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 ```python
# 理想情况: # 语义编码:每个词用"含义"来表示
# "猫" → [0.9, 0.1, 0.2] # 语义:动物、毛茸茸、会喵喵叫 # 维度:[动物性, 植物性, 可食用性, 宠物性]
# "狗" → [0.8, 0.3, 0.1] # 语义:动物、毛茸茸、会汪汪叫
# "苹果" → [0.1, 0.2, 0.9] # 语义:水果、甜的、红色/绿色
# 这样"猫"和"狗"的向量更接近(都是动物) 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(不太相似)
``` ```
## 2.3 相似度计算:向量的威力 **这就是文本向量的威力:把"语义"变成"可计算的数值"**
**核心应用:文本相似度** ## 3.3 向量化方法演进
```python ### 演进概览
import numpy as np
def cosine_similarity(v1, v2):
"""计算两个向量的余弦相似度"""
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
# 假设这些是词的向量表示
cat = np.array([0.9, 0.1, 0.2]) # 猫
dog = np.array([0.8, 0.3, 0.1]) # 狗
apple = np.array([0.1, 0.2, 0.9]) # 苹果
print("猫 vs 狗:", cosine_similarity(cat, dog)) # 应该较高(都是动物)
print("猫 vs 苹果:", cosine_similarity(cat, apple)) # 应该较低(动物 vs 水果)
```
**输出结果:**
```
猫 vs 狗: 0.862
猫 vs 苹果: 0.149
```
**结论**
- 相似度 0.862 → "猫"和"狗"语义相近 ✅
- 相似度 0.149 → "猫"和"苹果"语义相差很远 ✅
> 🎯 **这就是文本向量化的威力:把"语义"变成"可计算的数值"**
---
# 📖 第三部分:从 BoW 到 Embedding演进之路
## 3.1 演进概览
``` ```
文本向量化的三种主要方法: 文本向量化的三种主要方法:
@@ -195,11 +497,9 @@ print("猫 vs 苹果:", cosine_similarity(cat, apple)) # 应该较低(动物 v
无语义 部分语义 深度语义 无语义 部分语义 深度语义
``` ```
## 3.2 BoW词袋模型—— 最简单的方法 ### BoW词袋模型—— 最简单的方法
### 原理 **原理**:把文本看成"一袋词",不考虑顺序,只管词出现了几次。
把文本看成"一袋词",不考虑顺序,只管词出现了几次。
``` ```
文本1: "Python 是 编程 语言" 文本1: "Python 是 编程 语言"
@@ -211,25 +511,40 @@ print("猫 vs 苹果:", cosine_similarity(cat, apple)) # 应该较低(动物 v
**向量化:** **向量化:**
```python ```python
# 统计每个词出现的次数 from sklearn.feature_extraction.text import CountVectorizer
text1_vec = [1, 0, 1, 1, 1] # Python=1, Java=0, 是=1, 编程=1, 语言=1
text2_vec = [0, 1, 1, 1, 1] # Python=0, Java=1, 是=1, 编程=1, 语言=1 # 文档集合
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 的优缺点
| 优点 | 缺点 | | 优点 | 缺点 |
|------|------| |------|------|
| 简单直观 | 忽略词序 | | 简单直观 | 忽略词序 |
| 容易实现 | "我爱你"和"你爱我"向量完全相同 | | 容易实现 | "我爱你"和"你爱我"向量完全相同 |
| 计算速度快 | 所有词同等重要 | | 计算速度快 | 所有词同等重要 |
| 适合基线模型 | 无法捕捉语义 |
## 3.3 TF-IDF —— 加入词的重要性 ### TF-IDF —— 加入词的重要性
### 原理 **问题**BoW 中"Python"和"的"权重相同,这不合理!
BoW 的问题是:所有词同等重要。
"Python"和"的"在 BoW 中权重相同,这不合理。
**TF-IDF = 词频(TF) × 逆文档频率(IDF)** **TF-IDF = 词频(TF) × 逆文档频率(IDF)**
@@ -240,26 +555,43 @@ IDF = 这个词在所有文档中多不多(越多越不重要)
TF-IDF = TF × IDF TF-IDF = TF × IDF
``` ```
### 为什么有效? **为什么有效?**
``` ```
"Python":在少数文档中高频出现 → TF高, IDF高 → TF-IDF高 ✅ 重要 高频出现 ≠ 重要
"的"在所有文档中都出现 → TF高, IDF低 → TF-IDF低 ❌ 停用词 "的"在所有文都出现 → TF高, IDF低 → TF-IDF低 ❌ 停用词
```
### 直观理解 ・罕见词 ≠ 不重要
"TensorFlow"只在AI文章出现 → TF低, IDF高 → TF-IDF高 ✅ 重要词
```
TF-IDF = 词的重要性 × 词的独特性
・高频出现 ≠ 重要("的"在所有文章都出现)
・罕见词 ≠ 不重要("TensorFlow"只在AI文章出现
・既高频又独特 = 真正重要的词 ・既高频又独特 = 真正重要的词
``` ```
## 3.4 Word Embedding词嵌入—— 蕴含语义 **TF-IDF 示例:**
### BoW 和 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, ...] # 只是"位置编码" "猫" → [1, 0, 0, ...] # 只是"位置编码"
@@ -267,9 +599,9 @@ TF-IDF = 词的重要性 × 词的独特性
"小猫" → [0, 0, 1, ...] # 但它们语义相近,向量却正交! "小猫" → [0, 0, 1, ...] # 但它们语义相近,向量却正交!
``` ```
**问题**BoW 和 TF-IDF **无法表达语义相似性** **问题**:无法表达语义相似性!
### Embedding 的思想 **Embedding 的思想**
``` ```
不再用"位置"表示词,而是用"语义空间"表示词 不再用"位置"表示词,而是用"语义空间"表示词
@@ -279,49 +611,35 @@ TF-IDF = 词的重要性 × 词的独特性
动物 植物 动物 植物
| ↑ 猫 ↑ 狗 ↑ 苹果 | ↑ 猫 ↑ 狗 ↑ 苹果
| ↗ ↗ ↑ | ↗ ↗ ↑
| ↗ ↗ ↑
| ↗ ↗ ← 语义相近的词距离近 → | ↗ ↗ ← 语义相近的词距离近 →
|──────────→──────────────────────────── | ↗ ↗
|——————————————————————————————————————→
0 抽象 具体 0 抽象 具体
| ↑
| ↑
| ↑ 人
|
└────────────────────────────────────→
"猫"和"狗"距离近(都是动物)
"猫"和"苹果"距离远(动物 vs 植物)
``` ```
### 词嵌入的实际表示 **词嵌入的效果**
```python ```python
# 实际中,词向量通常是 50/100/300 维 # 假设我们用预训练模型得到了词的语义向量
# 这里用 3 维举例 # 实际中向量通常是 50/100/300 维这里用3维举例
cat = [0.9, 0.1, 0.2] # 猫:动物属性高,植物属性低 word_vectors = {
dog = [0.8, 0.3, 0.1] # 狗:动物属性高 "猫": [0.9, 0.1, 0.2], # 动物属性高
apple = [0.1, 0.2, 0.9] # 苹果:植物属性高 "狗": [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("=== 语义相似度 ===")
cosine_similarity(cat, dog) # ≈ 0.97 → 非常相似 print(f"猫 vs 狗: {cosine_similarity(word_vectors['猫'], word_vectors['狗']):.3f}")
cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 # 输出: 猫 vs 狗: 0.972(非常相似!都是动物)
```
### Word2Vec如何得到词向量 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}")
训练方式1CBOW # 输出: Python vs Java: 0.998(非常相似!都是编程语言)
・上下文:[猫 __ 鱼] → 预测中间词"吃"
・学习目标:调整向量使得能正确预测
训练方式2Skip-gram
・中心词:[吃] → 预测上下文[猫, 鱼]
・学习目标:调整向量使得能正确预测
原理:"相似上下文中的词,语义相似"
・猫和狗经常出现在相似的上下文中("猫吃鱼"、"狗吃肉"
・所以它们的向量也会相似
``` ```
--- ---
@@ -373,7 +691,7 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似
``` ```
原始文本: 原始文本:
"今天天气真不错Python是一门很棒的语言PYTHON也很重要!!!" "今天天气真不错Python是一门很棒的语言python也很重要!!!"
预处理后: 预处理后:
["今天", "天气", "不错", "Python", "语言"] ["今天", "天气", "不错", "Python", "语言"]
@@ -384,7 +702,7 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似
| 步骤 | 输入 | 输出 | 作用 | | 步骤 | 输入 | 输出 | 作用 |
|------|------|------|------| |------|------|------|------|
| 分词 | "今天天气不错" | ["今天", "天气", "不错"] | 把文本切成词 | | 分词 | "今天天气不错" | ["今天", "天气", "不错"] | 把文本切成词 |
| 去停用词 | ["今天", "天气", "不错"] | ["天气", "不错"] | 去掉无意义词 | | 去停用词 | ["今天", "天气", "不错"] | ["天气", "不错"] | 去掉"的、了、在"等无意义词 |
| 统一大小写 | ["Python", "python"] | ["python", "python"] | 归一化 | | 统一大小写 | ["Python", "python"] | ["python", "python"] | 归一化 |
| 去标点 | ["语言!!!"] | ["语言"] | 清理噪音 | | 去标点 | ["语言!!!"] | ["语言"] | 清理噪音 |
@@ -489,57 +807,79 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似
| 方法 | 公式 | 含义 | | 方法 | 公式 | 含义 |
|------|------|------| |------|------|------|
| TF | TF(t) = 词t在文档中出现次数 | 词在本文中多不多 | | 向量加法 | [1,2] + [3,4] = [4,6] | 对应位置相加 |
| IDF | IDF(t) = log(总文档数 / 含词t的文档数) | 词是否罕见 | | 向量数乘 | 2 × [1,2] = [2,4] | 每个元素乘以标量 |
| TF-IDF | TF-IDF(t) = TF(t) × IDF(t) | 词的重要程度 | | 向量点积 | [1,2] · [3,4] = 11 | 对应相乘再求和 |
| 余弦相似度 | cos(θ) = (A·B) / (|A|×|B|) | 向量相似程度 | | 向量长度 | |[3,4]| = 5 | √(3²+4²) |
| 余弦相似度 | cos(θ) = (A·B) / (\|A\|×\|B\|) | 向量相似程度 |
--- ---
# 📝 预习任务 # 📝 课后作业
在下一节课之前,请思考以下问题: ## 第一部分文本数据基础1-2道
## 问题1分词挑战 ### 题目1
在Python中用两种方式表示"Hello"
1.`ord()` 函数打印每个字符的ASCII码
2.`chr()` 函数验证字符65对应的是大写字母A
``` ### 题目2
英文分词很简单(空格分隔): 思考题:为什么计算机擅长处理图像矩阵,却不擅长处理文本?请从"数据的表示形式"和"语义理解"两个角度说明原因。
"I love Python" → ["I", "love", "Python"]
但中文分词很难: ---
"我爱你中国" 可以切成:
["我", "爱", "你", "中国"]
["我爱你", "中国"]
["我爱", "你中国"]
请思考:为什么中文分词比英文难? ## 第二部分向量基础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())
``` ```
## 问题2向量化思考 运行代码并回答:
1. 为什么"Python"在Doc3中的TF-IDF值不是最高假设Doc1和Doc2的值更小
``` 2. "Java"在Doc2中的TF-IDF值是多少解释原因。
假设我们有3个文档
Doc1: "Python是编程语言"
Doc2: "Java是编程语言"
Doc3: "猫是动物"
用BoW模型词表是[Python, Java, 是, 编程, 语言, 猫, 动物]
问题:
1. Doc1 和 Doc2 的相似度是多少?为什么?
2. Doc1 和 Doc3 的相似度是多少?为什么?
3. 这个结果合理吗?为什么?
```
## 问题3工具安装
```bash
# 请在命令行安装以下工具
pip install jieba scikit-learn numpy matplotlib
# 验证安装成功
python -c "import jieba; import sklearn; print('安装成功!')"
```
--- ---