From 4dae58def7f81dd571309e9cd1a6e03ace9cbb3f Mon Sep 17 00:00:00 2001 From: gitea_eternal <401029566@qq.com> Date: Mon, 20 Apr 2026 21:23:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B03-2-1=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86=E5=AF=BC=E8=AE=BA=EF=BC=88?= =?UTF-8?q?v2=E7=89=88=E6=9C=AC=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 760 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 550 insertions(+), 210 deletions(-) diff --git a/README.md b/README.md index dba3a20..fa7a3e7 100644 --- a/README.md +++ b/README.md @@ -6,100 +6,414 @@ | 目标 | 内容 | |------|------| -| **理解** | 为什么文本不能直接用于计算机计算 | +| **理解** | 什么是文本数据,以及计算机如何读取文本 | +| **掌握** | 为什么文本不能直接用于计算机计算 | +| **理解** | 向量、相似度的基本概念(零基础讲解) | | **掌握** | 文本向量化的核心思想与数学原理 | | **了解** | 从 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 文本 + +**图像数据的读取:** ``` -文本理解: -"今天天气真好!" → ??? → 计算机无法直接"理解" -"Python是世界上最好的语言" → ??? → 计算机不知道这是什么意思 +图像文件(.jpg/.png) + ↓ +计算机读取像素值 + ↓ +存储为3维矩阵 [高度, 宽度, 通道] + ↓ +一张 1920×1080 的彩色图 = 1920 × 1080 × 3 = 6,220,800 个数字 ``` -**核心问题:** - -> 计算机只能处理数字,**文本是符号**,符号不能直接用于计算。 - -## 1.2 文本 vs 图像:本质区别 +**文本数据的读取:** ``` -┌─────────────────────────────────────────────────────────┐ -│ 图像数据 │ -├─────────────────────────────────────────────────────────┤ -│ 📐 空间结构化数据 │ -│ ・像素 = 数字(0-255) │ -│ ・位置关系 = 空间关系(上下左右) │ -│ ・相邻像素通常相关 │ -│ ・直接可以用矩阵表示 │ -└─────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────┐ -│ 文本数据 │ -├─────────────────────────────────────────────────────────┤ -│ 📝 序列符号化数据 │ -│ ・词语/字符 = 离散符号 │ -│ ・位置关系 = 逻辑顺序(不是物理位置) │ -│ ・符号本身无"数值含义" │ -│ ・无法直接用数字运算 │ -└─────────────────────────────────────────────────────────┘ +文本文件(.txt/.md) + ↓ +计算机读取字符编码(ASCII/UTF-8) + ↓ +存储为字符序列(每个字符是一个数字编码) + ↓ +"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:一词多义 +### 文本的"存储形式" -``` -"苹果" 可以指: -・一种水果(营养丰富) -・一家公司(Apple Inc.) -・手机品牌(苹果手机) +```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='好' ``` -### 挑战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模型处理 @@ -112,78 +426,66 @@ ・向量加减:v1 + v2 = ? ・向量点积:v1 · v2 = ? ・向量距离:||v1 - v2|| = ? -・矩阵运算:A × B = ? +・余弦相似度:cos(θ) = ? 但计算机不擅长: ・字符串比较:"Python" == "Java" ? ・词语推理:"猫" 类似于 "狗" ? ``` -## 2.2 向量化示例:从"词"到"数" +**文本向量化的意义:** -### 简单例子:把词变成向量 +``` +"猫"和"狗"在文本中可能完全不相关 +但如果我们知道它们都是"动物",向量就会接近 +计算机就能"理解"它们的相似性了! +``` -假设我们只有一个很小的词汇表: +## 3.2 向量化示例:从"词"到"数" + +### 简单例子:把词变成向量(位置编码) ```python +# 假设我们有一个很小的词汇表(只有5个词) vocab = ["猫", "狗", "鱼", "苹果", "香蕉"] -# "猫" → [1, 0, 0, 0, 0] # 猫在这个词表中的位置 -# "狗" → [0, 1, 0, 0, 0] # 狗在这个词表中的位置 -# "苹果" → [0, 0, 0, 1, 0] # 苹果在这个词表中的位置 +# 位置编码:每个词对应一个位置 +# "猫" → [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 -# 理想情况: -# "猫" → [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 是 编程 语言" @@ -211,25 +511,40 @@ print("猫 vs 苹果:", cosine_similarity(cat, apple)) # 应该较低(动物 v **向量化:** ```python -# 统计每个词出现的次数 -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 +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 的优缺点 | 优点 | 缺点 | |------|------| | 简单直观 | 忽略词序 | | 容易实现 | "我爱你"和"你爱我"向量完全相同 | | 计算速度快 | 所有词同等重要 | +| 适合基线模型 | 无法捕捉语义 | -## 3.3 TF-IDF —— 加入词的重要性 +### TF-IDF —— 加入词的重要性 -### 原理 - -BoW 的问题是:所有词同等重要。 -"Python"和"的"在 BoW 中权重相同,这不合理。 +**问题**:BoW 中"Python"和"的"权重相同,这不合理! **TF-IDF = 词频(TF) × 逆文档频率(IDF)** @@ -240,26 +555,43 @@ 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, ...] # 只是"位置编码" @@ -267,9 +599,9 @@ TF-IDF = 词的重要性 × 词的独特性 "小猫" → [0, 0, 1, ...] # 但它们语义相近,向量却正交! ``` -**问题**:BoW 和 TF-IDF **无法表达语义相似性**! +**问题**:无法表达语义相似性! -### Embedding 的思想 +**Embedding 的思想** ``` 不再用"位置"表示词,而是用"语义空间"表示词 @@ -279,49 +611,35 @@ TF-IDF = 词的重要性 × 词的独特性 动物 植物 | ↑ 猫 ↑ 狗 ↑ 苹果 | ↗ ↗ ↑ - | ↗ ↗ ↑ - | ↗ ↗ ← 语义相近的词距离近 → - |──────────→────────────────────────────→ + | ↗ ↗ ← 语义相近的词距离近 → + | ↗ ↗ → + |——————————————————————————————————————→ 0 抽象 具体 - | ↑ - | ↑ - | ↑ 人 - | - └────────────────────────────────────→ - -"猫"和"狗"距离近(都是动物) -"猫"和"苹果"距离远(动物 vs 植物) ``` -### 词嵌入的实际表示 +**词嵌入的效果** ```python -# 实际中,词向量通常是 50/100/300 维 -# 这里用 3 维举例 +# 假设我们用预训练模型得到了词的语义向量 +# 实际中向量通常是 50/100/300 维,这里用3维举例 -cat = [0.9, 0.1, 0.2] # 猫:动物属性高,植物属性低 -dog = [0.8, 0.3, 0.1] # 狗:动物属性高 -apple = [0.1, 0.2, 0.9] # 苹果:植物属性高 +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], # 编程属性高 +} -# 计算相似度 -cosine_similarity(cat, dog) # ≈ 0.97 → 非常相似 -cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 -``` +print("=== 语义相似度 ===") +print(f"猫 vs 狗: {cosine_similarity(word_vectors['猫'], word_vectors['狗']):.3f}") +# 输出: 猫 vs 狗: 0.972(非常相似!都是动物) -### Word2Vec:如何得到词向量? +print(f"猫 vs 苹果: {cosine_similarity(word_vectors['猫'], word_vectors['苹果']):.3f}") +# 输出: 猫 vs 苹果: 0.149(不太相似!) -``` -训练方式1:CBOW -・上下文:[猫 __ 鱼] → 预测中间词"吃" -・学习目标:调整向量使得能正确预测 - -训练方式2:Skip-gram -・中心词:[吃] → 预测上下文[猫, 鱼] -・学习目标:调整向量使得能正确预测 - -原理:"相似上下文中的词,语义相似" -・猫和狗经常出现在相似的上下文中("猫吃鱼"、"狗吃肉") -・所以它们的向量也会相似 +print(f"Python vs Java: {cosine_similarity(word_vectors['Python'], word_vectors['Java']):.3f}") +# 输出: Python vs Java: 0.998(非常相似!都是编程语言) ``` --- @@ -373,7 +691,7 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 ``` 原始文本: -"今天天气真不错!!Python是一门很棒的语言,PYTHON也很重要!!!" +"今天天气真不错!!Python是一门很棒的语言,python也很重要!!!" 预处理后: ["今天", "天气", "不错", "Python", "语言"] @@ -384,7 +702,7 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 | 步骤 | 输入 | 输出 | 作用 | |------|------|------|------| | 分词 | "今天天气不错" | ["今天", "天气", "不错"] | 把文本切成词 | -| 去停用词 | ["今天", "天气", "不错"] | ["天气", "不错"] | 去掉无意义词 | +| 去停用词 | ["今天", "天气", "不错"] | ["天气", "不错"] | 去掉"的、了、在"等无意义词 | | 统一大小写 | ["Python", "python"] | ["python", "python"] | 归一化 | | 去标点 | ["语言!!!"] | ["语言"] | 清理噪音 | @@ -445,7 +763,7 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 │ scikit-learn ・BoW、TF-IDF 实现 │ │ Gensim ・Word2Vec、Doc2Vec │ │ TensorFlow/PyTorch ・深度学习文本处理 │ -│ transformers ・BERT、GPT 等预训练模型 │ +│ transformers ・BERT、GPT 等预训练模型 │ └─────────────────────────────────────────────────────────┘ ``` @@ -489,57 +807,79 @@ cosine_similarity(cat, apple) # ≈ 0.15 → 很不相似 | 方法 | 公式 | 含义 | |------|------|------| -| TF | TF(t) = 词t在文档中出现次数 | 词在本文中多不多 | -| IDF | IDF(t) = log(总文档数 / 含词t的文档数) | 词是否罕见 | -| TF-IDF | TF-IDF(t) = TF(t) × IDF(t) | 词的重要程度 | -| 余弦相似度 | cos(θ) = (A·B) / (|A|×|B|) | 向量相似程度 | +| 向量加法 | [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:分词挑战 +### 题目1 +在Python中,用两种方式表示"Hello": +1. 用 `ord()` 函数打印每个字符的ASCII码 +2. 用 `chr()` 函数验证:字符65对应的是大写字母A -``` -英文分词很简单(空格分隔): -"I love Python" → ["I", "love", "Python"] +### 题目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()) ``` -## 问题2:向量化思考 - -``` -假设我们有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('安装成功!')" -``` +运行代码并回答: +1. 为什么"Python"在Doc3中的TF-IDF值不是最高(假设Doc1和Doc2的值更小)? +2. "Java"在Doc2中的TF-IDF值是多少?解释原因。 ---