Spark DataFrame 如何区分不同的 VectorUDT 对象?

How does Spark DataFrame distinguish between different VectorUDT objects?

我正在尝试了解 DataFrame 列类型。当然,DataFrame并不是物化对象,它只是给Spark的一组指令,将来转化为代码。但我想这个类型列表代表了执行操作时可能在 JVM 内部具体化的对象类型。

import pyspark
import pyspark.sql.types as T
import pyspark.sql.functions as F
data = [0, 3, 0, 4]
d = {}
d['DenseVector'] = pyspark.ml.linalg.DenseVector(data)
d['old_DenseVector'] = pyspark.mllib.linalg.DenseVector(data)
d['SparseVector'] = pyspark.ml.linalg.SparseVector(4, dict(enumerate(data)))
d['old_SparseVector'] = pyspark.mllib.linalg.SparseVector(4, dict(enumerate(data)))
df = spark.createDataFrame([d])
df.printSchema()

四个矢量值的列在 printSchema()(或 schema)中看起来相同:

root
 |-- DenseVector: vector (nullable = true)
 |-- SparseVector: vector (nullable = true)
 |-- old_DenseVector: vector (nullable = true)
 |-- old_SparseVector: vector (nullable = true)

但是当我逐行检索它们时,结果发现它们是不同的:

> for x in df.first().asDict().items():
  print(x[0], type(x[1]))
(2) Spark Jobs
old_SparseVector <class 'pyspark.mllib.linalg.SparseVector'>
SparseVector <class 'pyspark.ml.linalg.SparseVector'>
old_DenseVector <class 'pyspark.mllib.linalg.DenseVector'>
DenseVector <class 'pyspark.ml.linalg.DenseVector'>

我对 vector 类型的含义感到困惑(在编写 UDF 时等同于 VectorUDT)。 DataFrame 如何知道它在每个 vector 列中具有四种向量类型中的哪一种?这些向量列中的数据是存储在 JVM 中还是 python VM 中?为什么 VectorUDT 可以存储在 DataFrame 中,如果它不是官方类型之一 listed here

(我知道来自 mllib.linalg 的四种矢量类型中的两种最终将被弃用。)

how come VectorUDT can be stored in the DataFrame

UDT a.k.a User Defined Type 应该是这里的提示。 Spark 提供(现在是私有的)机制来在 DataFrame 中存储自定义对象。您可以查看我对 或 Spark 源的回答以获取详细信息,但长话短说,它就是关于解构对象并将它们编码为 Catalyst 类型。

I'm confused about the meaning of vector type

很可能是因为您看错了东西。简短描述很有用,但不能确定类型。相反,您应该检查架构。让我们创建另一个数据框:

import pyspark.mllib.linalg as mllib
import pyspark.ml.linalg as ml

df = sc.parallelize([
    (mllib.DenseVector([1, ]), ml.DenseVector([1, ])),
    (mllib.SparseVector(1, [0, ], [1, ]), ml.SparseVector(1, [0, ], [1, ]))
]).toDF(["mllib_v", "ml_v"])

df.show()

## +-------------+-------------+
## |      mllib_v|         ml_v|
## +-------------+-------------+
## |        [1.0]|        [1.0]|
## |(1,[0],[1.0])|(1,[0],[1.0])|
## +-------------+-------------+

并检查数据类型:

{s.name: type(s.dataType) for s in df.schema}

## {'ml_v': pyspark.ml.linalg.VectorUDT,
##  'mllib_v': pyspark.mllib.linalg.VectorUDT}

如您所见,UDT 类型是完全限定的,所以这里没有混淆。

How does the DataFrame know which of the four vector types it has in each vector column?

如上所示DataFrame只知道它的模式并且可以区分ml / mllib类型但不关心向量变体(稀疏或密集)。

向量类型由其 type 字段(一个 byte 字段,0 -> 稀疏,1 -> 密集)确定,但总体架构相同。 mlmllib 之间的内部表示也没有区别。

Is the data in those vector columns stored in the JVM or in Python

DataFrame 是一个纯 JVM 实体。 Python 互操作性是通过耦合的 UDT 类:

实现的
  • Scala UDT 可以定义 pyUDT 属性。
  • Python UDT 可以定义 scalaUDT 属性。