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



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

更具体地说,我使用包含 0 到 23 之间的所有单个值的训练集对"小时"字段进行编码。

现在,我使用管道中的"转换"方法对单行数据帧进行评分。

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

(24,[5],[1.0]) 与 (11,[10],[1.0])

我在这里记录了这个,但这被确定为重复的。因此,在此线程中,发布了一个解决方案来更新数据帧的元数据以反映"小时"字段的实际范围:

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)) )

不幸的是,我收到此错误:

类型错误:alias() 得到一个意外的关键字参数"metadata"

在 PySpark 2.1 中,

alias 方法没有参数metadata(docs) - 这在 Spark 2.2 中可用;尽管如此,仍然可以在 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))

也为零323的这个答案点赞!

相关内容

  • 没有找到相关文章

最新更新