【问题标题】:Similarity of list elements列表元素的相似度
【发布时间】:2019-02-08 19:46:49
【问题描述】:

我有十个列表,我想获得它们的“相似性”。这是我的输入:

data = [
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'SeasonNumber', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'SeasonNumber', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'Genres', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', '_StudioName', 'Type', 'LanguageOfMetadata', 'ReleaseDate', 'Studio', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'TVSeriesID', 'Locales', 'EpisodeNumber', 'Name', 'Synopsis', 'Products', 'SeasonNumber', 'Platform'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'LanguageOfMetadata', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'Genres', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', '_StudioName', 'Type', 'LanguageOfMetadata', 'ReleaseDate', 'Studio', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'TVSeriesID', 'Locales', 'EpisodeNumber', 'Name', 'Synopsis', 'Products', 'SeasonNumber', 'Platform'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'ReleaseDate', 'Genres', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales'], 
    ['RuntimeInMinutes', 'EpisodeNumber', 'Genres', 'ReleaseDate', 'Name', 'Platform', 'PlatformID', 'BaseURL', 'Languages', 'ArtworkURL', 'Synopsis', 'TVSeriesID', 'Products', '_NetworkName', 'ReleaseYear', '_ContentProviderName', 'Studio', '_StudioName', 'Type', 'Locales']
]

我目前的方法是将这些值的集合的长度与总长度进行比较。所以在上面它会是:

>>> len(set(data))/len(data)
0.5

但这很粗略,因为我想得到一个不是“全有或全无”的相似性。换句话说,类似于概念上的相似性,上面可能有 98% 的相似性(很抱歉,如果我无法准确地解释我在这里想要什么——但我的意思是评估相似性不仅仅是列表本身,而是元素的相似性。

【问题讨论】:

  • 你在考虑不同元素的相似性吗? ['apple']['apple1'] 会是完全不同的列表,因为它们不共享元素,还是相似的列表,因为它们的元素非常接近?
  • @PatrickHaugh 这些元素需要相同。所以苹果!= apple1

标签: python python-3.x algorithm list


【解决方案1】:

看看datasketch library 及其MinHash 数据结构。这基于集合的Jaccard Similarity,它只是交集(它们的共同点)除以并集(所有可能的元素)。

这是一个例子:

from datasketch import MinHash

data1 = ['minhash', 'is', 'a', 'probabilistic', 'data', 'structure', 'for',
        'estimating', 'the', 'similarity', 'between', 'datasets']
data2 = ['minhash', 'is', 'a', 'probability', 'data', 'structure', 'for',
        'estimating', 'the', 'similarity', 'between', 'documents']

m1, m2 = MinHash(), MinHash()
for d in data1:
    m1.update(d.encode('utf8'))
for d in data2:
    m2.update(d.encode('utf8'))
print("Estimated Jaccard for data1 and data2 is", m1.jaccard(m2))

如果您的集合很大,则可以估计相似度。否则,只需使用内置的集合操作:

s1 = set(data1)
s2 = set(data2)
actual_jaccard = float(len(s1.intersection(s2)))/float(len(s1.union(s2)))
print("Actual Jaccard for data1 and data2 is", actual_jaccard)

如果你想取两个以上的 Jaccard 相似度,只需计算pairwise-comparison 并取所有值的平均值(平均值):

from datasketch import *
import itertools
minhash_data = list()
for element in data:
    m = MinHash()
    for d in element:
        m.update(d.encode('utf-8'))
    minhash_data.append(m)

jaccard_sims = list()
for pair in itertools.combinations(minhash_data, 2):
    jaccard_sims.append(pair[0].jaccard(pair[1]))

average = sum(jaccard_sims) / float(len(jaccard_sims))
print("Average Jaccard similarity: {}".format(average))

平均 Jaccard 相似度:0.9512152777777778

【讨论】:

  • 感谢您的建议。但是,您将如何为十个对象执行此操作?上面比较了两个文档。
  • 你可以取所有它们的成对jaccard相似度。然后取数字的平均值。
  • 您是否要使用我提供的输入数据展示一个示例,然后我会继续接受您的回答?
  • 当然,我刚刚添加了它。
【解决方案2】:

当您说要获得两个列表之间的相似性时,有多种方法可以做到这一点。像@Nick Pandey Jaccard 相似度。另一个称为tanimoto ratio 的比率也很有效。

这是我的实现:

def tanimoto (list1, list2):
    intersection = [common_item for common_item in list1 if common_item in list2]
    return float(len(c))/(len(a) + len(b) - len(c))

现在,解决您必须同时比较 10 个列表的问题。您只能使用上述方法同时比较两个元素。但是,您可以开发自己的逻辑,让您大致了解所有事物之间的相似程度。

例如,您可以一次获取五个列表并进行比较,或者更好的选择是比较前两个列表,存储 tanimoto 系数,比较接下来的两个并重复。最后取系数的平均值。代码更好:

def grouped(iterable, n):
    return zip(*[iter(iterable)]*n)

coeffs = []
for i, j in grouped(data, 2): # data refers to the variable in the question
    coeffs.append(tanimoto(i, j))

similarity = sum(coeffs)/len(coeffs)

希望这会有所帮助:)

【讨论】:

    猜你喜欢
    • 2014-05-14
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多