【问题标题】:How can I construct a distance or dissimilarity matrix?如何构建距离或相异矩阵?
【发布时间】:2019-09-09 04:06:02
【问题描述】:

我有一个df如下:

0    111155555511111116666611111111
1    555555111111111116666611222222
2    221111114444411111111777777777
3    111111116666666661111111111111
.......
1000  114444111111111111555555111111

我正在计算每个字符串之间的距离。例如,要获取前 2 个字符串之间的距离:textdistance.hamming(df[0], df[1])。这将返回一个整数。

现在,我想创建一个 df 来存储每个字符串之间的所有距离。在这种情况下,由于我有 1000 个字符串,我将有一个 1000 x 1000 df。第一个值是字符串 1 与自身之间的距离,然后是字符串 1 和字符串 2,依此类推。然后在下一行它的字符串 2 和 string1,字符串 2 和它本身等等。

【问题讨论】:

    标签: python pandas distance-matrix


    【解决方案1】:

    创建Series 的所有值组合并在列表中获取hamming 距离,然后转换为数组并为DataFrame 重塑:

    import textdistance
    from  itertools import product
    
    L = [textdistance.hamming(x, y) for x , y in product(df, repeat=2)]
    df = pd.DataFrame(np.array(L).reshape(len(df), len(df)))
    print (df)
        0   1   2   3   4
    0   0  14  24  18  15
    1  14   0  24  26  19
    2  24  24   0  20  23
    3  18  26  20   0  19
    4  15  19  23  19   0
    

    编辑:

    为了提高性能,请使用 this 更改 lambda 函数的解决方案:

    import numpy as np    
    from scipy.spatial.distance import pdist, squareform
    
    # prepare 2 dimensional array M x N (M entries (3) with N dimensions (1)) 
    transformed_strings = np.array(df).reshape(-1,1)
    
    # calculate condensed distance matrix by wrapping the hamming distance function
    distance_matrix = pdist(transformed_strings,lambda x,y: textdistance.hamming(x[0],y[0]))
    
    # get square matrix
    df1 = pd.DataFrame(squareform(distance_matrix), dtype=int)
    print (df1)
        0   1   2   3   4
    0   0  14  24  18  15
    1  14   0  24  26  19
    2  24  24   0  20  23
    3  18  26  20   0  19
    4  15  19  23  19   0
    

    【讨论】:

    • 这个解决方案看起来不错,但是,我在我的 jupyter notebook 上卡了 1 个多小时才能完成执行。也许 itertools.product() 不适合更大尺寸的计算。就我而言,我有 2000 行
    • pdist 内置支持汉明距离。我认为您可以使用 metric="hamming" 调用它以获得更好的性能。
    • @GZ0 - 我用print (pdist(transformed_strings, metric="hamming"))print (pdist(pd.concat([df, df], axis=1).values, metric="hamming")) 进行了测试,两者都返回[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]...
    • @jezrael 距离函数作用于数组/列表。如果将两个字符串传递给它,它们将被视为两个长度为 1 的列表。每个字符串都需要先转换成数组/列表。