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

7

我正在尝试理解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如何知道每个向量列中有哪四种向量类型?这些向量列中的数据是存储在JVM还是python VM中的?如果它不是此处列出的官方类型之一,那么为什么“VectorUDT”可以存储在DataFrame中呢?
(我知道来自“mllib.linalg”的四种向量类型中有两种最终将被弃用。)
1个回答

9

为什么VectorUDT可以存储在DataFrame中

UDT,即用户定义类型应该是一个提示。Spark提供了(现在是私有的)机制来存储自定义对象在DataFrame中。您可以查看我的回答如何在Spark SQL中定义自定义类型的模式?或者Spark源代码了解详情,但长话短说,它全部关于拆解对象并将其编码为Catalyst类型。

我对向量类型的含义感到困惑

很可能是因为您正在看错误的内容。简短的描述是有用的,但它不确定类型。相反,您应该检查模式。让我们创建另一个数据框:

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类型是完全限定的,因此这里没有混淆。
数据框知道每个向量列中有哪四种向量类型吗?
如上所示,DataFrame 只知道其模式并且可以区分 ml / mllib 类型,但不关心向量变量(稀疏或密集)。
向量类型由其 type 字段确定(一个 byte 字段,0 -> 稀疏,1 -> 密集),但总体模式相同。在 mlmllib 之间的内部表示也没有区别。
那些向量列中的数据是存储在JVM还是Python中? DataFrame 是一个纯JVM实体。通过耦合的UDT类实现了Python互操作性:
  • Scala UDT 可以定义 pyUDT 属性。
  • Python UDT 可以定义 scalaUDT 属性。

谢谢!我尝试了print(df.schema),但是VectorUDT实例的字符串表示不包括完整的限定符,我没有考虑直接检查它们的类。我只是对一些奇怪的魔法感到不舒服,但现在一切都看起来合理了。 - max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接