【问题标题】:Efficiently grouping sets based on number of similar items根据相似项目的数量有效地对集合进行分组
【发布时间】:2018-12-23 01:01:01
【问题描述】:

我有一个表格集合列表

animals[0] = {'cat', 'cow', 'dog'}
animals[1] = {'cat', 'cow', 'pig'}
animals[2] = {'cat', 'dog', 'fish'}
animals[3] = {'tiger', 'fish', 'pig'}
animals[4] = {'dog', 'fish', 'pig'}

如何对至少有 2 个相似项目的集合进行分组?为简单起见,我将使用一个 dict,其键是重叠集的第一个元素,并且不关心属于该键的某些项目是否少于 2 个相似项目。例如,

g['cat'] = [0,1,2]
g['fish'] = [2,3,4]

因为列表 0 和 1 有重叠项 cat 和 cow,而列表 0 和 2 有重叠项 cat 和 dog。然而,列表 1 和 2 只有重叠项 cat 但仍包含在字典中。一个简单的蛮力方法是遍历整个列表并检查每个列表与其他列表。

for i,x in enumerate(animals):
    for j,y in enumerate(animals):

        intersection = x & y
        if(len(intersection)>=2):
            dict[list(intersection)[0]].append(j)

但是如果我有一个非常大的列表,我认为这非常耗时,所以我想学习一种更好的方法来做到这一点。如果有人有什么功能可以推荐。

【问题讨论】:

  • 嗨!我们在谈论多大?如果这是一个市场篮子问题,我可以根据要处理的数据集的大小提出各种方法。
  • 这里不应该fish[2,3,4] 吗?
  • 这个问题有问题。动物[2] = {'cat', 'dog', 'fish'} 和 animals[4] = {'dog', 'fish', 'pig'} 有 2 个相同的项目,为什么鱼字典中没有 4 个?
  • @RoadRunner 和 Marcus.Aurelianus 是的,你是对的 :) 我在我的例子中忘记了这一点

标签: python set grouping


【解决方案1】:

使用余弦相似度的解决方案

关于稀疏矩阵

如果您谈论的是大型数据集,您应该考虑使用sparse matrix。特别是,我将要描述的技术可以很好地扩展,并且可以与MapReduce-like 框架一起使用。

因此,在继续之前,我会将您给出的示例转换为稀疏矩阵。以下方法绝不是最快的方法,通常它取决于您的数据是如何生成的,例如您是否已经拥有一套完整的数据集,或者您正在处理处理流的在线算法。

未知全集注意事项

如果您正在处理 unknown 完整集,这是处理在线算法时的常见问题,您可以尝试创建一个哈希函数族,以将您的键映射到 N 并逐渐散列函数,直到您有足够低的 误报 率(键映射到另一个键的存储桶)。

将集合转换为稀疏矩阵

我们现在继续assuming,您有一个称为all_the_animals 的有序完整集,它允许您将无序集映射到N

animals = [{'cat', 'cow', 'dog'},
{'cat', 'cow', 'pig'},
{'cat', 'dog', 'fish'},
{'tiger', 'fish', 'pig'},
{'dog', 'fish', 'pig'}]

all_the_animals = ['cat', 'cow', 'dog', 'pig', 'fish', 'tiger']

实际转化:

import scipy.sparse as sparse

def binarise(sets, full_set):
    """Return sparse binary matrix of given sets."""
    return sparse.csr_matrix([[x in s for x in full_set] for s in sets])

所以要得到你需要运行的稀疏矩阵:

sparse_matrix = binarise(animals, all_the_animals)

使用余弦相似度

一旦你有了稀疏矩阵,你就可以继续使用来自sklearncosine similarity,它被定义为:

from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity(sparse_matrix)

可视化余弦相似度

得到相似度矩阵的样子,使用seaborn.heatmap

import matplotlib.pyplot as plt
import seaborn
seaborn.heatmap(s, annot=True, cmap="YlGnBu")
plt.show()

阈值

现在您可以选择相似度阈值。例如,在您的问题中,您要求 2/3 的元素是共同的:

threshold = 2/3

使用numpy.where可以执行:

import numpy as np
similar = np.where(similarities >= threshold)

获取:

(array([0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4]),
 array([0, 1, 2, 0, 1, 0, 2, 4, 3, 4, 2, 3, 4]))

提取相似组

现在我们有了一组可以运行的similar_animals:

similar_sets = [(i, similar[1][similar[0]==i]) for i in np.unique(similar[0]))]

结果如下:

[(0, array([0, 1, 2])),
 (1, array([0, 1])),
 (2, array([0, 2, 4])),
 (3, array([3, 4])),
 (4, array([2, 3, 4]))]

要可视化结果,您可以使用有序集来获取动物名称:

similar_animal_sets = [(all_the_animals[i], similar_set) for i, similar_set in similar_sets]

哪个输出:

[('cat', array([0, 1, 2])),
 ('cow', array([0, 1])),
 ('dog', array([0, 2, 4])),
 ('pig', array([3, 4])),
 ('fish', array([2, 3, 4]))]

【讨论】:

  • 非常感谢您的解决方案!我也忘记了余弦相似度,这对我来说非常有用,因为我的所有列表都是固定长度的。
猜你喜欢
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-13
相关资源
最近更新 更多