You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python优化相似产品分组:兼顾相似度与组规模

产品分组优化方案(基于Jaccard相似度)

适用算法推荐

针对你的需求(最大化组内/整体平均相似度+避免组规模极端化),推荐以下两类算法:

  • 带约束的社区检测算法:把产品看作图节点,Jaccard相似度看作边的权重,用Louvain算法(支持加权图)进行社区划分,可通过调整模块度权重或后期剪枝/合并来控制组规模。优点是全局优化性好,适合大规模数据。
  • 贪心分组算法:从相似度最高的产品对入手,逐步吸纳与当前组平均相似度最高的产品,同时设置组规模上下限。优点是实现简单、可解释性强,适合快速迭代调整约束条件。

Python实现示例

贪心分组算法(带规模约束)

假设你的输入DataFrame包含product1、product2、jaccard_similarity三列,以下是可直接运行的代码:

import pandas as pd
import numpy as np
from collections import defaultdict

# 加载数据(替换为你的数据源)
df = pd.read_csv('product_similarity.csv')

# 构建对称相似度字典,方便快速查询任意产品对的相似度
similarity_dict = defaultdict(dict)
for _, row in df.iterrows():
    p1, p2, sim = row['product1'], row['product2'], row['jaccard_similarity']
    similarity_dict[p1][p2] = sim
    similarity_dict[p2][p1] = sim

def greedy_grouping(similarity_dict, min_group_size=3, max_group_size=10, min_avg_sim_threshold=0.3):
    ungrouped = set(similarity_dict.keys())
    groups = []
    
    while ungrouped:
        # 选择未分组产品中,与其他未分组产品总相似度最高的作为组核心
        core_product = max(ungrouped, key=lambda x: sum(similarity_dict[x].get(p, 0) for p in ungrouped))
        current_group = [core_product]
        ungrouped.remove(core_product)
        
        # 逐步吸纳符合条件的产品
        while len(current_group) < max_group_size and ungrouped:
            # 计算每个未分组产品与当前组的平均相似度
            avg_sims = {}
            for p in ungrouped:
                sims = [similarity_dict[p].get(member, 0) for member in current_group]
                avg_sims[p] = np.mean(sims)
            # 取平均相似度最高的产品
            next_product = max(avg_sims, key=avg_sims.get)
            # 只有当平均相似度超过阈值时才加入
            if avg_sims[next_product] >= min_avg_sim_threshold:
                current_group.append(next_product)
                ungrouped.remove(next_product)
            else:
                break
        
        # 处理规模过小的组:合并到最相似的现有组
        if len(current_group) < min_group_size and groups:
            group_similarities = []
            for g in groups:
                cross_sims = []
                for p1 in current_group:
                    for p2 in g:
                        cross_sims.append(similarity_dict[p1].get(p2, 0))
                group_similarities.append(np.mean(cross_sims))
            best_group_idx = np.argmax(group_similarities)
            groups[best_group_idx].extend(current_group)
        else:
            groups.append(current_group)
    
    return groups

# 执行分组(可根据业务调整参数)
groups = greedy_grouping(similarity_dict, min_group_size=4, max_group_size=8, min_avg_sim_threshold=0.25)

# 计算分组效果指标
def calculate_group_avg_sim(group, sim_dict):
    sims = []
    group_size = len(group)
    for i in range(group_size):
        for j in range(i+1, group_size):
            sim = sim_dict[group[i]].get(group[j], 0)
            sims.append(sim)
    return np.mean(sims) if sims else 0

# 输出结果
group_avg_sims = [calculate_group_avg_sim(g, similarity_dict) for g in groups]
overall_avg_sim = np.mean(group_avg_sims)
group_sizes = [len(g) for g in groups]
size_variance_coeff = np.std(group_sizes) / np.mean(group_sizes)

print(f"整体平均相似度: {overall_avg_sim:.4f}")
print(f"组规模变异系数: {size_variance_coeff:.4f}")
for idx, (group, avg_sim, size) in enumerate(zip(groups, group_avg_sims, group_sizes), 1):
    print(f"组{idx} | 规模: {size} | 平均相似度: {avg_sim:.4f} | 产品: {group}")

Louvain社区检测(带规模调整)

如果用Louvain算法,可使用python-louvain库,后期通过合并小规模组、拆分超大规模组来满足约束:

import community as community_louvain
import networkx as nx

# 构建加权图
G = nx.Graph()
for _, row in df.iterrows():
    G.add_edge(row['product1'], row['product2'], weight=row['jaccard_similarity'])

# 执行社区检测
partition = community_louvain.best_partition(G, weight='weight')

# 将分区转换为组列表
groups = defaultdict(list)
for product, group_id in partition.items():
    groups[group_id].append(product)
groups = list(groups.values())

# 后期调整组规模(可复用前面贪心算法中的规模调整逻辑)

更优评价指标建议

除了平均相似度,建议补充以下指标全面评估分组效果:

  • 组内平均Jaccard相似度:核心指标,直接反映组内产品的相似性
  • 整体加权平均相似度:用组规模作为权重计算整体平均,比简单均值更贴合实际业务价值
  • 组规模变异系数:(组规模标准差 / 组规模均值),数值越小说明组规模越均衡
  • 组间平均相似度:计算不同组之间产品的平均相似度,数值越低说明组间差异越明显,分组效果越好
  • 最小/最大组规模比:越接近1,说明规模越避免极端化

内容的提问来源于stack exchange,提问作者Liam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:50:12