我正在使用包含csv文件的目录的spark mllib算法计算TF和IDF,其中包含以下代码:
import argparse
from os import system
### args parsing
parser = argparse.ArgumentParser(description='runs TF/IDF on a directory of
text docs')
parser.add_argument("-i","--input", help="the input in HDFS",
required=True)
parser.add_argument("-o", '--output', help="the output in HDFS",
required=True )
parser.add_argument("-mdf", '--min_document_frequency', default=1 )
args = parser.parse_args()
docs_dir = args.input
d_out = "hdfs://master:54310/" + args.output
min_df = int(args.min_document_frequency)
# import spark-realated stuff
from pyspark import SparkContext
from pyspark.mllib.feature import HashingTF
from pyspark.mllib.feature import IDF
sc = SparkContext(appName="TF-IDF")
# Load documents (one per line).
documents = sc.textFile(docs_dir).map(lambda title_text:
title_text[1].split(" "))
hashingTF = HashingTF()
tf = hashingTF.transform(documents)
# IDF
idf = IDF().fit(tf)
tfidf = idf.transform(tf)
#print(tfidf.collect())
#save
tfidf.saveAsTextFile(d_out)
使用
print(tfidf.collect())
我得到了这个输出:
[SparseVector(1048576, {812399: 4.3307}), SparseVector(1048576, {411697:
0.0066}), SparseVector(1048576, {411697: 0.0066}), SparseVector(1048576,
{411697: 0.0066}), SparseVector(1048576, {411697: 0.0066}), ....
我还测试了KMeans mllib算法:
from __future__ import print_function
import sys
import numpy as np
from pyspark import SparkContext
from pyspark.mllib.clustering import KMeans
runs=4
def parseVector(line):
return np.array([float(x) for x in line.split(' ')])
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: kmeans <file> <k>", file=sys.stderr)
exit(-1)
sc = SparkContext(appName="KMeans")
lines = sc.textFile(sys.argv[1])
data = lines.map(parseVector)
k = int(sys.argv[2])
model = KMeans.train(data, k, runs)
print("Final centers: " + str(model.clusterCenters))
print("Total Cost: " + str(model.computeCost(data)))
sc.stop()
使用此示例测试用例
0.0 0.0 0.0
0.1 0.1 0.1
0.2 0.2 0.2
9.0 9.0 9.0
9.1 9.1 9.1
9.2 9.2 9.2
它工作正常。
现在我想在KMeans算法中应用上面tfidf的rdd输出,但我不知道如何像上面的示例文本一样转换rdd,或者如何正确分割Kmeans中的rdd算法正常工作。
我真的需要一些帮助。
更新
我真正的问题是如何从这样的文本文件中读取输入以将其应用于KMeans mllib
(1048576,[155412,857472,756332],[1.75642010278,2.41857747478,1.97365255252])
(1048576,[159196,323305,501636],[2.98856378408,1.63863706713,2.44956728334])
(1048576,[135312,847543,743411],[1.42412015238,1.58759872958,2.01237484818])
UPDATE2
我完全不确定,但我认为我需要从上面的矢量转到下面的数组,以便直接应用于KMeans mllib算法
1.75642010278 2.41857747478 1.97365255252
2.98856378408 1.63863706713 2.44956728334
1.42412015238 1.58759872958 2.01237484818
答案 0 :(得分:1)
IDF的输出是SparseVector
的数据帧。 KMeans将矢量作为输入(稀疏或密集),因此,不需要进行任何变换。您应该能够直接使用IDF的输出列作为KMeans的输入。
如果您需要在运行TFIDF和KMeans之间将数据保存到磁盘,我建议您通过数据帧API将其保存为csv。
首先使用Row
转换为数据框:
from pyspark.sql import Row
row = Row("features") # column name
df = tfidf.map(row).toDF()
无需导入的另一种转换方式:
df = tfidf.map(lambda x: (x, )).toDF(["features"])
转换后将数据框保存为镶木地板文件:
df.write.parquet('/path/to/save/file')
要阅读数据,只需使用:
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
df = sqlContext.read.parquet('/path/to/file')
# converting from dataframe into an RDD[Vector]
data = df.rdd.map(list)
如果您在任何情况下需要从保存为字符串的向量转换,那也是可能的。以下是一些示例代码:
from pyspark.mllib.linalg import Vectors, VectorUDT
from pyspark.sql.functions import udf
df = sc.parallelize(["(7,[1,2,4],[1,1,1])"]).toDF(["features"])
parse = udf(lambda s: Vectors.parse(s), VectorUDT())
df.select(parse("features"))
首先,使用相同的格式创建示例数据帧。然后使用UDF
将字符串解析为向量。如果你想要一个rdd而不是数据帧,请使用上面的代码&#34;读取镶木地板&#34;部分转换。
但是,IDF
的输出非常稀疏。这些向量的长度为1048576,其中只有一个的值大于1.KMeans不会给你任何有趣的结果。
我建议你转而研究word2vec。它将为每个单词提供更紧凑的向量,并且聚类这些向量将更有意义。使用此方法,您可以接收可用于聚类的矢量表示的单词映射。