IllegalArgumentException: Column 必须是 struct<type:tinyint,size:int,indices:array<int>,values:array<double>> 类型,但实际上是 double。

IllegalArgumentException: Column must be of type struct<type:tinyint,size:int,indices:array<int>,values:array<double>> but was actually double.'

我有一个包含多个分类列的数据框。我正在尝试使用两列之间的内置函数查找卡方统计数据:

from pyspark.ml.stat import ChiSquareTest

r = ChiSquareTest.test(df, 'feature1', 'feature2')

但是,它给了我错误:

IllegalArgumentException: 'requirement failed: Column feature1 must be of type struct<type:tinyint,size:int,indices:array<int>,values:array<double>> but was actually double.'

feature1 的数据类型是:

feature1: double (nullable = true)

你能帮我解决这方面的问题吗?

spark-ml 不是典型的统计库。它非常面向机器学习。因此,它假设您想要 运行 标签和特征或一组特征之间的测试。

因此,与训练模型时类似,您需要assemble根据标签测试要测试的特征。

对于你的情况,你可以 assemble feature1 如下:

from pyspark.ml.stat import ChiSquareTest
from pyspark.ml.feature import VectorAssembler

data = [(1, 2), (3, 4), (2, 1), (4, 3)]
df = spark.createDataFrame(data, ['feature1', 'feature2'])
assembler = VectorAssembler().setInputCols(['feature1']).setOutputCol('features')

ChiSquareTest.test(assembler.transform(df), 'features', 'feature2').show(false)

以防万一,scala中的代码:

import org.apache.spark.ml.stat.ChiSquareTest
import org.apache.spark.ml.feature.VectorAssembler

val df = Seq((1, 2, 3), (1, 2, 3), (4, 5, 6), (6, 5, 4))
    .toDF("features", "feature2", "feature3")
val assembler = new VectorAssembler()
    .setInputCols(Array("feature1"))
    .setOutputCol("features")

ChiSquareTest.test(assembler.transform(df), "features", "feature2").show(false)

为了扩展 Oli 的回答,Spark ML 希望将特征存储在 pyspark.ml.linalg.Vector 的实例中。有两种向量:

  • 密集向量 - 这些只是包含向量所有元素(包括所有零)的数组,并由 Spark 数组类型表示 array<T>
  • 稀疏向量 - 那些更复杂的数据结构,只存储向量的非零元素,允许紧凑存储只有少量非零元素的巨大向量。稀疏向量具有三个组成部分:
    • 表示向量全维的整数size
    • 保存非零元素位置的indices数组
    • 保存非零元素值的values数组

这两种向量类型实际上都使用稀疏向量的结构表示,而对于密集向量,indices 数组未被使用,values 存储所有值。第一个结构元素type用来区分这两种。

因此,如果您看到预期 struct<type:tinyint,size:int,indices:array<int>,values:array<double>> 的错误,这意味着您应该传递 pyspark.ml.linagl.Vector 的实例,而不仅仅是数字。

为了生成Vectors,您可以使用pyspark.ml.feature.VectorAssembler到assemble一个或多个独立的特征列到一个向量列中,或者使用工厂方法手动构造它们工厂对象 pyspark.ml.linalg.VectorsVectors.dense()(对于密集向量)和 Vectors.sparse()(对于稀疏向量)。使用 VectorAssembler 可能更容易也更快,因为它是在 Scala 中实现的。要使用显式向量创建,请参阅 PySpark 文档中的 example for ChiSquareTest