如何转换字符串格式Series为数值集合正确计算杰卡德相似度
问题根因
计算结果错误来自两处逻辑缺陷:
- 目标列存储的是单元素列表,列表内为逗号拼接的产品ID整串,直接转set只会得到包含整串的单元素集合,无法按单个产品ID计算交集
- 取数时传入列名列表
[column]会返回Series对象,直接转set会混入索引值,进一步干扰集合运算结果
修复方案
1. 预处理目标列
先统一把目标列处理为单个产品ID组成的集合,兼容不同行ID数量不一致的场景:
# 逐行转换:如果值是列表则先取内部字符串,按逗号拆分后转集合;如果直接是字符串则直接拆分 data[column] = data[column].apply( lambda x: set(x[0].split(',') if isinstance(x, list) else x.split(',')) )
处理后每行值为{'1','3','16','17','19'}格式的标准集合,可直接用于交并集运算。
2. 修正相似度计算函数
优化取数逻辑,避免循环内重复计算,返回结果保留原行索引方便匹配客户:
def set_sim(cust_id, data, column): sim_set = [] # 提前缓存目标客户的产品集合与长度,减少循环内重复取数 target_prod = data.loc[cust_id, column] target_len = len(target_prod) for idx in data.index: current_prod = data.loc[idx, column] inter_len = len(target_prod.intersection(current_prod)) # 杰卡德相似度 = 交集大小 / 并集大小 jaccard_sim = inter_len / (target_len + len(current_prod) - inter_len) sim_set.append(jaccard_sim) return pd.DataFrame(sim_set, index=data.index, columns=['jaccard_similarity'])
批量计算优化(可选)
如果需要计算全量客户两两之间的杰卡德相似度,可使用向量化运算替代for循环,数据量较大时运行效率可提升数十倍:
from sklearn.feature_extraction.text import CountVectorizer from sklearn.metrics.pairwise import pairwise_distances # 将集合转换为空格分隔的字符串,适配向量化输入 corpus = data[column].apply(lambda x: ' '.join(x)) # 生成客户-产品0-1矩阵,仅标记产品是否持有 cv = CountVectorizer(binary=True) prod_matrix = cv.fit_transform(corpus) # 杰卡德距离 = 1 - 杰卡德相似度,转换得到相似度矩阵 sim_matrix = 1 - pairwise_distances(prod_matrix, metric='jaccard') # 转换为带客户索引的DataFrame,行列均为cust_id sim_df = pd.DataFrame(sim_matrix, index=data.index, columns=data.index)
内容的提问来源于stack exchange,提问作者Nick15
相关产品推荐
相关产品推荐

