基于Python构建Home Depot相似客户账户匹配模型的技术实现咨询
嘿,这个需求在客户关系管理场景里太常见了!咱们不用搞复杂的深度学习或者树模型,因为你的数据全是分类变量,用基于集合相似度的方法就足够高效、直观,而且解释性超强。下面给你一步步拆解实现思路和代码:
核心思路与模型选择
首先明确:分类变量的相似性本质是「特征重叠度」——比如两个客户同属一个行业、同一个国家,那他们的相似度就高。最适合的方法有两种:
- Jaccard相似度:专门针对二进制特征(比如One-Hot编码后的分类字段),计算的是两个样本「共同拥有的特征数占总特征数的比例」,完美匹配你的场景。
- K近邻(KNN)模型:可以基于Jaccard或余弦相似度快速找到最相似的Top N客户,适合数据量较大的情况,不用预先计算整个相似度矩阵。
具体实施步骤
1. 数据预处理:把分类变量转成可计算的特征
所有分类字段(industry、country、state等)都需要转成二进制特征(One-Hot编码);如果services是多值字段(比如一个客户有多个服务,用逗号分隔),要做Multi-Hot编码。
2. 计算相似度或训练KNN模型
- 小数据量:直接计算全量相似度矩阵,方便随时查询。
- 大数据量:用KNN模型,按需查询,节省内存。
3. 构建查询函数
输入账户名,返回Top N相似客户的信息和相似度得分。
完整代码示例
假设你的DataFramedf已经加载完成,我们直接上代码:
第一步:导入依赖库
import pandas as pd from sklearn.preprocessing import OneHotEncoder from sklearn.metrics.pairwise import pairwise_distances from sklearn.neighbors import NearestNeighbors
第二步:处理多值字段(比如services)
如果services是类似"Installation,Repair"的字符串,先拆分再做Multi-Hot编码:
# 拆分services字段 df['services'] = df['services'].str.split(',') # 生成Multi-Hot编码的服务特征 services_features = df.explode('services').pivot_table( index='accountname', columns='services', aggfunc='size', fill_value=0 )
第三步:处理其他单值分类字段
对industry、country等字段做One-Hot编码:
# 定义需要编码的分类字段 categorical_cols = ['industry', 'territory', 'country', 'state', 'city'] # 初始化One-Hot编码器 encoder = OneHotEncoder(sparse_output=False, drop='first') # 生成编码后的特征矩阵 cat_features = encoder.fit_transform(df[categorical_cols]) # 转成DataFrame,方便后续合并 cat_features_df = pd.DataFrame( cat_features, columns=encoder.get_feature_names_out(categorical_cols), index=df['accountname'] )
第四步:合并所有特征
把服务特征和分类特征合并成最终的特征矩阵:
final_features = pd.concat([cat_features_df, services_features], axis=1).fillna(0)
方案一:全量相似度矩阵查询(适合小数据)
# 计算Jaccard相似度矩阵(1 - Jaccard距离) jaccard_dist = pairwise_distances(final_features.values, metric='jaccard') similarity_matrix = 1 - jaccard_dist similarity_df = pd.DataFrame( similarity_matrix, index=final_features.index, columns=final_features.index ) # 构建查询函数 def get_similar_customers(account_name, top_n=5): if account_name not in similarity_df.index: return f"账户 {account_name} 不存在于数据中" # 排序并排除自身 sorted_scores = similarity_df[account_name].sort_values(ascending=False) sorted_scores = sorted_scores[sorted_scores.index != account_name] # 获取Top N客户的详细信息 top_customers = df[df['accountname'].isin(sorted_scores.head(top_n).index)].copy() top_customers['similarity_score'] = top_customers['accountname'].map(sorted_scores) return top_customers[['accountname', 'industry', 'country', 'state', 'similarity_score']] # 测试查询 print(get_similar_customers('Jon Doe', top_n=3))
方案二:KNN模型查询(适合大数据)
# 初始化KNN模型,用Jaccard相似度 knn_model = NearestNeighbors(metric='jaccard', n_neighbors=6) # +1是为了排除自身 knn_model.fit(final_features.values) # 构建查询函数 def get_similar_customers_knn(account_name, top_n=5): if account_name not in final_features.index: return f"账户 {account_name} 不存在于数据中" # 找到目标账户的索引 idx = final_features.index.get_loc(account_name) # 查询最近邻 distances, indices = knn_model.kneighbors(final_features.values[idx].reshape(1, -1)) # 提取Top N(排除自身) similar_indices = indices[0][1:top_n+1] similar_scores = 1 - distances[0][1:top_n+1] # 获取客户信息 similar_accounts = final_features.index[similar_indices] top_customers = df[df['accountname'].isin(similar_accounts)].copy() top_customers['similarity_score'] = similar_scores return top_customers[['accountname', 'industry', 'country', 'state', 'similarity_score']] # 测试查询 print(get_similar_customers_knn('Jon Doe', top_n=3))
可选优化点
- 字段权重调整:如果认为industry、country比city更重要,可以给这些字段的编码特征乘以权重(比如industry的特征乘2,country乘1.5),让相似性计算更贴合业务需求。
- 高基数字段处理:如果city这类字段的取值太多(高基数),One-Hot编码后会生成大量特征,可以考虑把city聚合到state层级,或者用频率编码替代One-Hot。
- 相似性解释:可以在返回结果里增加「相似原因」,比如标注两个客户共享了哪些行业、国家等特征,让结果更有说服力。
内容的提问来源于stack exchange,提问作者Saa17
相关产品推荐
相关产品推荐

