[英]How do I serialize a LabeledPoint RDD in PySpark?
使用PySpark的saveAsHadoopFile()時出現錯誤,使用saveAsSequenceFile()時出現同樣的錯誤。 我需要保存(key,val)的RDD,其中鍵是字符串,val是LabeledPoint RDD(標簽,SparseVector)。 錯誤如下所示。 谷歌搜索幾個來源似乎我應該能夠在IPython筆記本中做到這一點。 我需要序列化這個大型RDD,以便我可以用Java處理它,因為Spark的MLLib功能還沒有用於python。 根據這篇文章,這應該是可行的。
看看這個頁面,我看到:
_picklable_classes = [
'LinkedList',
'SparseVector',
'DenseVector',
'DenseMatrix',
'Rating',
'LabeledPoint',
]
所以我真的不知道為什么我會收到這個錯誤。
代碼:labeledDataRDD.saveAsSequenceFile('/ tmp / pysequencefile /')
錯誤:
Py4JJavaError:調用z:org.apache.spark.api.python.PythonRDD.saveAsSequenceFile時發生錯誤。 :org.apache.spark.SparkException:由於階段失敗而中止作業:階段527.0中的任務0失敗1次,最近失敗:階段527.0中丟失任務0.0(TID 1454,localhost):net.razorvine.pickle.PickleException:在net.razorvine.pickle.objects.ClassDictConstructor.construct(ClassDictConstructor.java:23)中構造ClassDict(for numpy.dtype)的預期零參數
編輯:我發現了這個:
public class More ...ClassDictConstructor implements IObjectConstructor {
12
13 String module;
14 String name;
15
16 public More ...ClassDictConstructor(String module, String name) {
17 this.module = module;
18 this.name = name;
19 }
20
21 public Object More ...construct(Object[] args) {
22 if (args.length > 0)
23 throw new PickleException("expected zero arguments for construction of ClassDict (for "+module+"."+name+")");
24 return new ClassDict(module, name);
25 }
26}
我沒有直接使用上面的construct()方法..所以我不知道為什么我嘗試的saveAs ..方法在它不需要時傳遞參數。
編輯2:遵循zero323建議(謝謝)使用了一個小故障。 當我嘗試使用zero323編寫的內容時,我收到錯誤(見下文)。 但是,當我派生出一個更簡單的RDD時,它可以工作並將這個更簡單的RDD保存到.parquet文件的目錄中(將其分解為幾個.parquet文件)。 更簡單的RDD如下:
simplerRDD = labeledDataRDD.map(lambda (k,v): (v.label, v.features))
sqlContext.createDataFrame(simplerRDD, ("k", "v")).write.parquet("labeledData_parquet_file")
嘗試保存labeledDataRDD時出錯:
/usr/local/Cellar/apache-spark/1.5.1/libexec/python/pyspark/sql/types.pyc in _infer_schema(row)
831 raise TypeError("Can not infer schema for type: %s" % type(row))
832
--> 833 fields = [StructField(k, _infer_type(v), True) for k, v in items]
834 return StructType(fields)
835
/usr/local/Cellar/apache-spark/1.5.1/libexec/python/pyspark/sql/types.pyc in _infer_type(obj)
808 return _infer_schema(obj)
809 except TypeError:
--> 810 raise TypeError("not supported type: %s" % type(obj))
811
812
TypeError: not supported type: <type 'numpy.unicode_'>
問題的根源不是酸洗自己。 如果是,你就不會看到net.razorvine.pickle.PickleException
。 如果你看一下saveAsSequenceFile
文檔,你會發現它需要兩個步驟:
- Pyrolite用於將pickled Python RDD轉換為Java對象的RDD。
- 此Java RDD的鍵和值將轉換為Writable並寫出。
你的程序在第一步就失敗了,但即使它沒有,我也不確定什么是預期的Java對象以及如何閱讀它。
我只是將數據寫為Parquet文件,而不是使用序列文件:
from pyspark.mllib.regression import LabeledPoint
rdd = sc.parallelize([
("foo", LabeledPoint(1.0, [1.0, 2.0, 3.0])),
("bar", LabeledPoint(2.0, [4.0, 5.0, 6.0]))])
sqlContext.createDataFrame(rdd, ("k", "v")).write.parquet("a_parquet_file")
讀回來並轉換:
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.sql.Row
import org.apache.spark.rdd.RDD
val rdd: RDD[(String, LabeledPoint)] = sqlContext.read.parquet("a_parquet_file")
.select($"k", $"v.label", $"v.features")
.map{case Row(k: String, label: Double, features: Vector) =>
(k, LabeledPoint(label, features))}
rdd.sortBy(_._1, false).take(2)
// Array[(String, org.apache.spark.mllib.regression.LabeledPoint)] =
// Array((foo,(1.0,[1.0,2.0,3.0])), (bar,(2.0,[4.0,5.0,6.0])))
或者如果您更喜歡類似Java的方法:
def rowToKeyLabeledPointPair(r: Row): Tuple2[String, LabeledPoint] = {
// Vector -> org.apache.spark.mllib.linalg.Vector
Tuple2(r.getString(0), LabeledPoint(r.getDouble(1), r.getAs[Vector](2)))
}
sqlContext.read.parquet("a_parquet_file")
.select($"k", $"v.label", $"v.features")
.map(rowToKeyLabeledPointPair)
編輯
一般而言,Spark SQL中不支持NumPy類型作為獨立值。 如果您在RDD中有Numpy類型,則首先將它們轉換為標准Python類型:
tmp = rdd.map(lambda kv: (str(kv[0]), kv[1]))
sqlContext.createDataFrame(tmp, ("k", "v")).write.parquet("a_parquet_file")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.