无法将类型<class'pyspark.ml.linalg.SparseVector'>转换为Vector

Jac*_* Lv 6 apache-spark apache-spark-sql pyspark apache-spark-ml apache-spark-mllib

鉴于我的pyspark Row对象:

>>> row
Row(clicked=0, features=SparseVector(7, {0: 1.0, 3: 1.0, 6: 0.752}))
>>> row.clicked
0
>>> row.features
SparseVector(7, {0: 1.0, 3: 1.0, 6: 0.752})
>>> type(row.features)
<class 'pyspark.ml.linalg.SparseVector'>
Run Code Online (Sandbox Code Playgroud)

但是,row.features未能通过isinstance(row.features,Vector)测试.

>>> isinstance(SparseVector(7, {0: 1.0, 3: 1.0, 6: 0.752}), Vector)
True
>>> isinstance(row.features, Vector)
False
>>> isinstance(deepcopy(row.features), Vector)
False
Run Code Online (Sandbox Code Playgroud)

这个奇怪的错误让我陷入了巨大的麻烦.没有传递"isinstance(row.features,Vector)",我无法使用map函数生成LabeledPoint.如果有人能解决这个问题,我将非常感激.

use*_*411 14

这不太可能是一个错误.您没有提供重现问题所需代码,但很可能您使用Spark 2.0与ML变换器并且您比较错误的实体.

让我们用一个例子来说明.简单的数据

from pyspark.ml.feature import OneHotEncoder

row = OneHotEncoder(inputCol="x", outputCol="features").transform(
    sc.parallelize([(1.0, )]).toDF(["x"])
).first()
Run Code Online (Sandbox Code Playgroud)

现在让我们导入不同的矢量类:

from pyspark.ml.linalg import Vector as MLVector, Vectors as MLVectors
from pyspark.mllib.linalg import Vector as MLLibVector, Vectors as MLLibVectors
from pyspark.mllib.regression import  LabeledPoint
Run Code Online (Sandbox Code Playgroud)

并进行测试:

isinstance(row.features, MLLibVector)
Run Code Online (Sandbox Code Playgroud)
False
Run Code Online (Sandbox Code Playgroud)
isinstance(row.features, MLVector)
Run Code Online (Sandbox Code Playgroud)
True
Run Code Online (Sandbox Code Playgroud)

正如你看到的,我们拥有的是pyspark.ml.linalg.Vector不是pyspark.mllib.linalg.Vector这是不符合旧的API兼容:

LabeledPoint(0.0, row.features)
Run Code Online (Sandbox Code Playgroud)
TypeError                                 Traceback (most recent call last)
...
TypeError: Cannot convert type <class 'pyspark.ml.linalg.SparseVector'> into Vector
Run Code Online (Sandbox Code Playgroud)

您可以将ML对象转换为MLLib:

from pyspark.ml import linalg as ml_linalg

def as_mllib(v):
    if isinstance(v, ml_linalg.SparseVector):
        return MLLibVectors.sparse(v.size, v.indices, v.values)
    elif isinstance(v, ml_linalg.DenseVector):
        return MLLibVectors.dense(v.toArray())
    else:
        raise TypeError("Unsupported type: {0}".format(type(v)))

LabeledPoint(0, as_mllib(row.features))
Run Code Online (Sandbox Code Playgroud)
LabeledPoint(0.0, (1,[],[]))
Run Code Online (Sandbox Code Playgroud)

或者干脆:

LabeledPoint(0, MLLibVectors.fromML(row.features))
Run Code Online (Sandbox Code Playgroud)
LabeledPoint(0.0, (1,[],[]))
Run Code Online (Sandbox Code Playgroud)

但一般来说,你应该在必要时避免出现这种情况.


小智 6

如果您只想将SparseVectors从pyspark.ml转换为pyspark.mllib SparseVectors,您可以使用MLUtils.假设df是您的数据框,具有SparseVectors的列被命名为"features".然后以下几行让你完成这个:

from pyspark.mllib.utils import MLUtils
df = MLUtils.convertVectorColumnsFromML(df, "features")
Run Code Online (Sandbox Code Playgroud)

我遇到这个问题,因为当从pyspark.ml.feature使用CountVectorizer时,我无法创建LabeledPoints,因为它与pyspark.ml中的SparseVector不兼容

我想知道为什么他们最新的文档CountVectorizer不使用"新的"SparseVector类.由于分类算法需要LabeledPoints,这对我来说没有意义......

更新:我误解了ml库是为DataFrame-Objects设计的,而mllib库是为RDD对象设计的.因为Spark> 2.0,所以建议使用DataFrame-Datastructure,因为SparkSession比SparkContext更兼容(但存储了SparkContext对象)并且确实提供了DataFrame而不是RDD.我发现这篇文章让我得到了"aha" - 效果:mllib和ml.谢谢Alberto Bonsanto :).

要从mllib使用fe NaiveBayes,我必须将我的DataFrame转换为来自mllib的NaledBayes的LabeledPoint对象.

但是使用ml中的NaiveBayes更容易,因为您不需要LabeledPoints,但只能为数据帧指定feature-和class-col.

PS:我几个小时都在努力解决这个问题,所以我觉得我需要在这里发布:)

  • `pyspark` 感觉像是一个很好的例子,说明了如何不做 api,说实话——不知何故既不直观又不稳定。通常它不直观,但至少稳定,因为修复被认为不值得。或者不稳定,但至少直观,因为修复正在使其变得如此。我认为它的缺点是成为“java”实现背后的二等公民,因此它保留了语言翻译包。 (3认同)