
零基础 10 行代码实现内容推荐系统(TF-IDF + 余弦相似度)
本文教你用 Python 实现一个简单的内容推荐系统【目标:输入一句话,推荐最相似的另一句】
- 适合初学者,核心代码不到 10 行
💜 安装所需库并准备示例数据
-
只需安装 scikit-learn:
pip install scikit-learn -
以下为简单的示例数据:
documents = [ "我喜欢看电影", "他今天去看了场电影", "天气真好,适合出去散步", "我们去图书馆学习吧", "你觉得这部电影好看吗", ]
💜 1. 将句子文本转化为向量:提取特征
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(documents)
💡 此处使用的是 词频-逆文档频率(TF-IDF)来表示每个句子中关键词的重要性。默认提取的是单个词(即 1-gram)。
💜 2. 相似度计算:使用余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
cos_sim = cosine_similarity(tfidf_matrix, tfidf_matrix)
💡 什么是余弦相似度?
它是通过两个向量夹角的余弦值,来判断它们在方向上的相似程度。
公式如下所示:
similarity=cos(θ)=A⋅B∣A∣∣B∣=∑i=1nAiBi∑i=1nAi2⋅∑i=1nBi2 \text{similarity} = \cos(\theta) = \frac{A \cdot B}{|A||B|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \cdot \sqrt{\sum_{i=1}^{n} B_i^2}} similarity=cos(θ)=∣A∣∣B∣A⋅B=∑i=1nAi2⋅∑i=1nBi2∑i=1nAiBi
当 θ=0∘\theta = 0^\circθ=0∘ 时,两个向量完全相似,cos(θ)=1\cos(\theta) = 1cos(θ)=1;当 θ=90∘\theta = 90^\circθ=90∘,向量正交,cos(θ)=0\cos(\theta) = 0cos(θ)=0。
💜 3. 得到推荐:返回最相似的一条文本
import numpy as np
target_index = 0 # 想查找的那句,比如第0句
similarities = cos_sim[target_index]
most_similar = np.argsort(similarities)[::-1][1] # 除了自己以外的第一相似
print("原句:", documents[target_index])
print("推荐:", documents[most_similar])
完整代码(带步骤对照注释)
# 💜 示例文本数据
documents = [
"我喜欢看电影",
"他今天去看了场电影",
"天气真好,适合出去散步",
"我们去图书馆学习吧",
"你觉得这部电影好看吗",
]
# 💜 1. TF-IDF 特征提取
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(documents)
# 💜 2. 计算余弦相似度矩阵
from sklearn.metrics.pairwise import cosine_similarity
cos_sim = cosine_similarity(tfidf_matrix, tfidf_matrix)
# 💜 3. 找出最相似的句子
import numpy as np
target_index = 0 ## 以第 0 句为例
similarities = cos_sim[target_index]
most_similar = np.argsort(similarities)[::-1][1] # 排除自身
print("原句:", documents[target_index])
print("推荐:", documents[most_similar])
输出示例:
原句: 我喜欢看电影
推荐: 他今天去看了场电影
💜💜 可选进阶 - 1:使用 N-Gram 提升语义捕捉能力
你可以启用 N-Gram 提取连续词组作为特征,例如 bigram(双词组):
vectorizer = TfidfVectorizer(ngram_range=(1, 2))
这会把句子 “我 喜欢 看 电影” 转换为以下特征:
["我", "喜欢", "看", "电影", "我 喜欢", "喜欢 看", "看 电影"]
💡 好处是保留词序信息,更适合表达语义联系,如“看 电影”比单词“电影”更精确。
💜💜 可选进阶 - 2:使用向量数据库快速查找 (主页有对应教程)
当句子或文档数量非常大时(如成千上万条),用普通方式计算相似度会很慢;此时可以使用 向量数据库高效处理
| 特性 | FAISS | Milvus | Pinecone |
|---|---|---|---|
| 开发方 | 开源社区(Zilliz) | 商业公司 Pinecone | |
| 部署方式 | 本地部署 | 自部署 / 云部署 / 混合 | 完全托管(SaaS) |
| 数据类型 | 静态数据 | 支持动态数据更新 | 支持动态数据更新 |
| 架构支持 | 单机 | 分布式架构 | 云原生、自动扩缩容 |
| 优势 | 高性能、索引类型丰富 | 扩展性强、灵活的数据管理 | 零运维、易部署、适合大规模生产 |
| 局限性 | 不支持动态数据写入/删除操作复杂 | 对复杂部署环境有一定要求 | 商业产品,成本相对较高 |
| 适用场景 | 离线/静态大规模相似性搜索 | 动态、分布式应用、需要扩展性 | 云端应用、对可用性和易维护性要求高 |
配合 TF-IDF 使用示意:提取向量 -> 建立索引(Index) -> 执行查询(Search Top-K 相似)
import faiss ## 以 faiss 向量数据库为例
faiss.normalize_L2(tfidf_matrix) # FAISS 要求归一化
index = faiss.IndexFlatIP(tfidf_matrix.shape[1]) # 内积即余弦相似度
index.add(tfidf_matrix.toarray())
D, I = index.search(tfidf_matrix[0:1].toarray(), k=5)
💜 延伸方向
- 使用 Word2Vec 或 BERT 替代 TF-IDF,表达更深层语义
- 使用 Flask 做成推荐接口服务
- 使用 FAISS + GPU 提速百万量级文档检索
10行代码实现内容推荐系统
2万+

被折叠的 条评论
为什么被折叠?



