Как преобразовать RDD плотного вектора в фрейм данных в pyspark?

у меня есть DenseVector RDD такой

>>> frequencyDenseVectors.collect()
[DenseVector([1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0]), DenseVector([1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), DenseVector([1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0]), DenseVector([0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])]

Я хочу преобразовать это в Dataframe. Я пробовал вот так!--9-->

>>> spark.createDataFrame(frequencyDenseVectors, ['rawfeatures']).collect()

это дает ошибку типа

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/BIG-DATA/spark-2.0.0-bin-hadoop2.7/python/pyspark/sql/session.py", line 520, in createDataFrame
    rdd, schema = self._createFromRDD(data.map(prepare), schema, samplingRatio)
  File "/opt/BIG-DATA/spark-2.0.0-bin-hadoop2.7/python/pyspark/sql/session.py", line 360, in _createFromRDD
    struct = self._inferSchema(rdd, samplingRatio)
  File "/opt/BIG-DATA/spark-2.0.0-bin-hadoop2.7/python/pyspark/sql/session.py", line 340, in _inferSchema
    schema = _infer_schema(first)
  File "/opt/BIG-DATA/spark-2.0.0-bin-hadoop2.7/python/pyspark/sql/types.py", line 991, in _infer_schema
    fields = [StructField(k, _infer_type(v), True) for k, v in items]
  File "/opt/BIG-DATA/spark-2.0.0-bin-hadoop2.7/python/pyspark/sql/types.py", line 968, in _infer_type
    raise TypeError("not supported type: %s" % type(obj))
TypeError: not supported type: <type 'numpy.ndarray'>

старое решение

frequencyVectors.map(lambda vector: DenseVector(vector.toArray()))

Edit 1-Код Воспроизводимый

from pyspark import SparkConf, SparkContext
from pyspark.sql import SQLContext, Row
from pyspark.sql.functions import split

from pyspark.ml.feature import CountVectorizer
from pyspark.mllib.clustering import LDA, LDAModel
from pyspark.mllib.linalg import Vectors
from pyspark.ml.feature import HashingTF, IDF, Tokenizer
from pyspark.mllib.linalg import SparseVector, DenseVector

sqlContext = SQLContext(sparkContext=spark.sparkContext, sparkSession=spark)
sc.setLogLevel('ERROR')

sentenceData = spark.createDataFrame([
    (0, "Hi I heard about Spark"),
    (0, "I wish Java could use case classes"),
    (1, "Logistic regression models are neat")
], ["label", "sentence"])
sentenceData = sentenceData.withColumn("sentence", split("sentence", "s+"))
sentenceData.show()

vectorizer = CountVectorizer(inputCol="sentence", outputCol="rawfeatures").fit(sentenceData)
countVectors = vectorizer.transform(sentenceData).select("label", "rawfeatures")

idf = IDF(inputCol="rawfeatures", outputCol="features")
idfModel = idf.fit(countVectors)
tfidf = idfModel.transform(countVectors).select("label", "features")
frequencyDenseVectors = tfidf.rdd.map(lambda vector: [vector[0],DenseVector(vector[1].toArray())])
frequencyDenseVectors.map(lambda x: (x, )).toDF(["rawfeatures"])

2 ответов


вы не можете преобразовать RDD[Vector] напрямую. Он должен быть сопоставлен с RDD объектов, которые могут быть интерпретированы как structs, например RDD[Tuple[Vector]]:

frequencyDenseVectors.map(lambda x: (x, )).toDF(["rawfeatures"])

в противном случае Spark попытается преобразовать объект __dict__ и создать использовать неподдерживаемый массив NumPy в качестве поля.

from pyspark.ml.linalg import DenseVector  
from pyspark.sql.types import _infer_schema

v = DenseVector([1, 2, 3])
_infer_schema(v)
TypeError                                 Traceback (most recent call last)
... 
TypeError: not supported type: <class 'numpy.ndarray'>

и

_infer_schema((v, ))
StructType(List(StructField(_1,VectorUDT,true)))

Примечания:

  • в Spark 2.0 вы должны использовать правильный локальный типы:

    • pyspark.ml.linalg при работе DataFrame на основе pyspark.ml API-интерфейс.
    • pyspark.mllib.linalg при работе RDD на основе pyspark.mllib API-интерфейс.

    эти два пространства имен больше не могут быть совместимы и требуют явных преобразований (например как конвертировать из org.апаш.искра.mllib.linalg.VectorUDT к ОД.linalg.VectorUDT).

  • код, указанный в правке, не эквивалентен коду из оригинала вопрос. Вы должны знать, что tuple и list не имеют той же семантики. Если вы сопоставляете вектор с парой, используйте tuple и конвертировать непосредственно к DataFrame:

    tfidf.rdd.map(
        lambda row: (row[0], DenseVector(row[1].toArray()))
    ).toDF()
    

    используя tuple (тип продукта) будет работать и для вложенной структуры, но я сомневаюсь, что это то, что вы хотите:

    (tfidf.rdd
        .map(lambda row: (row[0], DenseVector(row[1].toArray())))
        .map(lambda x: (x, ))
        .toDF())
    

    list в любом другом месте, кроме верхнего уровня row трактуется как ArrayType.

  • гораздо чище использовать UDF для преобразование (Spark Python: Стандартная ошибка масштабирования " не поддерживается ... SparseVector").


Я считаю, что проблема здесь в том, что createDataframe не принимает denseVactor в качестве аргумента, пожалуйста, попробуйте преобразовать denseVector в соответствующую коллекцию [т. е. массив или список]. В scala и java

toArray ()

метод доступен вы можете преобразовать denseVector в массив или список, а затем попытаться создать dataFrame.