【问题标题】:Modify all elements in ArrayType [duplicate]修改 ArrayType 中的所有元素 [重复]
【发布时间】:2019-10-25 23:24:27
【问题描述】:

我有一个 DataFrame,其中有一列 ArrayType(StringType):

+------------------------------------+
|colname                             |
+------------------------------------+
|[foo_XX_foo, bar_YY_bar]            |
|[qwe_ZZ_rty, asd_AA_fgh, zxc_BB_vbn]|
+------------------------------------+

我现在想提取第一个和第二个_ 之间的字符串,即预期的输出是:

+------------+
|newcolname  |
+------------+
|[XX, YY]    |
|[ZZ, AA, BB]|
+------------+

this answer 之后,我尝试将expr()transform 一起使用,但我没有设法让它工作。即使将所有字符串更改为大写的示例,如上面引用的答案,对我也不起作用,我收到以下错误:

pyspark.sql.utils.ParseException: u"\nextraneous input '>' 期待 {'(', 'SELECT', ...

如何修改ArrayType 中的所有元素?我想避免使用udf

【问题讨论】:

  • 您使用的是什么版本的 Spark?
  • @Bala Spark 2.3.2
  • @pfnuesel transform 仅在 2.4+ 中可用。你最好的选择可能是udf,尽管使用concat_wsregexp_extractsplit 有一种很老套的方法

标签: apache-spark pyspark pyspark-sql pyspark-dataframes


【解决方案1】:

有点不安全,但试试这样的:

df = spark.sparkContext.parallelize([
  [["foo_XX_foo", "bar_YY_bar"]],
  [["qwe_ZZ_rty", "asd_AA_fgh", "zxc_BB_vbn"]]
]).toDF(['colname'])

df.selectExpr('transform(colname, x -> split(x, "_")[1]) as newcolname').show()

导致:

+------------+
|  newcolname|
+------------+
|    [XX, YY]|
|[ZZ, AA, BB]|
+------------+

【讨论】:

    【解决方案2】:

    由于您使用的是 Spark 2.3.2 版,因此您无法使用 transform。因此,正如post you linked 中所解释的那样,通常最好的方法是使用udf

    但是,在这种特定情况下,您可以使用一些 hacky 正则表达式替换来避免 udf

    from pyspark.sql.functions import col, concat_ws, regexp_replace, split, trim
    
    df.withColumn(
        "newcolname",
        regexp_replace(concat_ws(",", col("colname")), "((?<=_)[^_,]+(?=_))", " $1 ")
    ).withColumn(
        "newcolname",
        regexp_replace(col("newcolname"), "(_[^_ ]+_)", "")
    ).withColumn(
        "newcolname",
        regexp_replace(col("newcolname"), "([^_ ]+_)", "")
    ).withColumn(
        "newcolname",
        regexp_replace(col("newcolname"), "_([^_ ]+)", "")
    ).withColumn(
        "newcolname",
        split(trim(col("newcolname")), "\s+")
    ).show(truncate=False)
    #+------------------------------------+------------+
    #|colname                             |newcolname  |
    #+------------------------------------+------------+
    #|[foo_XX_foo, bar_YY_bar]            |[XX, YY]    |
    #|[qwe_ZZ_rty, asd_AA_fgh, zxc_BB_vbn]|[ZZ, AA, BB]|
    #+------------------------------------+------------+
    

    说明

    首先我们获取ArrayType(StringType()) 列并将元素连接在一起形成一个字符串。我使用逗号作为分隔符,仅当逗号未出现在您的数据中时才有效。

    接下来我们执行一系列regexp_replace 调用。

    第一个模式((?&lt;=_)[^_,]+(?=_)) 标识您实际要提取的内容:下划线括起来的文本。然后匹配组被替换为空格" $1 "包围的匹配组。与之前的逗号分隔符一样,这​​假定您的数据中没有出现空格。

    例如:

    df.select(
        regexp_replace(
            concat_ws(",", col("colname")), 
            "((?<=_)[^_,]+(?=_))", 
            " $1 "
        ).alias("pattern1")
    ).show(truncate=False)
    #+--------------------------------------+
    #|pattern1                              |
    #+--------------------------------------+
    #|foo_ XX _foo,bar_ YY _bar             |
    #|qwe_ ZZ _rty,asd_ AA _fgh,zxc_ BB _vbn|
    #+--------------------------------------+
    

    接下来 3 次调用 regexp_replace 有选择地删除此字符串中不需要的部分。

    最后,只剩下想要的内容了。字符串被修剪以删除尾随/前导空格并在空格上拆分以获得最终结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-20
      • 2018-11-28
      • 1970-01-01
      • 1970-01-01
      • 2017-12-12
      • 2020-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多