Как использовать sklearn.metrics.pairwise pairwise_distances с вызываемой метрикой?
Я делаю некоторый анализ поведения, где отслеживаю поведение с течением времени, а затем создаю n-граммы этого поведения.
sample_n_gram_list = [['scratch', 'scratch', 'scratch', 'scratch', 'scratch'],
['scratch', 'scratch', 'scratch', 'scratch', 'smell/sniff'],
['scratch', 'scratch', 'scratch', 'sit', 'stand']]
Я хочу иметь возможность кластеризовать эти n-граммы, но мне нужно создать предварительно вычисленную матрицу расстояний, используя собственную метрику. Моя метрика работает нормально, но когда я пытаюсь создать матрицу расстояний с помощью функции 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 ответ
Это потому что pairwise_distances
in 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.]])