如何在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()
您可以像使用python一样使用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)
访问这些值:[]
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]| +---+-------+
- 如果它的类型为
:(可能是通过读取JSON构建数据帧)StructType()
您可以使用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| +---+------+------+------+
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()