【发布时间】:2017-10-07 09:13:30
【问题描述】:
我正在尝试通过预处理、生成 tf-idf 矩阵,然后应用 K-means 来完成对文本文档进行聚类的经典工作。但是,在经典的 20NewsGroup 数据集上测试此工作流程会导致大多数文档被聚集到一个集群中。 (我最初尝试将 20 个组中的 6 个中的所有文档聚类 - 因此希望聚类为 6 个聚类)。
我在 Apache Spark 中实现了这一点,因为我的目的是在数百万个文档中使用这种技术。这是在 Databricks 上用 Pyspark 编写的代码:
#declare path to folder containing 6 of 20 news group categories
path = "/mnt/%s/20news-bydate.tar/20new-bydate-train-lessFolders/*/*" %
MOUNT_NAME
#read all the text files from the 6 folders. Each entity is an entire
document.
text_files = sc.wholeTextFiles(path).cache()
#convert rdd to dataframe
df = text_files.toDF(["filePath", "document"]).cache()
from pyspark.ml.feature import HashingTF, IDF, Tokenizer, CountVectorizer
#tokenize the document text
tokenizer = Tokenizer(inputCol="document", outputCol="tokens")
tokenized = tokenizer.transform(df).cache()
from pyspark.ml.feature import StopWordsRemover
remover = StopWordsRemover(inputCol="tokens",
outputCol="stopWordsRemovedTokens")
stopWordsRemoved_df = remover.transform(tokenized).cache()
hashingTF = HashingTF (inputCol="stopWordsRemovedTokens", outputCol="rawFeatures", numFeatures=200000)
tfVectors = hashingTF.transform(stopWordsRemoved_df).cache()
idf = IDF(inputCol="rawFeatures", outputCol="features", minDocFreq=5)
idfModel = idf.fit(tfVectors)
tfIdfVectors = idfModel.transform(tfVectors).cache()
#note that I have also tried to use normalized data, but get the same result
from pyspark.ml.feature import Normalizer
from pyspark.ml.linalg import Vectors
normalizer = Normalizer(inputCol="features", outputCol="normFeatures")
l2NormData = normalizer.transform(tfIdfVectors)
from pyspark.ml.clustering import KMeans
# Trains a KMeans model.
kmeans = KMeans().setK(6).setMaxIter(20)
km_model = kmeans.fit(l2NormData)
clustersTable = km_model.transform(l2NormData)
ID number_of_documents_in_cluster
0 3024
3 5
1 3
5 2
2 2
4 1
正如您所见,我的大多数数据点都聚集到集群 0 中,我无法弄清楚我做错了什么,因为我在网上遇到的所有教程和代码都指向使用这种方法。
此外,我还尝试在 K-means 之前对 tf-idf 矩阵进行归一化,但这也会产生相同的结果。我知道余弦距离是一种更好的测量方法,但我希望在 Apache Spark 中使用标准 K-means 会提供有意义的结果。
谁能帮助我了解我的代码中是否存在错误,或者我的数据集群管道中是否缺少某些内容?
提前谢谢你!
这是python中的实现,即使具有大量最大特征,它也不会将所有文档组合在一起:
#imports
import pandas as pd
import os
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans, MiniBatchKMeans
vectorizer = TfidfVectorizer(max_features=200000, lowercase=True,
min_df=5, stop_words='english',
use_idf=True)
X = vectorizer.fit_transform(df['document'])
#Apply K-means to create cluster
from time import time
km = KMeans(n_clusters=20, init='k-means++', max_iter=20, n_init=1,
verbose=False)
km.fit(X)
#result
3 2634
6 1720
18 1307
15 780
0 745
1 689
16 504
8 438
7 421
5 369
11 347
14 330
4 243
13 165
10 136
17 118
9 113
19 106
12 87
2 62
我原以为我们可以在 pyspark 中使用具有欧几里得距离的 KMeans 复制类似的东西,然后再在 KMeans 中尝试余弦或 Jaccard 距离。有什么解决方案或cmets?
【问题讨论】:
-
您是否尝试过将您的 epsilon 更改为更高的数字?这将有助于限制集群合并在一起
.setEpsilonapache-spark-user-list.1001560.n3.nabble.com/… 有一点解释 -
Apache spark 有方法:kmeans.getTol()/setTol 用于获取和设置 tol 值。默认设置为 0.0001。我相信这个值是需要设置的,因为我找不到对方法 setEpsilon 的任何引用。但是,由于相同的方法和 tol 值可以使用 sklearn 在 python 中对文档进行集群 - 我认为修改它不会有帮助。
-
我已经在 python 中使用 Sklearn 解决了这个问题,使用构建 tf-idf 矩阵和使用 K-means 算法的相同方法。任何人都可以建议为什么它在 spark 中失败 - 我的 pyspark 代码中有错误吗?
-
你用的是什么版本的python/spark?
-
我使用的是 spark 2.1。目前我在 Databricks 社区版上实现了这一点。
标签: python apache-spark k-means tf-idf