创建具有可变模式的 Pyspark 数据框

Posted

技术标签:

【中文标题】创建具有可变模式的 Pyspark 数据框【英文标题】:Creating a Pyspark data frame with variable schema 【发布时间】:2020-09-02 03:36:58 【问题描述】:

我想创建一个 pyspark 数据框,其中有一列具有可变架构。所以我的数据框看起来像这样:

| Id | Variable_Column                  |
|----|----------------------------------|
| 1  | ["col1":"val1"]                |
| 2  | ["col1":"val2", "col2":"val3"] |

所以要实现这一点。我是这样开始的:

schema = StructType([StructField("Id", IntegerType(), True),\
                      StructField("Variable_Column", ArrayType(StructType()), True)\
                               ])
valdict = dict()
valdict["col1"] = "val1"
values = [(1, [valdict])]
df = spark.createDataFrame(values, schema)
display(df)

| Id | Variable_Column |
|----|-----------------|
| 1  | []            |

这样做我正在创建一个空数组。这也感觉不对,我希望也保留内部列的类型。请建议插入数据的正确方法是什么。 对于我的变量列,我使用的是“ArrayType(StructType())”,这是正确的列类型吗?

【问题讨论】:

您能否提供一个详细的模式示例,并准确告诉我们您对该变量列的期望?我的主要问题是:什么是变量?长度?种类?结构? 嗨。在我的用例中,它可能是上述任何一种。例如,第一行可以有两个整数类型的键值对。第二行可以有 2 个字符串类型 2 个整数类型等。在 pyspark 数据帧中是否可能出现这种情况?如果不是,那么处理问题的正确方法是什么? 这在标准火花中是不​​可能的。列具有DataType,并且该列中的所有值都必须具有此类型。可变长度可以通过数组或映射来实现。但据我所知,这就是你所能做的。有解决方法,但在普通的 pyspark 中没有。让我尝试提供一个解决方案。 【参考方案1】:

解决方案 1

如果您只是想创建一个包含可变数量值的列,您可以使用ArrayTypeStructType。在您的情况下,您定义了一个空的StructType,因此您得到了结果。

你可以像这样定义一个数据框:

df1 = spark.createDataFrame([ (1, [('name1', 'val1'), ('name2', 'val2')]),
                              (2, [('name3', 'val3')])],
           ['Id', 'Variable_Column'])
df1.show(truncate=False)

与您提供的示例相对应:

+---+----------------------------+
|Id |Variable_Column             |
+---+----------------------------+
|1  |[[name1,val1], [name2,val2]]|
|2  |[[name3,val3]]              |
+---+----------------------------+

请注意,在这种情况下您不需要显式定义架构,但如果您愿意,它看起来像这样(您可以调用 df1.schema 顺便打印它):

schema = StructType([
             StructField('Id',LongType()),
             StructField('Variable_Column',ArrayType(StructType([
                   StructField('name',StringType()),
                   StructField('value',StringType())
             ])))
         ])

解决方案 2

非常相似,您可以像这样使用MapType 类型:

df2 = spark.createDataFrame([ (1, dict([('name1', 'val1'), ('name2', 'val2')])), 
                              (2, dict([('name3', 'val3')]) )
              ], ['Id', 'Variable_Column'])
df2.show(truncate=False)
+---+---------------------------------+
|Id |Variable_Column                  |
+---+---------------------------------+
|1  |Map(name2 -> val2, name1 -> val1)|
|2  |Map(name3 -> val3)               |
+---+---------------------------------+

解决方案 3

在评论中,您说您还需要变量类型。数据框不可能做到这一点。如果这确实是您想要的,那么您可能没有使用正确的工具。但如果这只是一个极端情况,您可以将数据的类型记录在这样的字符串中:

df3 = spark.createDataFrame([ (1, [('name1', 'val1', 'string'),
                                   ('name2', '0.6', 'double')]),
                              (2, [('name3', '3', 'integer')])],
           ['Id', 'Variable_Column'])
df3.show(truncate=False)
+---+-----------------------------------------+
|Id |Variable_Column                          |
+---+-----------------------------------------+
|1  |[[name1,val1,string], [name2,0.6,double]]|
|2  |[[name3,3,integer]]                      |
+---+-----------------------------------------+

【讨论】:

感谢您的解决方案,这很有帮助。我采用了解决方案 3 的想法,做了一些更改并将架构存储在单独的架构文件中。虽然我希望数据框默认具有该功能。【参考方案2】:

您可以如下定义架构:

schema = StructType([StructField("Id", IntegerType(), True),\
                      StructField("Variable_Column", ArrayType(MapType(StringType(),StringType())), True)\
                                ])

这将给出如下输出:

df.show()
+---+--------------------+
| Id|     Variable_Column|
+---+--------------------+
|  1|[[col2 -> val3, c...|
+---+--------------------+

【讨论】:

以上是关于创建具有可变模式的 Pyspark 数据框的主要内容,如果未能解决你的问题,请参考以下文章

pyspark:删除所有行中具有相同值的列

从具有目标列值的列更新 pyspark 数据框

PySpark数据框显示错误的值

从 pyspark 中的字典列创建数据框

pyspark 使用模式将 csv 文件加载到数据框中

如何使用其模式从 Pyspark 数据框创建配置单元表?