【问题标题】:Similarity of lists in Python - comparing customers according to their featuresPython中列表的相似性-根据客户的特征比较客户
【发布时间】:2013-05-29 11:26:04
【问题描述】:

我有以下格式的客户和功能列表:

UserID, Feature1, Feature2, Feature3, Feature4

所以我有一个列表——称为“客户”——它看起来像这样:

[
['975676924', '1345207523', '-1953633084', '-2041119774', '587903155'], 
['1619201613', '-1384105381', '1433106581', '1445361759', '587903155'], 
['-1470352544', '-1068707556', '-1002282042', '-563691616', '587903155'], 
['-1958275692', '-739953679', '69580355', '-481818422', '587903155'],
['1619201613', '-739953679', '-1002282042', '-481818422', '587903155']
]

每一行都是具有特定特征的交易。每行中的第一个元素是执行该交易的用户 ID(客户)。因此,Customers[1] 给出了第二行,Customers[1][0] 给出了该行的用户 ID (1619201613)。

用户 ID 可以在其他行(新交易)中重复,因为重复的客户将被附加到列表中。因此,例如,请注意 Customers[4][0] 提供相同的用户 ID (1619201613),但 Customers[4] 的功能与 Customers[1] 的功能不同——即,客户回来购买了不同的产品具有不同的功能。

所以这里的核心问题是:我如何有效地计算我列表中每两个不同客户之间的相似度?
我认为这个问题实际上应该分为两个不同的问题/任务:

  1. 将不同的 UserID 组合在一起。所以第一个问题是:如何有效地将单个 UserID 的所有不同特征组合在一起,例如,Customers[1]Customers[4] 被放入一个新行(新列表?),形式如下:
    ['1619201613', '-1384105381', '1433106581', '1445361759', '587903155', '-739953679', '-1002282042', '-481818422']

  2. 通过交易发现客户的相似性。所以第二个问题是:我如何有效地评估[0,1] 中的相似函数,它告诉我两个不同的客户是否对相同的东西感兴趣?


PS。一些附加说明:

  1. 特征的顺序无关紧要,因为它们是经过散列的并且是唯一标识的。
  2. 特征的基数也无关紧要,即,我们不在乎相同的特征是否针对相同的 UserID 出现两次或三次。
  3. 整个事情的最终结果是能够获得一个客户网络,其中 UserID 是节点,它们之间的边由相似度得分加权。
  4. 我更喜欢余弦相似度或 Jaccard 索引,但对替代方案持开放态度。
  5. 我需要速度和可扩展性,即使这会在一定程度上牺牲一些准确性。
  6. 我已经彻底检查了以前的问题 - 例如,以下问题不相关:Calculating the similarity of two lists; Python Checking Multiple Lists For Similarities; How to compute the similarity between lists of features?

【问题讨论】:

  • 对于一个完整的问题,您应该显示您当前的尝试
  • 我无法进行第一次尝试,jamylak。我对 Python 比较陌生,我在这种情况下使用它,以便扩展到数十万用户并将它们作为网络处理(然后使用我更熟悉的 NetworkX)。

标签: python list machine-learning similarity


【解决方案1】:

这回答了您的问题之一:

raw_data = [
['975676924', '1345207523', '-1953633084', '-2041119774', '587903155'],
['1619201613', '-1384105381', '1433106581', '1445361759', '587903155'],
['-1470352544', '-1068707556', '-1002282042', '-563691616', '587903155'],
['-1958275692', '-739953679', '69580355', '-481818422', '587903155'],
['1619201613', '-739953679', '-1002282042', '-481818422', '587903155']
]

import collections
data = collections.defaultdict(list)

for line in raw_data:
    data[line[0]].extend(line[1:])

现在你有了一个以 id 为键的字典:

defaultdict(<type 'list'>, {
'1619201613': 
         ['-1384105381', '1433106581', '1445361759', '587903155',
          '-739953679', '-1002282042', '-481818422', '587903155'],  
'-1470352544': 
         ['-1068707556', '-1002282042', '-563691616', '587903155'], 
 '975676924': 
        ['1345207523', '-1953633084', '-2041119774', '587903155'],
 '-1958275692':
         ['-739953679', '69580355', '-481818422', '587903155']})  

您将通过重新排列获得所需的列表:

data_list = [[key] + value for key, value in data.items()]

【讨论】:

    【解决方案2】:

    第 1 步:假设您的列表名为 l,对不同的用户进行分组

    summary = {}  # init a map for group
    for entry in l:
        if summary[entry[0]]:
            summary[entry[0]] += entry[1:]
        else:
            summary[entry[0]] = entry[1:]
    
    # delete duplicate element
    for s in summary:
        summary[s] = [int(x) for x in list(set(summary[s]))]
    

    第二步:搭建一个网络,其实是一个二维数组,计算不同用户之间的相似度。

    # the row and column number of this array
    cnt = len(summary) 
    network = [[0] * cnt] * cnt
    
    index = [x for x in summary]
    for x, xvalue in enumerate(index):
        for y, yvalue in enumerate(index):
            common = len(set(summary[xvalue]) & set(summary[yvalue]))
            network[x][y] = common
    

    现在网络是一个二维数组,包含每个 UserID 之间的公共项目编号。

    例如,您的列表是:

    [['100', '2', '3','4'],
     ['110', '2', '5', '6'],
     ['120', '6', '3', '4']]
    

    那么网络是:

    [[3, 1, 2],
     [1, 3, 1],
     [2, 1, 3]]
    

    部分代码取自this question

    【讨论】:

    • 谢谢罗杰。第一步生成一个空字典(用于摘要)。第二个(改编自 Mike 的第二个答案中的字典)生成了一个 NxN 表,但它对我来说看起来不正确 - 有一列全为 0,对角线并不总是等于 1。也许我读错了当然是你的答案!
    • 对不起。第一步是错误的,我已经修复了。第二步生成的网络告诉两个用户都购买了多少物品。例如,[0,1] 中的元素为 1,表示 User0 和 User1 购买了 1 件相同的商品。如果值为 0,那么这两个用户没有相同的项目。您可以为每个元素添加 1,以使矩阵中没有 0。
    • 感谢 Roger - 第一部分现在可以很好地处理小型数据集(最多 10k 行),但在处理超过 100 万行时会遇到困难。在更大的情况下,我得到“内存不足”。我在其他地方(stackoverflow.com/questions/11283220/memory-error-in-python)看到可以使用 baffer?你知道吗?
    • 哪个语句导致内存不足?
    • Out of Memory 是由 for 循环引起的(第一个,它建立了“summary”)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-26
    • 2022-06-11
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    相关资源
    最近更新 更多