如何聚类一组字符串?

Posted

技术标签:

【中文标题】如何聚类一组字符串?【英文标题】:How to cluster a set of strings? 【发布时间】:2015-08-22 15:12:43 【问题描述】:

我的数据集看起来像这样

['', 'ABCDH', '', '', 'H', 'HHIH', '', '', '', '', '', '', '', '', ' ','','','FECABDAI','','','','','','','','','','','','','' ,'','','','','FABHJJFFFFEEFGEE','FFFF','','','','','','','','','','FF ','F','FF','F','F','FFFFFFIFF','','FFFFFFF','F','','','F','','',' ','','','','','F','','','ABB','','','','','','','',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ,'','FF','','','','','','','','','','','','','','', '','F','FFEIE','FF','ABABCDIIJCCFG','','FABACFFF','FEGGIHJCABAGGFEFGGFEECA','','FF','FFGEFGGFFG','F','FFF',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '一世' , '', '', 'ABIIII', '', '', '', '', 'I', '', '', '', '', '', '', '', '' , '', '', '', '', '', '', '', '', '', '', 'AAAAA', 'AFGFE', 'FGFEEFGFEFGFEFGJJGFEACHJ', '', '', ' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ' ','JFEFFFFFFF','','AAIIJFFGEFGCABAGG','','','','','','','','','','F','JFJFJFJ','' ,'','','','','','','','','','','','','','','','',' ','','','F','','','','','','','','','F','','','',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ,'','','','','','','','','','','','','','','','',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ,'','','','','','','','','F','FGFEFGFE','','','','','','' ,'','','','','','','','','','','','','','','','',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ,'','','','','','','','','','','','','','','','',' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

这只是一个示例,但我会有更多的字符串。我如何对它们进行聚类,使每个聚类都有一些模式

【问题讨论】:

顺便说一句:存储/传递所有这些空值真的是强制性的吗? 不,现在可以忽略空字符串。 生物信息学像数据吗? 字符有限制吗?会只选择 7-8 个字符还是可以选择 26 个英文字符或更大的词汇量? 暂时只有A-J,以后可能会增加一些 【参考方案1】:

我建议的想法起源于文本处理、NLP 和信息检索,并且非常广泛地用于您拥有诸如遗传信息之类的字符/信息序列的情况。因为您必须保留序列,所以我们可以使用 n-gram 的概念。我在以下示例中使用了二元语法,尽管您可以概括为更高阶的克数。 N-gram 有助于保留数据中的顺序模式。别担心 - 我们一直在借鉴其他科学领域的想法 - 甚至编辑距离和动态编程最初都不是计算机科学概念。

有许多可能的方法来解决这个问题 - 每一种都是独一无二的,而且没有正确的方法 - 至少没有足够的研究证明哪一种方法是正确的。这是我的看法。

因此,我们的目标是从您的数据字符串中创建一个类似词袋的向量 - 这些向量可以轻松地馈送到任何机器学习工具或库中进行聚类。步骤的快速总结:-

    收集二元组(和一元组等) 创建字典以获取词袋(附代码) 创建从字符串中获取向量的功能

让我们开始吧

import numpy
from sklearn.cluster import KMeans
def getStringBigrams(string):
    if len(string) <= 0: return []
    if len(string) == 1: return string[0] # Handle strings with only one character = extract unigram
    return [string[i]+string[i+1] for i in range(len(string)-1)]

def getDataBigrams(strings):
    return [getStringBigrams(x) for x in strings]

所以这里这些函数会将给定的字符串转换为一组两个字符(如果只有一个字符,则为单个字符)。您可以修改它们以捕获 3-gram 甚至所有可能的 uni-、bi- 和 tri-gram 的完整集。随意尝试。

现在如何将字符串转换为向量?我们将定义一个函数,它将字符串转换为向量,以处理特定 n-gram 出现的次数。这称为 BAG OF WORDS。在这里,这些是屏幕袋。以下两个函数可以帮助您:

def generateDictionary(data):
    '''
    This function identifies unique n-grams in your data.
    '''
    vocab = set()
    for line in data:
        for item in line:
            vocab.add(item)
    dictionary = 
    i=0
    for item in vocab:
        dictionary[item] = i
        i+=1
    return dictionary

    def doc2Bow(bigramData, dictionary):
    ''' 
    Take single document in bigram format and return a vector
    '''
    vect = [0]*len(dictionary) # Initialize vector to zero
    for gram in bigramData:
        vect[dictionary[gram]]+=1
    return numpy.asarray(vect)  # Convert to numpy vector

瞧!我们完成了。现在将您的数据向量提供给您选择的任何 K-Means 实现。我用过SKLearn。

strings = ['', 'ABCDH', '', '', 'H', 'HHIH', '', '', '', '', '', '', '', '', '', '', '', 'FECABDAI', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'FABHJJFFFFEEFGEE', 'FFFF', '', '', '', '', '', '', '', '', '', 'FF', 'F', 'FF', 'F', 'F', 'FFFFFFIFF', '', 'FFFFFFF', 'F', '', '', 'F', '', '', '', '', '', '', '', 'F', '', '', 'ABB', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'FF', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'F', 'FFEIE', 'FF', 'ABABCDIIJCCFG', '', 'FABACFFF', 'FEGGIHJCABAGGFEFGGFEECA', '', 'FF', 'FFGEFGGFFG', 'F', 'FFF', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'I', '', '', 'ABIIII', '', '', '', '', 'I', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AAAAA', 'AFGFE', 'FGFEEFGFEFGFEFGJJGFEACHJ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'JFEFFFFFFF', '', 'AAIIJFFGEFGCABAGG', '', '', '', '', '', '', '', '', '', 'F', 'JFJFJFJ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'F', '', '', '', '', '', '', '', '', 'F', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'F', 'FGFEFGFE', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

你应该选择从文件中读取字符串

strings = [x for x in strings if len(x) > 0] # Just cleanup for experiment purpose
nGramData = getDataBigrams(strings)
dictionary = generateDictionary(nGramData)
data = [doc2Bow(nGramData[i], dictionary) for i in range(len(nGramData))]

K = 10
km = KMeans(init='k-means++', n_clusters=K, n_init=10)

km.fit(data)

然后我终于看到使用 KMeans 类的 km.labels_ 属性的集群是什么样子了。

这是您的集群。查看控制台(底部)窗口 - 有十个集群。

现在您可以修改我在代码中编写的特征生成,看看您的修改效果如何。不仅仅是二元组,提取所有可能的一元组、二元组和三元组,并使用它们来创建 BOW。会有显着差异。您还可以使用字符串的长度作为特征。您还可以尝试其他算法,包括层次聚类。请务必在修改后将更新的结果发送给我。

享受吧!

【讨论】:

以上是关于如何聚类一组字符串?的主要内容,如果未能解决你的问题,请参考以下文章

聚类(尤其是字符串聚类)如何工作?

根据2个(理想情况下推广到n个)任意分组规则对字母字符串列表进行聚类?

字符字符串和文本的处理之String类型

如何在 r 中对充满字符串变量的数据集进行 K-means 聚类

Mahout canopy聚类

如何从 scikit-learn KMeans 中获取聚类中心的文本?