Apache spark 使用PySpark将数组值分解为多列
我是pyspark的新手,我希望以这样一种方式分解数组值,即每个值都分配给一个新列。我尝试使用explode,但无法获得所需的输出。下面是我的输出 这是密码Apache spark 使用PySpark将数组值分解为多列,apache-spark,pyspark,apache-spark-sql,pyspark-dataframes,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Dataframes,我是pyspark的新手,我希望以这样一种方式分解数组值,即每个值都分配给一个新列。我尝试使用explode,但无法获得所需的输出。下面是我的输出 这是密码 from pyspark.sql import * from pyspark.sql.functions import explode if __name__ == "__main__": spark = SparkSession.builder \ .master("local[3]"
from pyspark.sql import *
from pyspark.sql.functions import explode
if __name__ == "__main__":
spark = SparkSession.builder \
.master("local[3]") \
.appName("DataOps") \
.getOrCreate()
dataFrameJSON = spark.read \
.option("multiLine", True) \
.option("mode", "PERMISSIVE") \
.json("data.json")
dataFrameJSON.printSchema()
sub_DF = dataFrameJSON.select(explode("values.line").alias("new_values"))
sub_DF.printSchema()
sub_DF2 = sub_DF.select("new_values.*")
sub_DF2.printSchema()
sub_DF.show(truncate=False)
new_DF = sub_DF2.select("id", "period.*", "property")
new_DF.show(truncate=False)
new_DF.printSchema()
这是数据:
{
"values" : {
"line" : [
{
"id" : 1,
"period" : {
"start_ts" : "2020-01-01T00:00:00",
"end_ts" : "2020-01-01T00:15:00"
},
"property" : [
{
"name" : "PID",
"val" : "P120E12345678"
},
{
"name" : "EngID",
"val" : "PANELID00000000"
},
{
"name" : "TownIstat",
"val" : "12058091"
},
{
"name" : "ActiveEng",
"val" : "5678.1"
}
]
}
}
你能用数据代替截图吗 同时,假设
df
是正在使用的数据帧,我们需要做的是创建一个新的数据帧,同时将vals
从以前的property
数组提取到新列,最后删除property
列:
from pyspark.sql.functions import col
output_df = df.withColumn("PID", col("property")[0].val).withColumn("EngID", col("property")[1].val).withColumn("TownIstat", col("property")[2].val).withColumn("ActiveEng", col("property")[3].val).drop("property")
如果元素
的类型为阵列类型
,请使用以下命令:
from pyspark.sql.functions import col
output_df = df.withColumn("PID", col("property")[0][1]).withColumn("EngID", col("property")[1][1]).withColumn("TownIstat", col("property")[2][1]).withColumn("ActiveEng", col("property")[3][1]).drop("property")
Explode将数组分解为新行,而不是新列,请参见:这是一种通用解决方案,即使JSON很凌乱,也能正常工作(元素顺序不同或缺少某些元素) 首先,您需要将“属性”列展平,
regexp\u替换为split,最后是pivot。这也避免了新列名的硬编码
构建数据帧:
from pyspark.sql.types import *
from pyspark.sql import functions as F
from pyspark.sql.functions import col
from pyspark.sql.functions import *
schema = StructType([StructField("id", IntegerType()), StructField("start_ts", StringType()), StructField("end_ts", StringType()), \
StructField("property", ArrayType(StructType( [StructField("name", StringType()), StructField("val", StringType())] )))])
data = [[1, "2010", "2020", [["PID", "P123"], ["Eng", "PA111"], ["Town", "999"], ["Act", "123.1"]]],\
[2, "2011", "2012", [["PID", "P456"], ["Eng", "PA222"], ["Town", "777"], ["Act", "234.1"]]]]
df = spark.createDataFrame(data,schema=schema)
df.show(truncate=False)
+---+--------+------+------------------------------------------------------+
|id |start_ts|end_ts|property |
+---+--------+------+------------------------------------------------------+
|1 |2010 |2020 |[[PID, P123], [Eng, PA111], [Town, 999], [Act, 123.1]]|
|2 |2011 |2012 |[[PID, P456], [Eng, PA222], [Town, 777], [Act, 234.1]]|
+---+--------+------+------------------------------------------------------+
展开和旋转:
df_flatten = df.rdd.flatMap(lambda x: [(x[0],x[1], x[2], y) for y in x[3]]).toDF(['id', 'start_ts', 'end_ts', 'property'])\
.select('id', 'start_ts', 'end_ts', col("property").cast("string"))
df_split = df_flatten.select('id', 'start_ts', 'end_ts', regexp_replace(df_flatten.property, "[\[\]]", "").alias("replacced_col"))\
.withColumn("arr", split(col("replacced_col"), ", "))\
.select(col("arr")[0].alias("col1"), col("arr")[1].alias("col2"), 'id', 'start_ts', 'end_ts')
final_df = df_split.groupby(df_split.id,)\
.pivot("col1")\
.agg(first("col2"))\
.join(df,'id').drop("property")
输出:
final_df.show()
+---+-----+-----+----+----+--------+------+
| id| Act| Eng| PID|Town|start_ts|end_ts|
+---+-----+-----+----+----+--------+------+
| 1|123.1|PA111|P123| 999| 2010| 2020|
| 2|234.1|PA222|P456| 777| 2011| 2012|
+---+-----+-----+----+----+--------+------+
请将代码示例、错误输出放在文本而不是图像中,以便社区更容易帮助您。@Mikayel Saghyan,我希望现在代码和示例数据对您可见?我正在尝试生成上面链接中给出的所需输出感谢您的回复,我尝试了您建议的代码,但我得到了以下错误:TypeError:col()缺少1个必需的位置参数:“strg”您能在上面的问题中包含您的代码吗?有数据样本吗?编辑时,请尝试编辑您自己的问题,而不是我的答案,您的路径代码正确,示例数据现在可用,请帮助我生成我在屏幕截图中提供的所需输出,提前感谢您您可能忘记在col()中插入“property”字符串,你能在使用我的答案后显示你所有的代码吗?我只是在DataRicks上使用了相同的代码,它工作得很好,没有错误sub_DF=dataFrameJSON.select(“UrbanDataset.values.line”)sub_DF2=dataFrameJSON.select(explode(“UrbanDataset.values.line”).alias(“new_values”))sub_DF3=sub_DF2.select(“new_values.*)_DF=sub_DF3.select(“id”、“period.*”、“property”)new_DF.show(truncate=False)output\u df=new\u df.withColumn(“PID”,col(“property”)[0][1])\。withColumn(“EngID”,col(“property”)[1][1])\。withColumn(“TownIstat”,col(“property”)[2][1])\。withColumn(“ActiveEng”,col property”)[3][1])。drop(“property”)output\u df show(truncate=False)非常感谢您的回复,通过使用您的代码,我得到了以下错误:TypeError:col()缺少1个必需的位置参数:“strg”,我想我对col软件包有问题?你能分享完整的代码,包括所有的导入吗?谢谢你,我已经添加了导入。你从哪里得到错误?非常感谢你的回复,它现在也对我起作用了。为什么不简单地提取rele,而需要这么多麻烦通过访问数据来获取数据,然后创建新列?我不明白,这会使事情变得复杂。因为这是一个通用的解决方案。我知道,在这个问题上只使用索引更简单。但是如果“属性”中元素的顺序发生了变化,或者其中一个元素丢失,索引方法将无法工作。我正在分解在这种情况下,我的解决方案中会出现混乱的JSON(并且没有列名的硬编码。适用于“n”个元素)