我是数据工程师,对ML方法的理解有限,我试图在开始编码之前获得一个我理解的好策略。我要做的是创建集群的键值对,键是一个名称,值是某种类型的字符串列表。
目标是基于各自字符串列表的相似性,创建名称的自然集群。
import pandas as pd
df = pd.DataFrame({"name":['lion','leopard','racoon','possum'],
"features":[
['mane', 'teeth', 'tail', 'carnivore'],
['spots', 'teeth', 'tail', 'carnivore'],
['stripes', 'teeth', 'omnivore', 'small'],
['teeth', 'omnivore', 'small']]})
df
例如,在这个数据集中,我期望的自然分组是狮子/豹和浣熊/负鼠,因为teeth, tail and carnivore
这两个词很相似我已经做过的一种方法是比较一个条目,例如狮子,遍历每个列表并将其与其他值进行比较,如果在另一个列表中找到一个值,则为其分配相似性分数。然而,我喜欢使用k-means聚类算法来学习如何主要使用它,但我也希望它能提供更有意义的聚类系列。
我想我挂起来的地方是文本到数字表示的转换以及如何最好地做到这一点,在那之后,我觉得有一些KMeans教程我可能会遵循,但如果有人对如何处理这个问题有任何建议,我会非常感兴趣。
有很多方法可以解决这个问题。但总的来说,这里有一些简单的替代方法——
- 向量表示-使用单热编码或TF-IDF来表示句子
- 特征提取(可选)在大型复杂句子的情况下,您可能需要使用主题模型来提取主题级特征。 集群
- -可以使用任何聚类方法,如K-means
下面是一个示例代码。
1。进口,数据
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.cluster import KMeans
import pandas as pd
df = pd.DataFrame({"name":['lion','leopard','racoon','possum'],
"features":[
['mane', 'teeth', 'tail', 'carnivore'],
['spots', 'teeth', 'tail', 'carnivore'],
['stripes', 'teeth', 'omnivore', 'small'],
['teeth', 'omnivore', 'small']]})
print(df)
name features
0 lion [mane, teeth, tail, carnivore]
1 leopard [spots, teeth, tail, carnivore]
2 racoon [stripes, teeth, omnivore, small]
3 possum [teeth, omnivore, small]
2。向量表示
你可以使用来自sklearn的多标签二值化器使用单热编码的句子
mlb = MultiLabelBinarizer()
vec = mlb.fit_transform(df['features'])
vectors = pd.DataFrame(vec, columns=mlb.classes_)
vectors
carnivore mane omnivore small spots stripes tail teeth
0 1 1 0 0 0 0 1 1
1 1 0 0 0 1 0 1 1
2 0 0 1 1 0 1 0 1
3 0 0 1 1 0 0 0 1
或者你可以使用sklearn中的tf-idf矢量器
tfidf = TfidfVectorizer()
vec = tfidf.fit_transform(df['features'].apply(' '.join).to_list())
vectors = pd.DataFrame(vec.todense(), columns=tfidf.get_feature_names())
print(vectors)
carnivore mane omnivore small spots stripes tail
0 0.497096 0.630504 0.000000 0.000000 0.000000 0.000000 0.497096
1 0.497096 0.000000 0.000000 0.000000 0.630504 0.000000 0.497096
2 0.000000 0.000000 0.497096 0.497096 0.000000 0.630504 0.000000
3 0.000000 0.000000 0.640434 0.640434 0.000000 0.000000 0.000000
teeth
0 0.329023
1 0.329023
2 0.329023
3 0.423897
3。特征提取(可选)
接下来,我们可以选择使用来自sklearn的LDA来创建主题作为下一步聚类的特征。注意,您可以在这里使用其他降维或分解方法,但LDA专门用于主题建模,并且具有高度可解释性(如下所示),因此我使用它。
让我们假设数据有两个主题。
#Using LDA to create topic level features
lda = LatentDirichletAllocation(n_components=2, verbose=0)
lda_features = lda.fit_transform(vec)
lda_features
array([[0.19035075, 0.80964925],
[0.19035062, 0.80964938],
[0.81496776, 0.18503224],
[0.79598858, 0.20401142]])
要了解LDA如何决定主题,检查主题词矩阵以了解主题的组成是有用的。
#Topic-word matrix
pd.DataFrame(lda.components_,
index=['topic1', 'topic2'],
columns=tfidf.get_feature_names()).round(1)
carnivore mane omnivore small spots stripes tail teeth
topic1 0.5 0.5 1.6 1.6 0.5 1.1 0.5 1.3
topic2 1.5 1.1 0.5 0.5 1.1 0.5 1.5 1.1
如你所见,代表"食肉动物"的单词动物主题是第二个主题的一部分,而代表"杂食"的词;动物是第一个主题。根据您的数据和内容的复杂性模式,以及数据包含的潜在主题的数量,最好使用网格搜索来为您的模型找到主题的最佳数量。或者,你可以像我一样做假设。
4。集群
最后,让我们使用k-means聚类来根据特征的相似性对句子进行分类。
首先,让我们不使用LDA聚类。
#Using k-means directly on the one-hot vectors OR Tfidf Vectors
kmeans = KMeans(n_clusters=2)
kmeans.fit(vec)
df['pred'] = kmeans.predict(vec)
print(df)
name features pred
0 lion [mane, teeth, tail, carnivore] 0
1 leopard [spots, teeth, tail, carnivore] 0
2 racoon [stripes, teeth, omnivore, small] 1
3 possum [teeth, omnivore, small] 1
接下来,我们做同样的事情,但这次使用LDA特征。
# clustering the topic level features
kmeans = KMeans(n_clusters=2)
kmeans.fit(lda_features)
df['pred'] = kmeans.predict(lda_features)
name features pred
0 lion [mane, teeth, tail, carnivore] 0
1 leopard [spots, teeth, tail, carnivore] 0
2 racoon [stripes, teeth, omnivore, small] 1
3 possum [teeth, omnivore, small] 1
注意:当使用任何集群时,每次重新运行时标签都会更改,但除非数据/参数更改,否则不会干扰集群。也就是说,有时你可能会看到集群0被标记为集群1,反之亦然。
更新,最接近我想要的东西本质上是这个jupyter笔记本。https://nbviewer.jupyter.org/github/LucasTurtle/national-anthems-clustering/blob/master/Cluster_Anthems.ipynb
本质上是使用sklearn的tfdif功能向量化列表,然后在该数组上运行kmeans。
我还研究了spaCy库和gensim主题建模
我用第一种方法得到的结果,我认为是有意义的。然而,我更想多了解一点我在做什么。