首页 文章

如何在Spark 2.1上更新pyspark数据帧元数据?

提问于
浏览
0

我遇到了SparkML的OneHotEncoder问题,因为它读取数据帧元数据以确定它应为其创建的稀疏矢量对象分配的值范围 .

更具体地说,我使用包含0到23之间的所有单个值的训练集来编码“小时”字段 .

现在我使用Pipeline的“transform”方法对单行数据帧进行评分 .

不幸的是,这导致OneHotEncoder的不同编码的稀疏矢量对象

(24,[5],[1.0])vs.(11,[10],[1.0])

我已经记录了这个here,但这被认为是重复的 . 所以在这个thread中有一个解决方案,用于更新数据帧的元数据以反映"hour"字段的实际范围:

from pyspark.sql.functions import col

meta = {"ml_attr": {
    "vals": [str(x) for x in range(6)],   # Provide a set of levels
    "type": "nominal", 
    "name": "class"}}

loaded.transform(
    df.withColumn("class", col("class").alias("class", metadata=meta)) )

不幸的是我收到了这个错误:

TypeError:alias()得到一个意外的关键字参数'metadata'

1 回答

  • 3

    在PySpark 2.1中, alias 方法没有参数 metadatadocs) - 这是Spark 2.2中的became available;尽管如此,仍然可以在PySpark <2.2中修改列元数据,这要归功于由@eliasah@zero323维护的令人难以置信的Spark Gotchas

    import json
    
    from pyspark import SparkContext
    from pyspark.sql import Column
    from pyspark.sql.functions import col
    
    spark.version
    # u'2.1.1'
    
    df = sc.parallelize((
            (0, "x", 2.0),
            (1, "y", 3.0),
            (2, "x", -1.0)
            )).toDF(["label", "x1", "x2"])
    
    df.show()
    # +-----+---+----+ 
    # |label| x1|  x2|
    # +-----+---+----+
    # |    0|  x| 2.0|
    # |    1|  y| 3.0|
    # |    2|  x|-1.0|
    # +-----+---+----+
    

    假设我们希望强制我们的 label 数据在0到5之间的可能性,尽管在我们的数据帧中介于0和2之间,我们应该如何修改列元数据:

    def withMeta(self, alias, meta):
        sc = SparkContext._active_spark_context
        jmeta = sc._gateway.jvm.org.apache.spark.sql.types.Metadata
        return Column(getattr(self._jc, "as")(alias, jmeta.fromJson(json.dumps(meta))))
    
    Column.withMeta = withMeta
    
    # new metadata:
    meta = {"ml_attr": {"name": "label_with_meta",
                        "type": "nominal",
                        "vals": [str(x) for x in range(6)]}}
    
    df_with_meta = df.withColumn("label_with_meta", col("label").withMeta("", meta))
    

    感谢_3239263_ by zero323!

相关问题