十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

混合推荐算法在鲜花电商中的实践:从原理到工程实现

混合推荐算法在鲜花电商中的实践:从原理到工程实现 1. 先搞清楚“混合推荐”在鲜花销售里到底解决什么问题很多人一看到“推荐系统”就觉得是电商平台那种千人千面的大工程但落到鲜花销售这个具体场景它的核心痛点其实很直接用户不知道自己想买什么或者不知道除了“玫瑰”“百合”还能买什么。一个纯粹的鲜花电商SKU商品种类可能只有几十到几百个远不如综合电商平台海量。如果只用“用户买了A所以推荐相似的B”这种单一算法很容易陷入推荐单调、重复的困境用户逛两下就觉得没新意了。这就是“混合推荐算法”的价值所在。它不是一个炫技的概念而是为了解决单一推荐策略在垂直领域的局限性。简单说它会把几种不同的推荐逻辑“混”在一起用。比如基于内容的推荐看花的颜色红色系、品类玫瑰类、寓意爱情相关给喜欢红玫瑰的用户推荐其他红色或爱情主题的花束。协同过滤推荐看和你相似的人还买了什么。“用户A和你一样买了生日花束和桌面盆栽他还买了‘一周鲜花订阅’你可能也会感兴趣。”基于流行度的推荐把近期最畅销、评价最好的花束放在显眼位置解决新用户的“冷启动”问题——刚来的用户总得给他看点大家都说好的东西。所以这个系统的首要目标不是追求算法的极致复杂度而是让不同场景下的推荐都“说得通”。给老用户推荐点新鲜的混合策略给新用户推荐点靠谱的热门策略在节日推应景的规则策略。理解了这一点后面的技术选型和实现才不会跑偏。2. 环境与数据准备别让算法“巧妇难为无米之炊”在动手写代码之前最费时间也最容易出问题的就是环境搭建和数据准备。很多人项目跑不起来八成是卡在这两步。2.1 开发环境与核心依赖这不是一个需要强大GPU的深度学习项目但对数据处理的库依赖比较明确。我习惯用一个独立的Python虚拟环境来做避免包冲突。# 创建并激活虚拟环境以conda为例 conda create -n flower_recommend python3.8 conda activate flower_recommend # 核心依赖安装 pip install pandas numpy scikit-learn scipy # 如果需要更复杂的模型可以加上lightfm或surprise # pip install lightfm为什么是这些库pandas处理用户行为表、商品信息表的核心数据清洗、合并、分组聚合全靠它。numpy底层数值计算很多机器学习库的基础。scikit-learn不仅用于机器学习它的pairwise_distances可以用来计算商品相似度基于内容推荐LabelEncoder用来处理用户和商品的ID编码也非常方便。scipy协同过滤中计算稀疏矩阵的相似度如余弦相似度时会用到。如果你的推荐逻辑里包含简单的深度学习模型比如用神经网络做特征交叉那可能还需要tensorflow或pytorch但对于大多数中小型鲜花电商的起步阶段传统机器学习方法完全够用且更易于理解和调试。2.2 数据准备模拟出有业务逻辑的“脏数据”教程里的数据往往太干净而真实数据是“脏”的。我们直接模拟一份更贴近现实的数据包含三种关键表1. 商品表 (flowers.csv)这张表描述“物”的属性是基于内容推荐的依据。flower_id,name,category,color,price,meaning,tags,sales_count 1,红色玫瑰,玫瑰,红色,199,爱情,浪漫|求婚|周年纪念,1500 2,白色百合,百合,白色,168,纯洁,祝福|探病|家居,890 3,向日葵,向日葵,黄色,88,阳光,开业|毕业|正能量,1200 4,蓝色绣球,绣球,蓝色,299,美满,婚礼|宴会|奢华,450 5,多肉盆栽,盆栽,绿色,58,治愈,桌面|绿植|懒人植物,3200 ...关键字段说明category,color,meaning,tags这些是“内容特征”用于计算商品之间的相似度。sales_count用于热门推荐。2. 用户-行为表 (user_behavior.csv)这是最重要的数据记录了“人”和“物”的交互是协同过滤的基石。行为可以不止一种。user_id,flower_id,behavior_type,behavior_time,rating 1001,1,view,2023-10-01 10:00:00, 1001,1,cart,2023-10-01 10:05:00, 1001,1,buy,2023-10-01 10:30:00,5 1001,3,view,2023-10-02 15:00:00, 1002,5,buy,2023-10-01 09:00:00,4 1002,2,view,2023-10-03 20:00:00, 1003,1,buy,2023-10-05 14:00:00,5 1003,4,buy,2023-10-05 14:00:00,4 ...行为类型权重直接给不同行为赋予不同分数是简化问题的一个有效方法。例如buy5分,cart3分,view1分。这样可以把多类行为融合成一个“用户-商品”兴趣分数矩阵。3. 用户表 (users.csv) (可选)如果有用户画像数据可以增强推荐。user_id,gender,age_group,preferred_color,preferred_price_range 1001,F,25-35,红色,150-300 1002,M,18-25,绿色,50-150 ...准备好这些CSV文件放在项目的data/目录下。真实场景中这些数据可能来自数据库我们这里用文件模拟原理相通。3. 核心推荐引擎的实现拆解三种基础策略混合推荐不是一上来就“混”而是先把每个基础策略单独实现和调试通。我会用最直观的代码展示每种策略的核心避免一上来就被复杂的框架绕晕。3.1 基于内容的推荐商品画像与相似度计算思路根据商品的属性内容计算它们之间的相似度为用户推荐和他历史喜好商品相似的其他商品。import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity # 加载商品数据 df_flowers pd.read_csv(data/flowers.csv) # 将文本特征合并成一个“内容”字段 # 这里用tags实际中可以组合category, color, meaning等 df_flowers[content] df_flowers[tags].fillna() # 使用TF-IDF将文本转换为特征向量 tfidf TfidfVectorizer(stop_wordsNone) # 鲜花标签一般无停用词 tfidf_matrix tfidf.fit_transform(df_flowers[content]) # 计算商品间的余弦相似度矩阵 content_similarity cosine_similarity(tfidf_matrix, tfidf_matrix) # 包装成一个函数输入商品ID返回最相似的N个商品 def recommend_by_content(flower_id, top_n5): try: idx df_flowers[df_flowers[flower_id] flower_id].index[0] except IndexError: return [] # 获取该商品对所有商品的相似度序列 sim_scores list(enumerate(content_similarity[idx])) # 排序排除自己相似度第一的永远是自己 sim_scores sorted(sim_scores, keylambda x: x[1], reverseTrue)[1:top_n1] # 获取推荐商品的ID flower_indices [i[0] for i in sim_scores] return df_flowers.iloc[flower_indices][[flower_id, name, category]].to_dict(records) # 测试推荐与“红色玫瑰”相似的商品 print(基于内容的推荐输入红色玫瑰:) print(recommend_by_content(1))关键点特征工程这里简单用了tags。更精细的做法可以把category、color、meaning进行独热编码One-Hot与TF-IDF特征拼接形成更丰富的商品向量。相似度选择余弦相似度在文本和稀疏向量上效果很好计算也快。冷启动优势只要商品有内容描述即使它从未被购买过也能被推荐出来。这是内容推荐的核心价值。3.2 基于协同过滤的推荐找到“相似的用户”思路利用群体智慧“和你喜好相似的人喜欢的东西你也可能喜欢”。这里实现最经典的“用户-物品”评分矩阵的协同过滤。import numpy as np from scipy.sparse import csr_matrix from sklearn.neighbors import NearestNeighbors # 加载用户行为数据并转换为隐式评分矩阵 df_behavior pd.read_csv(data/user_behavior.csv) # 定义行为权重 behavior_weight {view: 1, cart: 3, buy: 5} df_behavior[weight] df_behavior[behavior_type].map(behavior_weight) # 对于有显式评分的可以以评分为主这里简单处理有评分则覆盖权重 df_behavior.loc[df_behavior[rating].notna(), weight] df_behavior[rating] # 构建用户-商品交互矩阵稀疏矩阵 user_item_matrix df_behavior.pivot_table( indexuser_id, columnsflower_id, valuesweight, aggfuncsum, # 同一用户对同一商品多次行为分数累加 fill_value0 ) # 使用KNN计算用户相似度基于物品的协同过滤Item-CF原理类似计算物品相似度 # 这里使用余弦相似度 knn_model NearestNeighbors(metriccosine, algorithmbrute) knn_model.fit(user_item_matrix.values) # 推荐函数输入用户ID返回推荐商品 def recommend_by_cf(user_id, top_n5): try: user_idx user_item_matrix.index.get_loc(user_id) except KeyError: # 新用户无法用协同过滤退回热门推荐 return [] # 找到K个最近邻用户 distances, indices knn_model.kneighbors( user_item_matrix.iloc[user_idx, :].values.reshape(1, -1), n_neighbors3 # 找3个相似用户 ) # 获取相似用户喜欢的商品去除输入用户已交互过的 similar_users user_item_matrix.iloc[indices.flatten()] # 计算推荐得分相似用户对该商品的兴趣分加权和 # 这里简化处理直接取相似用户交互过的商品且当前用户未交互过的 target_user_vector user_item_matrix.iloc[user_idx] interacted_items set(target_user_vector[target_user_vector 0].index) candidate_items {} for _, sim_user in similar_users.iterrows(): for item_id, score in sim_user.items(): if score 0 and item_id not in interacted_items: candidate_items[item_id] candidate_items.get(item_id, 0) score # 按得分排序返回Top N recommended sorted(candidate_items.items(), keylambda x: x[1], reverseTrue)[:top_n] flower_ids [item[0] for item in recommended] return df_flowers[df_flowers[flower_id].isin(flower_ids)][[flower_id, name, category]].to_dict(records) # 测试为用户1001推荐 print(\n基于协同过滤的推荐输入用户1001:) print(recommend_by_cf(1001))关键点与坑稀疏矩阵用户-商品矩阵非常稀疏一个用户只买过几十种花中的几种必须使用csr_matrix等稀疏格式存储否则内存爆炸。新用户问题冷启动全新用户没有行为记录协同过滤失效。这是必须处理的边界情况代码中已做退回处理。新商品问题新上架的花束没有被任何用户购买过协同过滤也无法推荐。这需要与内容推荐互补。算法选择这里用了基于内存的KNN适合中小规模数据。如果用户量巨大数十万以上需要考虑基于模型的协同过滤如矩阵分解surprise库或转向深度学习模型。3.3 基于热门度的推荐简单但有效的保底策略思路直接推荐近期最畅销、评分最高或浏览最多的商品。它虽然不个性化但在以下场景至关重要新用户冷启动不知道用户喜好时给他看最受欢迎的。流行趋势情人节前玫瑰就是热门。系统兜底当其他推荐算法因数据不足失效时热门推荐能保证有结果输出。def recommend_by_popularity(top_n5, strategysales): 热门推荐策略 strategy: sales 按销量 | rating 按平均评分需评分数据| views 按浏览量 df_flowers_sorted df_flowers.copy() if strategy sales: df_flowers_sorted df_flowers_sorted.sort_values(bysales_count, ascendingFalse) # 如果有评分数据可以计算平均分 # elif strategy rating: ... return df_flowers_sorted.head(top_n)[[flower_id, name, category, sales_count]].to_dict(records) print(\n基于热门度的推荐按销量:) print(recommend_by_popularity(5, sales))4. 混合策略与工程化整合让推荐结果“智能”起来单独的策略都跑通了现在进入核心环节如何“混合”不是简单地把结果拼在一起而是要根据用户和场景动态决定以哪种策略为主哪种为辅。4.1 设计混合逻辑规则与权重一个实用且易于调试的混合方案是“加权混合”或“分层混合”。方案一加权分数混合适用于可量化的推荐结果假设我们能为每个推荐结果打一个分数如相似度、预测评分那么最终推荐分数可以是最终分数 w1 * 内容推荐分数 w2 * 协同过滤分数 w3 * 热门度分数然后按最终分数排序取Top N。难点在于如何公平地量化不同来源的分数并进行归一化。方案二分层混合更直观更常用我更喜欢用分层逻辑因为它更符合业务直觉也更好调试触发层判断用户状态。是新用户吗 - 走热门推荐为主内容推荐为辅。是老用户但行为很少5次 -热门推荐 内容推荐结合。是老用户且行为丰富 - 以协同过滤为主内容推荐用于解决CF的“新颖性”不足问题。召回层根据触发策略调用不同的推荐算法各生成一个候选商品列表比如各20个。过滤与排序层去重合并多个候选列表去掉用户已经购买过的商品。打散避免同一品类或同一价格段的商品扎堆出现。业务规则干预例如库存为0的商品不推荐高利润商品适当提权情人节期间强插玫瑰品类。最终输出层生成最终的有序推荐列表如前10个。class HybridRecommender: def __init__(self, df_flowers, user_item_matrix, behavior_df): self.df_flowers df_flowers self.user_item_matrix user_item_matrix self.behavior_df behavior_df # 初始化各推荐器这里简化实际中每个推荐器可能是一个独立的类 self.content_sim content_similarity # 来自3.1节计算好的相似度矩阵 self.knn_model knn_model # 来自3.2节训练好的KNN模型 def get_user_status(self, user_id): 判断用户状态 if user_id not in self.user_item_matrix.index: return new interaction_count (self.user_item_matrix.loc[user_id] 0).sum() if interaction_count 3: return light else: return active def recommend(self, user_id, top_n10): user_status self.get_user_status(user_id) candidate_pool [] # 分层召回逻辑 if user_status new: # 新用户热门 内容基于一些默认偏好或随机种子商品 candidate_pool.extend(recommend_by_popularity(top_n*2)) # 随机选一个热门商品做内容推荐种子 seed candidate_pool[0][flower_id] candidate_pool.extend(recommend_by_content(seed, top_n)) elif user_status light: # 轻度用户协同过滤结果可能少 内容基于其少量行为 热门 cf_items recommend_by_cf(user_id, top_n) candidate_pool.extend(cf_items) # 找出用户最近交互的一个商品作为内容种子 user_last_item self.behavior_df[self.behavior_df[user_id]user_id].iloc[-1][flower_id] candidate_pool.extend(recommend_by_content(user_last_item, top_n)) candidate_pool.extend(recommend_by_popularity(top_n)) else: # 活跃用户协同过滤为主内容推荐增加多样性 cf_items recommend_by_cf(user_id, top_n*2) candidate_pool.extend(cf_items) # 从CF结果中随机选一个做内容扩展引入惊喜度 import random if cf_items: seed random.choice(cf_items)[flower_id] candidate_pool.extend(recommend_by_content(seed, top_n)) # 过滤与排序简化版去重、按业务逻辑排序 # 1. 去重 seen set() unique_candidates [] for item in candidate_pool: fid item[flower_id] if fid not in seen: seen.add(fid) unique_candidates.append(item) # 2. 简单业务规则例如优先展示有库存的假设有库存字段in_stock # 这里假设所有商品都有库存 # 3. 最终截取 final_recommendations unique_candidates[:top_n] return final_recommendations # 初始化混合推荐器 hybrid_rec HybridRecommender(df_flowers, user_item_matrix, df_behavior) print(\n 混合推荐测试 ) print(用户1001 (活跃用户) 推荐结果:) print(hybrid_rec.recommend(1001)) print(\n用户1005 (假设为新用户) 推荐结果:) print(hybrid_rec.recommend(1005)) # 需要确保1005不在user_item_matrix中4.2 工程化考量从脚本到服务一个可用的Python脚本和线上推荐服务之间还隔着很多工程问题。性能每次请求都实时计算相似度矩阵和KNN模型是不可行的。需要离线计算在线查询。离线层定时如每天用全部数据重新训练模型计算好商品相似度矩阵、用户相似度矩阵、热门商品列表并把结果存入Redis或数据库。在线层推荐服务接收到用户ID请求后直接从缓存中读取预计算好的结果进行混合、过滤、排序响应时间应在毫秒级。存储特征存储商品特征向量、用户Embedding向量需要高效存储和读取。模型存储训练好的协同过滤模型如矩阵分解的User/Item向量需要持久化。AB测试与评估上线后如何判断推荐效果好坏了不能只靠感觉。需要设计评估指标线上指标推荐位的点击率CTR、转化率CVR、客单价变化。离线指标准确率、召回率、覆盖率、新颖性。可以在历史数据上划分训练集和测试集进行模拟评估。5. 部署、评估与常见问题排查5.1 简易API服务部署用Flask或FastAPI快速搭建一个推荐接口感受一下服务化的过程。# app.py (FastAPI示例) from fastapi import FastAPI, HTTPException from pydantic import BaseModel import pandas as pd # 假设我们已经有一个训练好的HybridRecommender实例 rec_system app FastAPI() class RecommendRequest(BaseModel): user_id: int top_n: int 10 app.post(/recommend) async def recommend_flowers(request: RecommendRequest): try: recommendations rec_system.recommend(request.user_id, request.top_n) return {user_id: request.user_id, recommendations: recommendations} except Exception as e: raise HTTPException(status_code500, detailstr(e)) # 运行: uvicorn app:app --reload这样前端或APP就可以通过调用/recommend接口获取推荐结果了。5.2 效果评估与迭代没有评估的推荐系统就是“盲人摸象”。在资源有限的情况下可以优先关注两个核心问题推荐的商品用户会点吗- 看点击率。在推荐位埋点记录曝光和点击。推荐的商品用户会买吗- 看转化率。追踪从推荐位点击到下单的路径。如果发现点击率低问题可能是推荐结果不相关算法不准或者展示样式不吸引人UI问题。排查先看日志确认输入的用户ID和特征是否正确。然后抽样查看给低点击率用户推荐了些什么是不是总推他已经买过的东西去重没做好或者总推同一类商品打散没做好如果转化率低但点击率高问题“标题党”效应。可能推荐了吸引人但用户不想买的花比如太贵的奢华花束点击高但购买少。排查检查推荐结果的价格分布是否与用户历史消费水平匹配。在排序规则中加入价格偏好因子。5.3 典型问题排查清单当推荐结果看起来“不对劲”时按这个顺序查数据问题最常见数据是否更新新上的商品有没有进入商品表今天的购买行为有没有同步到行为表数据是否干净用户行为日志里有没有大量爬虫或测试账号的垃圾数据商品标签有没有大量空值或乱码关键字段是否缺失做内容推荐的商品tags字段是不是空的特征工程问题内容特征向量能否区分商品所有商品的tags如果都是“鲜花|礼品”那计算出的相似度全一样推荐自然无效。需要更精细的标签。行为权重设置是否合理buy5, cart3, view1这个比例是否真实反映了用户的兴趣程度可能需要根据业务数据调整。算法逻辑问题冷启动处理了吗新用户访问是否返回了空列表或错误是否正确地降级到了热门推荐去重生效了吗用户刚买完一束红玫瑰推荐列表里是否还出现红玫瑰混合策略权重是否极端比如协同过滤权重太高导致所有用户推荐结果都趋同。工程实现问题离线模型更新了吗代码里用的是不是一周前的旧模型文件在线缓存命中了吗Redis里的相似度矩阵是否成功加载缓存是否过期API响应慢吗在线计算部分是否过于复杂导致接口超时这个基于混合推荐算法的鲜花销售推荐系统从原型到上线的核心路径就是这样。它不是一个追求前沿算法的复杂系统而是一个重视业务适配、可解释、可迭代的实用工具。真正的价值不在于算法本身多高级而在于它能否在用户浏览鲜花的短短几分钟内给出那么一两个让他觉得“哎这个不错”的建议。
返回列表