有很多方法可以解决这个问题。但总的来说,这里有一些简单的替代方案 -
-
向量表示 - 使用 one-hot 编码或 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 的 multi-label binarizer 使用 one-hot 编码句子
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 vectorizer
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 专门用于主题建模并且具有高度可解释性(如下所示),因此我正在使用它。
假设数据有 2 个主题。
#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
如您所见,代表“食肉”动物主题的词属于第二个主题,而代表“杂食”动物的词代表第一个主题。根据您的数据和内容中的复杂性模式,您的数据包含的潜在主题数量最好使用grid search 为您的模型找到最佳主题数量。或者,您可以像我一样做出假设。
4。聚类
最后,让我们使用k-means clustering按特征相似度对句子进行分桶。
首先,让我们在不使用 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,反之亦然。