我正在使用mini_batch_kmeans和kmeans算法对一些文档进行聚类。我只是按照scikit-learn网站上的教程进行操作,链接如下:http://scikit-learn.org/stable/auto_examples/text/document_clustering.html
他们使用了一些向量化方法,其中之一是HashingVectorizer。在HashingVectorizer中,他们使用TfidfTransformer()方法创建了一个管道。
# 对HashingVectorizer的输出进行IDF归一化hasher = HashingVectorizer(n_features=opts.n_features, stop_words='english', non_negative=True, norm=None, binary=False)vectorizer = make_pipeline(hasher, TfidfTransformer())
这样做之后,我得到的vectorizer没有get_feature_names()方法。但由于我使用它进行聚类,我需要使用这个“get_feature_names()”来获取“术语”。
terms = vectorizer.get_feature_names()for i in range(true_k): print("Cluster %d:" % i, end='') for ind in order_centroids[i, :10]: print(' %s' % terms[ind], end='') print()
我该如何解决这个错误?
我的完整代码如下所示:
X_train_vecs, vectorizer = vector_bow.count_tfidf_vectorizer(_contents)mini_kmeans_batch = MiniBatchKmeansTechnique()# 没有LSA降维的MiniBatchKmeansmini_kmeans_batch.mini_kmeans_technique(number_cluster=8, X_train_vecs=X_train_vecs, vectorizer=vectorizer, filenames=_filenames, contents=_contents, is_dimension_reduced=False)
计数向量化器与tfidf结合使用。
def count_tfidf_vectorizer(self,contents): count_vect = CountVectorizer() vectorizer = make_pipeline(count_vect,TfidfTransformer()) X_train_vecs = vectorizer.fit_transform(contents) print("The count of bow : ", X_train_vecs.shape) return X_train_vecs, vectorizer
mini_batch_kmeans类如下所示:
class MiniBatchKmeansTechnique(): def mini_kmeans_technique(self, number_cluster, X_train_vecs, vectorizer, filenames, contents, svd=None, is_dimension_reduced=True): km = MiniBatchKMeans(n_clusters=number_cluster, init='k-means++', max_iter=100, n_init=10, init_size=1000, batch_size=1000, verbose=True, random_state=42) print("Clustering sparse data with %s" % km) t0 = time() km.fit(X_train_vecs) print("done in %0.3fs" % (time() - t0)) print() cluster_labels = km.labels_.tolist() print("List of the cluster names is : ",cluster_labels) data = {'filename':filenames, 'contents':contents, 'cluster_label':cluster_labels} frame = pd.DataFrame(data=data, index=[cluster_labels], columns=['filename', 'contents', 'cluster_label']) print(frame['cluster_label'].value_counts(sort=True,ascending=False)) print() grouped = frame['cluster_label'].groupby(frame['cluster_label']) print(grouped.mean()) print() print("Top Terms Per Cluster :") if is_dimension_reduced: if svd != None: original_space_centroids = svd.inverse_transform(km.cluster_centers_) order_centroids = original_space_centroids.argsort()[:, ::-1] else: order_centroids = km.cluster_centers_.argsort()[:, ::-1] terms = vectorizer.get_feature_names() for i in range(number_cluster): print("Cluster %d:" % i, end=' ') for ind in order_centroids[i, :10]: print(' %s' % terms[ind], end=',') print() print("Cluster %d filenames:" % i, end='') for file in frame.ix[i]['filename'].values.tolist(): print(' %s,' % file, end='') print()
回答:
Pipeline没有get_feature_names()方法,因为为Pipeline实现这个方法并不简单——需要考虑管道的所有步骤来获取特征名称。请参见https://github.com/scikit-learn/scikit-learn/issues/6424,https://github.com/scikit-learn/scikit-learn/issues/6425等——有很多相关的工单和几次尝试修复它。
如果你的管道很简单(TfidfVectorizer后接MiniBatchKMeans),那么你可以从TfidfVectorizer中获取特征名称。
如果你想使用HashingVectorizer,情况会更复杂,因为HashingVectorizer设计上不提供特征名称。HashingVectorizer不存储词汇表,而是使用哈希值——这意味着它可以在线应用,并且不需要任何RAM——但权衡之处正是你无法获得特征名称。
尽管如此,还是有可能从HashingVectorizer中获取特征名称的;要做到这一点,你需要对一组文档应用它,存储哪些哈希值对应哪些单词,这样就可以了解这些哈希值的含义,即特征名称是什么。可能会有冲突,所以无法100%确定特征名称是正确的,但通常这种方法可以正常工作。这种方法在eli5库中实现;请参见http://eli5.readthedocs.io/en/latest/tutorials/sklearn-text.html#debugging-hashingvectorizer以获取示例。你将不得不做类似的事情,使用InvertableHashingVectorizer:
from eli5.sklearn import InvertableHashingVectorizerivec = InvertableHashingVectorizer(vec) # vec是一个HashingVectorizer实例# X_sample是从contents中抽取的样本;你可以使用整个contents数组,或者例如每10个元素抽取一个ivec.fit(content_sample) hashing_feat_names = ivec.get_feature_names()
然后你可以使用hashing_feat_names
作为你的特征名称,因为TfidfTransformer不会改变输入向量的大小,只是对相同的特征进行缩放。