在列中将String转换为ArrayType并展开

时间:2018-02-19 10:32:43

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

我有一个PySpark数据框,其中列是字符串类型,而字符串是2D数组/列表,需要分解成行。但是,由于它不是结构/数组类型,因此无法直接使用explode

这可以在下面的例子中看到:

a = [('Bob', 562,"Food", "[[29,June,2018],[12,May,2018]]"), ('Bob',880,"Food","[[01,June,2018]]"), ('Bob',380,'Household',"[[16,June,2018]]")]
df = spark.createDataFrame(a, ["Person", "Amount","Budget", "Date"])

df.printSchema()

输出:

root
 |-- Person: string (nullable = true)
 |-- Amount: long (nullable = true)
 |-- Budget: string (nullable = true)
 |-- Date: string (nullable = true)

我正在寻找的输出如下所示。我需要能够将String转换为Struct / Array,以便我可以爆炸:

+------+------+---------+---+-----+-----+
|Person|Amount|Budget   |Day|Month|Year |
+------+------+---------+---+-----+-----+
|Bob   |562   |Food     |29 |June |2018 |
|Bob   |562   |Food     |12 |May  |2018 |
|Bob   |880   |Food     |01 |June |2018 |
|Bob   |380   |Household|16 |June |2018 |
+------+------+---------+---+-----+-----+

2 个答案:

答案 0 :(得分:2)

首先删除外部[[]],然后在所有],[上拆分字符串。 拆分后,数据将在数组中,从而可以使用explode函数。之后,剩下的就是使用另一个splitgetItem将数据格式化为所需的输出。

可以按照以下方式完成:

from pyspark.sql import functions as F

df.withColumn('date_arr', F.split(F.regexp_replace('Date', '\[\[|\]\]', ''), ','))\
  .withColumn('date_arr', F.explode('date_arr'))\
  .withColumn('date_arr', F.split('date_arr', ','))\
  .select('Person',
          'Amount',
          'Budget',
          'date_arr'.getItem(0).alias('Day'),
          'date_arr'.getItem(0).alias('Month'),
          'date_arr'.getItem(0).alias('Year'))

答案 1 :(得分:0)

如果您有一个与我们展示的格式相同的字符串,那么您需要执行以下任务:

  1. 使用explode
  2. 分割所有数组中的列
  3. 删除[和]
  4. ,逗号
  5. 拆分日期
  6. 将新数组的每个成员分配到其列。
  7. 如果我给你写了代码:

    from pyspark.sql import functions as F
    
    df.select("Person",
              "Amount",
              "Budget",
              F.explode(F.split("Date", '],')).alias("date_array")
             ).select("Person",
                      "Amount",
                      "Budget",
                      F.split(F.translate(F.translate("date_array", '[', ''), ']', ''), ',').alias("date_array")
                     ).select("Person",
                              "Amount",
                              "Budget",
                              F.col("date_array").getItem(0).alias("Day"),
                              F.col("date_array").getItem(1).alias("Month"),
                              F.col("date_array").getItem(2).alias("Year"),
                             ).show()
    
    +------+------+---------+---+-----+----+
    |Person|Amount|   Budget|Day|Month|Year|
    +------+------+---------+---+-----+----+
    |   Bob|   562|     Food| 29| June|2018|
    |   Bob|   562|     Food| 12|  May|2018|
    |   Bob|   880|     Food| 01| June|2018|
    |   Bob|   380|Household| 16| June|2018|
    +------+------+---------+---+-----+----+