将列表的列转换为数据框

Posted

技术标签:

【中文标题】将列表的列转换为数据框【英文标题】:Convert Column of List to Dataframe 【发布时间】:2017-12-08 09:49:46 【问题描述】:

我在 spark 数据框中有一列列表。

+-----------------+
|features         |
+-----------------+
|[0,45,63,0,0,0,0]|
|[0,0,0,85,0,69,0]|
|[0,89,56,0,0,0,0]|
+-----------------+

如何将其转换为 spark 数据框,其中列表中的每个元素都是数据框中的一列?我们可以假设列表的大小相同。

例如,

+--------------------+
|c1|c2|c3|c4|c5|c6|c7|
+--------------------+
|0 |45|63|0 |0 |0 |0 |
|0 |0 |0 |85|0 |69|0 |
|0 |89|56|0 |0 |0 |0 |
+--------------------+

【问题讨论】:

可能类似于this? 特征列的数据类型是什么。你能发布你的架构吗? 【参考方案1】:

你描述的实际上是VectorAssembler操作的反转。

可以通过转换为中间RDD来实现,如下:

spark.version
# u'2.2.0'

# your data:
df.show(truncate=False)
# +-----------------+ 
# |        features | 
# +-----------------+
# |[0,45,63,0,0,0,0]|
# |[0,0,0,85,0,69,0]|
# |[0,89,56,0,0,0,0]|
# +-----------------+ 

dimensionality = 7
out = df.rdd.map(lambda x: [float(x[0][i]) for i in range(dimensionality)]).toDF(schema=['c'+str(i+1) for i in range(dimensionality)])
out.show()
# +---+----+----+----+---+----+---+ 
# | c1|  c2|  c3|  c4| c5|  c6| c7|
# +---+----+----+----+---+----+---+ 
# |0.0|45.0|63.0| 0.0|0.0| 0.0|0.0|
# |0.0| 0.0| 0.0|85.0|0.0|69.0|0.0| 
# |0.0|89.0|56.0| 0.0|0.0| 0.0|0.0| 
# +---+----+----+----+---+----+---+

【讨论】:

【参考方案2】:

你可以使用getItem:

df.withColumn("c1", df["features"].getItem(0))\
  .withColumn("c2", df["features"].getItem(1))\
  .withColumn("c3", df["features"].getItem(2))\
  .withColumn("c4", df["features"].getItem(3))\
  .withColumn("c5", df["features"].getItem(4))\
  .withColumn("c6", df["features"].getItem(5))\
  .withColumn("c7", df["features"].getItem(6))\
  .drop('features').show()

+--------------------+
|c1|c2|c3|c4|c5|c6|c7|
+--------------------+
|0 |45|63|0 |0 |0 |0 |
|0 |0 |0 |85|0 |69|0 |
|0 |89|56|0 |0 |0 |0 |
+--------------------+

【讨论】:

【参考方案3】:

这是一个不转换为rdd的替代方案,

from pyspark.sql import functions as F

##Not incase of vectorAssembeler.
stop = df.select(F.max(F.size('features')).alias('size')).first().size ## if having a list of varying size, this might be useful.

udf1 = F.udf(lambda x : x.toArray().tolist(),ArrayType(FloatType()))
df = df.withColumn('features1',udf1('features'))

df.select(*[df.features1[i].alias('col_'.format(i)) for i in range(1,stop)]).show()
+-----+-----+-----+-----+-----+-----+
|col_1|col_2|col_3|col_4|col_5|col_6|
+-----+-----+-----+-----+-----+-----+
|   45|   63|    0|    0|    0|    0|
|    0|    0|   85|    0|   69|    0|
+-----+-----+-----+-----+-----+-----+

【讨论】:

该问题指定了“列表”列。为什么在这里使用 toArray()? 如果是列表列,没关系,我们不需要udf本身。但是,列名“功能”是它击中我的地方。 @desertnaut 我同意 @desertnaut 也同意。 好。作为奖励,我在您的帖子中添加了代码突出显示... ;) @mayankagrawal【参考方案4】:

@desertnaut 的回答也可以用 dataframe 和 udf 来完成。

import pyspark.sql.functions as F

dimensionality = 7
column_names = ['c'+str(i+1) for i in range(dimensionality)]
splits = [F.udf(lambda val:val[i],FloatType()) for i in range(dimensionality)]
df = df.select(*[s('features').alias(j) for s,j in zip(splits,column_names)])

【讨论】:

这是否适用于向量列或数组类型列? @Suresh 不错 - 它不适用于向量列(已测试) 没错,如果我们使用数组类型,我们可以直接索引它。 @mayankagrawal 没有 @mayankagrawal 类向量具有 toArray() 方法。只有类 densevector 和 sparsevector 有值。如果我错了,请纠正我。请检查这个,spark.apache.org/docs/2.2.0/api/python/…

以上是关于将列表的列转换为数据框的主要内容,如果未能解决你的问题,请参考以下文章

将字典列表的 Python 数据框列转换为具有单个元素的列

如何使用pyspark将具有多个可能值的Json数组列表转换为数据框中的列

将多个火花数据框列转换为具有列表类型的单列

列表的列,将列表转换为字符串作为新列

如何将元组列表转换为 pandas 数据框,以便每个元组的第一个值代表一列?

将包含字符串和 NAN 的列转换为 Pandas 中的整数列表