如何在Pyspark中将列表拆分为多列?

如何在Pyspark中将列表拆分为多列?,pyspark,apache-spark-sql,Pyspark,Apache Spark Sql,我有: 我想: key value a [1,2,3] b [2,3,4] 似乎我可以在scala中编写:df.select($“value.\u 1”,“$”value.\u 2”,“$”value.\u 3”),但在python中是不可能的 那么有什么好方法可以做到这一点呢?这取决于“列表”的类型: 如果其类型为ArrayType(): df=hc.createDataFrame(sc.parallelize([[a',[1,2,3]],[b',[2,3,4]]),[“k

我有:

我想:

key   value
a    [1,2,3]
b    [2,3,4]
似乎我可以在scala中编写:
df.select($“value.\u 1”,“$”value.\u 2”,“$”value.\u 3”)
,但在python中是不可能的


那么有什么好方法可以做到这一点呢?

这取决于“列表”的类型:

  • 如果其类型为
    ArrayType()

    df=hc.createDataFrame(sc.parallelize([[a',[1,2,3]],[b',[2,3,4]]),[“key”,“value”])
    df.printSchema()
    df.show()
    根
    |--键:字符串(nullable=true)
    |--值:数组(nullable=true)
    ||--元素:长(containsnall=true)
    
    您可以像使用python一样使用
    []
    访问这些值:

    df.select(“键”,df.value[0],df.value[1],df.value[2]).show()
    +---+--------+--------+--------+
    |键|值[0]|值[1]|值[2]|
    +---+--------+--------+--------+
    |a | 1 | 2 | 3|
    |b | 2 | 3 | 4|
    +---+--------+--------+--------+
    +---+-------+
    |键值|
    +---+-------+
    |a |[1,2,3]|
    |b |[2,3,4]|
    +---+-------+
    
  • 如果它的类型为
    StructType()
    :(可能是通过读取JSON构建数据帧)

    df2=df.select(“key”),psf.struct(
    df.value[0]。别名(“value1”),
    df.value[1]。别名(“value2”),
    df.value[2]。别名(“value3”)
    ).别名(“值”))
    df2.printSchema()
    df2.show()
    根
    |--键:字符串(nullable=true)
    |--值:struct(nullable=false)
    ||--value1:long(nullable=true)
    ||--value2:long(nullable=true)
    ||--value3:long(nullable=true)
    +---+-------+
    |键值|
    +---+-------+
    |a |[1,2,3]|
    |b |[2,3,4]|
    +---+-------+
    
    您可以使用
    *
    直接“拆分”列:

    df2.select('key','value.*').show()
    +---+------+------+------+
    |键|值1 |值2 |值3|
    +---+------+------+------+
    |a | 1 | 2 | 3|
    |b | 2 | 3 | 4|
    +---+------+------+------+
    

我想在pault答案中添加大小列表(数组)的情况

如果我们的列包含中型数组(或大型数组),仍然可以将它们拆分为列

key value1 value2 value3
a     1      2      3
b     2      3      4
结果是:

from pyspark.sql.types import *          # Needed to define DataFrame Schema.
from pyspark.sql.functions import expr   

# Define schema to create DataFrame with an array typed column.
mySchema = StructType([StructField("V1", StringType(), True),
                       StructField("V2", ArrayType(IntegerType(),True))])

df = spark.createDataFrame([['A', [1, 2, 3, 4, 5, 6, 7]], 
                            ['B', [8, 7, 6, 5, 4, 3, 2]]], schema= mySchema)

# Split list into columns using 'expr()' in a comprehension list.
arr_size = 7
df = df.select(['V1', 'V2']+[expr('V2[' + str(x) + ']') for x in range(0, arr_size)])

# It is posible to define new column names.
new_colnames = ['V1', 'V2'] + ['val_' + str(i) for i in range(0, arr_size)] 
df = df.toDF(*new_colnames)

@jordi Aceiton感谢您的解决方案。 我试图使它更简洁,试图删除重命名新创建的列名的循环,在创建列时这样做。 使用df.columns获取所有列名,而不是手动创建

df.show(truncate= False)

+---+---------------------+-----+-----+-----+-----+-----+-----+-----+
|V1 |V2                   |val_0|val_1|val_2|val_3|val_4|val_5|val_6|
+---+---------------------+-----+-----+-----+-----+-----+-----+-----+
|A  |[1, 2, 3, 4, 5, 6, 7]|1    |2    |3    |4    |5    |6    |7    |
|B  |[8, 7, 6, 5, 4, 3, 2]|8    |7    |6    |5    |4    |3    |2    |
+---+---------------------+-----+-----+-----+-----+-----+-----+-----+
输出:

    from pyspark.sql.types import *          
    from pyspark.sql.functions import * 
    from pyspark import Row

    df = spark.createDataFrame([Row(index=1, finalArray = [1.1,2.3,7.5], c =4),Row(index=2, finalArray = [9.6,4.1,5.4], c= 4)])
    #collecting all the column names as list
    dlist = df.columns
    #Appending new columns to the dataframe
    df.select(dlist+[(col("finalArray")[x]).alias("Value"+str(x+1)) for x in range(0, 3)]).show()

我需要取消712维数组的列列表,以便将其写入csv。我首先使用@MaFF的解决方案来解决我的问题,但这似乎会导致很多错误和额外的计算时间。我不确定是什么原因造成的,但我使用了另一种方法,大大减少了计算时间(22分钟,而不是4个多小时)

@MaFF的方法:

     +---------------+-----+------+------+------+
     |  finalArray   |index|Value1|Value2|Value3|
     +---------------+-----+------+------+------+
     |[1.1, 2.3, 7.5]|  1  |   1.1|   2.3|   7.5|
     |[9.6, 4.1, 5.4]|  2  |   9.6|   4.1|   5.4|
     +---------------+-----+------+------+------+
我用的是:

length = len(dataset.head()["list_col"])
dataset = dataset.select(dataset.columns + [dataset["list_col"][k] for k in range(length)])

如果有人知道是什么导致了计算时间的差异,请告诉我!我怀疑在我的例子中,瓶颈在于调用
head()
来获取列表长度(我希望是自适应的)。因为(i)我的数据管道相当长且详尽,(ii)我不得不取消多个列的列表。此外,缓存整个数据集不是一个选项。

如果要添加到@MaFF的答案中,对于arraytype数据,要动态执行,可以执行以下操作
df2.选择(['key']+[df2.features[x]代表范围内的x(0,3)])

当我使用
*
拆分StructType的列时,我可以重命名列吗?添加到答案中,为了让arraytype动态执行此操作,您可以执行类似于df2的操作。选择(['key']+[df2.features[x]代表范围内的x(0,3)])名称错误:未定义名称“col”
dataset = dataset.rdd.map(lambda x: (*x, *x["list_col"])).toDF()