Python贪心算法实现搜索推荐

下面是一段用贪心算法做搜索推荐的 Python 示例。

场景:用户输入搜索问题,系统从候选内容中推荐最相关的若干条。贪心策略是:每一步都从剩余候选里选"当前得分最高且满足约束"的内容,同时考虑相关度、质量、新鲜度,以及推荐结果之间的多样性。

```python

import re

from dataclasses import dataclass

from typing import List, Set

@dataclass

class Candidate:

id: int

title: str

content: str

tags: Liststr

quality: float = 0.8 # 内容质量分

freshness: float = 0.8 # 新鲜度

click_rate: float = 0.5 # 历史点击率

length: int = 100 # 内容长度,可用于控制总推荐长度

def tokenize(text: str) -> Setstr:

"""

简单分词:

  • 英文/数字按单词切分

  • 中文按连续片段 + 2-gram 切分

不依赖 jieba,方便直接运行。

"""

text = text.lower()

tokens = set(re.findall(r"a-z0-9+", text))

chinese_seqs = re.findall(r"\\u4e00-\\u9fa5+", text)

for seq in chinese_seqs:

if len(seq) == 1:

tokens.add(seq)

else:

tokens.add(seq)

for i in range(len(seq) - 1):

tokens.add(seqi:i + 2)

return tokens

def jaccard(a: Setstr, b: Setstr) -> float:

"""计算两个集合的 Jaccard 相似度"""

if not a or not b:

return 0.0

return len(a & b) / len(a | b)

def base_score(query_tokens: Setstr, cand: Candidate) -> float:

"""

计算候选内容的基础得分:

相关性 + 质量 + 新鲜度 + 点击率

"""

cand_text = cand.title + " " + cand.content + " " + " ".join(cand.tags)

cand_tokens = tokenize(cand_text)

relevance = jaccard(query_tokens, cand_tokens)

标签命中额外加权

tag_tokens = tokenize(" ".join(cand.tags))

tag_relevance = jaccard(query_tokens, tag_tokens)

relevance = max(relevance, tag_relevance)

score = (

0.55 * relevance +

0.20 * cand.quality +

0.15 * cand.freshness +

0.10 * cand.click_rate

)

return score

def greedy_recommend(

query: str,

candidates: ListCandidate,

top_k: int = 5,

max_similarity: float = 0.7, # 与已选内容标签相似度超过该值则跳过

diversity_penalty: float = 0.3, # 相似度带来的得分惩罚

max_total_length: int = 1000 # 推荐内容总长度限制

) -> ListCandidate:

"""

贪心推荐:

每一步从剩余候选中选择当前得分最高、且满足多样性/长度约束的内容。

"""

query_tokens = tokenize(query)

selected: ListCandidate = \[\]

selected_tag_sets: ListSet\[str] = \[\]

total_length = 0

预计算基础得分

remaining = (base_score(query_tokens, c), c) for c in candidates

while len(selected) < top_k and remaining:

best_idx = -1

best_score = -1.0

best_cand = None

for i, (base_s, cand) in enumerate(remaining):

cand_tags = tokenize(" ".join(cand.tags))

计算与已选内容的最大标签相似度

max_overlap = 0.0

for tag_set in selected_tag_sets:

max_overlap = max(max_overlap, jaccard(tag_set, cand_tags))

多样性约束:太相似就不选

if selected and max_overlap > max_similarity:

continue

长度约束

if total_length + cand.length > max_total_length:

continue

当前得分 = 基础得分 - 多样性惩罚

current_score = base_s - diversity_penalty * max_overlap

if current_score > best_score:

best_score = current_score

best_idx = i

best_cand = cand

没有满足约束的候选,结束

if best_idx == -1:

break

选中当前最优

selected.append(best_cand)

selected_tag_sets.append(tokenize(" ".join(best_cand.tags)))

total_length += best_cand.length

remaining.pop(best_idx)

return selected

if name == "main":

candidates = [

Candidate(1, "贪心算法入门", "贪心算法是一种局部最优策略...", "算法", "贪心算法", "基础", 0.90, 0.70, 0.60, 120),

Candidate(2, "活动选择问题详解", "用贪心算法解决活动选择...", "贪心算法", "活动选择", "区间调度", 0.85, 0.80, 0.70, 150),

Candidate(3, "动态规划与贪心算法区别", "对比动态规划和贪心算法...", "算法", "动态规划", "贪心算法", 0.88, 0.60, 0.65, 180),

Candidate(4, "霍夫曼编码实现", "霍夫曼编码的贪心构造...", "贪心算法", "霍夫曼编码", "压缩", 0.80, 0.75, 0.55, 200),

Candidate(5, "Dijkstra 最短路", "Dijkstra 算法是贪心思想...", "贪心算法", "图论", "最短路", 0.90, 0.65, 0.75, 160),

Candidate(6, "0/1 背包问题", "0/1 背包不能用贪心...", "动态规划", "背包", 0.95, 0.90, 0.80, 140),

Candidate(7, "分数背包贪心解法", "分数背包可以按单位价值贪心...", "贪心算法", "背包", "分数背包", 0.82, 0.70, 0.60, 130),

Candidate(8, "贪心算法常见错误", "贪心算法不是万能的...", "贪心算法", "算法", "反例", 0.87, 0.80, 0.72, 110),

]

query = "贪心算法 活动选择"

recs = greedy_recommend(query, candidates, top_k=4, max_total_length=600)

print(f"查询:{query}\n推荐结果:")

for i, c in enumerate(recs, 1):

print(f"{i}. {c.title} | 标签:{', '.join(c.tags)} | 质量:{c.quality} | 长度:{c.length}")

```

这段代码的核心贪心逻辑在 greedy_recommend 里:

  1. 先计算每个候选内容的基础得分;

  2. 每一步遍历剩余候选;

  3. 计算它和已选内容的标签相似度,并做多样性惩罚;

  4. 选择当前得分最高、且满足相似度阈值和长度限制的内容;

  5. 加入推荐列表,重复直到选够 top_k 或没有可用候选。

你可以根据实际业务调整这些参数:

· top_k:推荐几条;

· max_similarity:控制内容多样性;

· diversity_penalty:相似内容的降权幅度;

· max_total_length:控制推荐总长度;

· base_score 里的权重:相关性、质量、新鲜度、点击率各占多少。

文章仅供参考用。

相关推荐
小oo呆1 小时前
【学习心得】Python协程
python
信誓旦旦的程序猿1 小时前
【Python量化实战宝典 #22】涨跌停、连板情绪手册:情绪指标构建(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
gCode Teacher 格码致知1 小时前
Pandas教学-21:subplots的使用
python·pandas·1024程序员节
2601_967980111 小时前
Python开发的顶级开源项目全景图:2025-2026年生态概览
python·机器学习·开源项目·数据科学·生态概览
benchmark_cc2 小时前
量化开发中,什么时候应该停止手动下载股票数据?
python·数据分析·pandas·量化交易·1024程序员节·股票数据·quantdash
泡茶喝茶写代码2 小时前
A股量化策略回测实战:从行情数据到绩效评估(第 15 篇):新高新低策略
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
全栈练习生2 小时前
Jev 决策模型
python·ai·1024程序员节
LMT流氓兔2 小时前
第五单元——第十二课:把脚本整理成项目
java·数据库·python·langchain·1024程序员节
光依旧2 小时前
day-trader-skill实测:让Claude Code当交易助理,纯Python+确定性+fail-closed
python·量化交易·ai agent·a股·风控·claude code·开源项目实测
CCblandy3 小时前
前缀缓存命中率不靠引擎靠排列:本机仿真 3 轮,易变字段放开头 98.0%→0.0%
人工智能·python·算法·自然语言处理·性能优化