我可以在字符串上使用 K-means 算法吗?

Posted

技术标签:

【中文标题】我可以在字符串上使用 K-means 算法吗?【英文标题】:Can I use K-means algorithm on a string? 【发布时间】:2011-09-11 17:25:57 【问题描述】:

我正在研究一个 python 项目,我在其中研究 RNA 结构进化(表示为字符串,例如:“(((...)))”,其中括号表示碱基对)。关键是我有一个理想的结构和一个朝着理想结构发展的人口。我已经实现了一切,但是我想添加一个功能,我可以在其中获得“桶数”,即每一代人口中最具代表性的 k 个结构。

我正在考虑使用 k-means 算法,但我不确定如何将它与字符串一起使用。我找到了scipy.cluster.vq,但我不知道如何在我的情况下使用它。

谢谢!

【问题讨论】:

【参考方案1】:

如果使用scipy.cluster.vq.kmeans,您将面临的一个问题是该函数使用欧几里得距离来测量接近度。要将您的问题固定为可通过k-means 聚类解决的问题,您必须找到一种将字符串转换为数值向量的方法,并能够证明使用欧几里得距离作为接近度的合理衡量标准。

这似乎……很难。也许您正在寻找Levenshtein distance?

请注意,variants of the K-means algorithm 可以使用非欧几里得距离度量(例如 Levenshtein 距离)。 K-medoids(又名 PAM),例如,can be applied to data with an arbitrary distance metric。

例如,使用Pycluster's实现k-medoids,和nltk's实现Levenshtein距离,

import nltk.metrics.distance as distance
import Pycluster as PC

words = ['apple', 'Doppler', 'applaud', 'append', 'barker', 
         'baker', 'bismark', 'park', 'stake', 'steak', 'teak', 'sleek']

dist = [distance.edit_distance(words[i], words[j]) 
        for i in range(1, len(words))
        for j in range(0, i)]

labels, error, nfound = PC.kmedoids(dist, nclusters=3)
cluster = dict()
for word, label in zip(words, labels):
    cluster.setdefault(label, []).append(word)
for label, grp in cluster.items():
    print(grp)

产生类似的结果

['apple', 'Doppler', 'applaud', 'append']
['stake', 'steak', 'teak', 'sleek']
['barker', 'baker', 'bismark', 'park']

【讨论】:

【参考方案2】:

K-means 仅适用于欧式距离。编辑距离(例如 Levenshtein)不甚至不服从三角不等式 可能服从三角不等式,但不是欧几里得。对于您感兴趣的指标类型,您最好使用不同类型的算法,例如层次聚类:http://en.wikipedia.org/wiki/Hierarchical_clustering

或者,只需将您的 RNA 列表转换为加权图,边缘带有 Levenshtein 权重,然后将其分解为最小生成树。从某种意义上说,该树中连接最多的节点将是“最具代表性的”。

【讨论】:

Levenshtein Distance and the Triangle Inequality 谢谢,已修复!尴尬的是,博客的作者是我的朋友:-)【参考方案3】:

K-means 并不真正关心所涉及的数据类型。做 K-means 所需要的只是某种方法来测量从一个项目到另一个项目的“距离”。它会根据距离来做自己的事情,而不管它是如何从基础数据中计算出来的。

也就是说,我没有使用过scipy.cluster.vq,所以我不确定你如何准确地告诉它项目之间的关系,或者如何计算从项目 A 到项目 B 的距离。

【讨论】:

这个答案没有任何意义。两串RNA之间的“距离”是多少,使得它A)服从三角不等式,B)是欧几里得?有很多聚类算法,在这种情况下,k-means 尤其有用,这似乎超出了我的理解。 我使用的距离是结构距离,例如序列:(1) "(((..)))" 和 (2) "((((..)) ))" 距离为 1,因为插入的唯一区别 杰瑞,你能解释一下这怎么可能吗?正如@sclv 在他的回答中提到的,K-means 仅适用于欧几里得距离。似乎不可能将其应用于字符串,因为在每一步,您都需要将质心移动到代表最近数据点平均值的绝对位置......对于任意距离度量,似乎 K-medoids 会起作用,因为它改为使用数据点作为质心。 @codesparkle:我没有试图告诉他他的距离测量会起作用——我只是指出(至少部分)K-means 起作用的要求。肯定有符合这些要求的字符串之间的差异度量(例如,余弦相似度)。哦,sclv 的说法也不完全正确:余弦相似度并不是严格意义上的欧几里得度量,但确实很好。 k-means 接受质心的多种定义(例如,3),对所使用的度量有不同的要求。 这个答案是错误的。 K-means 还需要计算 means,这需要浮点数,并且需要平方欧几里得或伯格曼散度作为“距离”。【参考方案4】:

Kmeans 需要的是“距离”度量(代表向量的数字,以便它可以找到向量之间的距离并根据距离将它们聚集在质心周围)。以下是我为您编写的一些示例:

假设您有表示日期的字符串,例如2019-06-27 15:52:41.623Z。在这种情况下,您要做的是选择一个日期,比如 UTC 时间戳开始的时间。现在以开始日期和时间为参考,您可以计算到每个日期字符串的“距离”。

假设您有代码字符串,if(a == b)if(a == c) 那么您可能想要使用不同的“距离”,例如 字符串之间不同的字符。

或者如果你有 html DOM 结构,<html></html> vs <html><head></head></html> 你可能不想计算字符数 但是有多少标签与您的“距离”不同。

或者对于数据库中的已知枚举,您可以根据自己的枚举之间的“距离”概念将每个键定义为不同的数字。例如,“男性”、“女性”、“中性”如果定义为向量 [0]、[1]、[2],则意味着中性比男性更接近女性。所以你可能想做 [0],[2],[1] 或 [-1],[1],[0]。

对于问题中询问的 RNA/DNA 结构,“距离”可能是 链之间有多少个碱基对不同。

我希望你能明白。因此,您需要考虑字符串的内容是什么,并考虑定义内容之间“距离”的最佳方法。简单的字符差异距离可以作为字符串之间的通用距离度量,但是如果您获得更好的距离想法,您的算法会更好地工作。

【讨论】:

以上是关于我可以在字符串上使用 K-means 算法吗?的主要内容,如果未能解决你的问题,请参考以下文章

K-means真的不能使用曼哈顿距离吗?

在线 k-means 聚类

K-Means 算法 [重复]

K-Means 算法 [重复]

聚类算法,k-means,高斯混合模型(GMM)

自动确定簇数 k-means