代码之家  ›  专栏  ›  技术社区  ›  not-bob

如何使用sklearn.metrics.pairwise pairwise ou Distances with Callable metric?

  •  1
  • not-bob  · 技术社区  · 7 年前

    我正在做一些行为分析,在那里我跟踪一段时间后的行为,然后创建这些行为的n个图。

    sample_n_gram_list = [['scratch', 'scratch', 'scratch', 'scratch', 'scratch'],
                          ['scratch', 'scratch', 'scratch', 'scratch', 'smell/sniff'],
                          ['scratch', 'scratch', 'scratch', 'sit', 'stand']]
    

    我想能够集群这些N-gram,但我需要使用自定义度量创建一个预先计算的距离矩阵。我的度量似乎工作正常,但当我尝试使用sklearn函数创建距离矩阵时,我得到一个错误:

    ValueError: could not convert string to float: 'scratch'
    

    我看过文件了 https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise_distances.html 在这个问题上还不太清楚。

    有人知道如何正确使用这个吗?


    完整代码如下:

    import pandas as pd
    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib.mlab as mlab
    import math
    import hashlib 
    import networkx as nx
    import itertools
    import hdbscan
    from sklearn.metrics.pairwise import pairwise_distances
    
    def get_levenshtein_distance(path1, path2):
        """
        https://en.wikipedia.org/wiki/Levenshtein_distance
        :param path1:
        :param path2:
        :return:
        """
        matrix = [[0 for x in range(len(path2) + 1)] for x in range(len(path1) + 1)]
    
        for x in range(len(path1) + 1):
            matrix[x][0] = x
        for y in range(len(path2) + 1):
            matrix[0][y] = y
    
        for x in range(1, len(path1) + 1):
            for y in range(1, len(path2) + 1):
                if path1[x - 1] == path2[y - 1]:
                    matrix[x][y] = min(
                        matrix[x - 1][y] + 1,
                        matrix[x - 1][y - 1],
                        matrix[x][y - 1] + 1
                    )
                else:
                    matrix[x][y] = min(
                        matrix[x - 1][y] + 1,
                        matrix[x - 1][y - 1] + 1,
                        matrix[x][y - 1] + 1
                    )
    
        return matrix[len(path1)][len(path2)]
    
    sample_n_gram_list = [['scratch', 'scratch', 'scratch', 'scratch', 'scratch'],
                          ['scratch', 'scratch', 'scratch', 'scratch', 'smell/sniff'],
                          ['scratch', 'scratch', 'scratch', 'sit', 'stand']]
    
    print("should be 0")
    print(get_levenshtein_distance(sample_n_gram_list[1],sample_n_gram_list[1]))
    print("should be 1")
    print(get_levenshtein_distance(sample_n_gram_list[1],sample_n_gram_list[0]))
    print("should be 2")
    print(get_levenshtein_distance(sample_n_gram_list[0],sample_n_gram_list[2]))
    
    clust_number = 2
    distance_matrix = pairwise_distances(sample_n_gram_list, metric=get_levenshtein_distance)
    clusterer = hdbscan.HDBSCAN(metric='precomputed')
    clusterer.fit(distance_matrix)
    clusterer.labels_
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Vivek Kumar    7 年前

    那是因为 pairwise_distances 在sklearn中,设计用于数值数组(这样所有不同的内置距离函数都可以正常工作),但是您要向它传递一个字符串列表。如果您可以将字符串转换为数字(将字符串编码为特定的数字),然后传递它,它将正常工作。

    一种快速麻木的方法是:

    # Get all the unique strings in the input data
    uniques = np.unique(sample_n_gram_list)
    # Output:
    # array(['scratch', 'sit', 'smell/sniff', 'stand'])
    
    # Encode the strings to numbers according to the indices in "uniques" array
    X = np.searchsorted(uniques, sample_n_gram_list)
    
    # Output:
    # array([[0, 0, 0, 0, 0],    <= scratch is assigned 0, sit = 1 and so on
             [0, 0, 0, 0, 2],
             [0, 0, 0, 1, 3]])
    
    
    # Now this works
    distance_matrix = pairwise_distances(X, metric=get_levenshtein_distance)
    
    # Output
    # array([[0., 1., 2.],
             [1., 0., 2.],
             [2., 2., 0.]])
    
    推荐文章