根据相似项目的数量有效地对集合进行分组

时间:2018-07-15 05:39:37

标签: python set grouping

我有一组表格的形式

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)

但是,如果我认为清单很大,这将非常耗时,因此我想学习一种更好的方法。如果有人有任何推荐功能。

1 个答案:

答案 0 :(得分:4)

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

关于稀疏矩阵

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

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

关于未知全套的注释

如果要处理的是未知完整集,这是处理在线算法时的常见问题,则可以尝试创建一个散列函数系列,以将密钥映射到 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)

使用余弦相似度

一旦有了稀疏矩阵,就可以继续使用cosine similarity中的sklearn,它的定义为:

Cosine 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()

Cosine similarities

阈值

现在,您可以选择相似性阈值。例如,在您的问题中,您要求元素的 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_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]))]