来自 Python 字典的 PySpark 数据框,没有 Pandas

Posted

技术标签:

【中文标题】来自 Python 字典的 PySpark 数据框,没有 Pandas【英文标题】:PySpark Dataframe from Python Dictionary without Pandas 【发布时间】:2018-07-27 09:29:15 【问题描述】:

我正在尝试将以下 Python dict 转换为 PySpark DataFrame,但我没有得到预期的输出。

dict_lst = 'letters': ['a', 'b', 'c'], 
             'numbers': [10, 20, 30]
df_dict = sc.parallelize([dict_lst]).toDF()  # Result not as expected
df_dict.show()

有没有办法在不使用 Pandas 的情况下做到这一点?

【问题讨论】:

【参考方案1】:

引用myself:

我发现将 createDataFrame() 的参数视为元组列表很有用,其中列表中的每个条目对应于 DataFrame 中的一行,元组的每个元素对应于一列。

所以最简单的事情就是把你的字典转换成这种格式。您可以使用zip() 轻松做到这一点:

column_names, data = zip(*dict_lst.items())
spark.createDataFrame(zip(*data), column_names).show()
#+-------+-------+
#|letters|numbers|
#+-------+-------+
#|      a|     10|
#|      b|     20|
#|      c|     30|
#+-------+-------+

以上假设所有列表的长度相同。如果不是这种情况,则必须使用 itertools.izip_longest (python2) 或 itertools.zip_longest (python3)。

from itertools import izip_longest as zip_longest # use this for python2
#from itertools import zip_longest # use this for python3

dict_lst = 'letters': ['a', 'b', 'c'], 
             'numbers': [10, 20, 30, 40]

column_names, data = zip(*dict_lst.items())

spark.createDataFrame(zip_longest(*data), column_names).show()
#+-------+-------+
#|letters|numbers|
#+-------+-------+
#|      a|     10|
#|      b|     20|
#|      c|     30|
#|   null|     40|
#+-------+-------+

【讨论】:

【参考方案2】:

您的dict_lst 并不是您真正想要采用的格式来创建数据框。如果你有一个字典列表而不是列表字典会更好。

此代码从您的列表中创建一个 DataFrame :

from pyspark.sql import SQLContext, Row

sqlContext = SQLContext(sc)

dict_lst = 'letters': ['a', 'b', 'c'], 
             'numbers': [10, 20, 30]

values_lst = dict_lst.values()
nb_rows = [len(lst) for lst in values_lst]
assert min(nb_rows)==max(nb_rows) #We must have the same nb of elem for each key

row_lst = []
columns = dict_lst.keys()

for i in range(nb_rows[0]):
    row_values = [lst[i] for lst in values_lst]
    row_dict = column: value for column, value in zip(columns, row_values)
    row = Row(**row_dict)
    row_lst.append(row)

df = sqlContext.createDataFrame(row_lst)

【讨论】:

【参考方案3】:

使用上面的pault's 答案,我在我的数据框上强加了一个特定的架构,如下所示:

import pyspark
from pyspark.sql import SparkSession, functions

spark = SparkSession.builder.appName('dictToDF').getOrCreate()

获取数据:

dict_lst = 'letters': ['a', 'b', 'c'],'numbers': [10, 20, 30]
data = dict_lst.values()

创建架构:

from pyspark.sql.types import *
myschema= StructType([ StructField("letters", StringType(), True)\
                      ,StructField("numbers", IntegerType(), True)\
                         ])

从字典创建 df - 使用架构:

df=spark.createDataFrame(zip(*data), schema = myschema)
df.show()
+-------+-------+
|letters|numbers|
+-------+-------+
|      a|     10|
|      b|     20|
|      c|     30|
+-------+-------+

显示 df 架构:

df.printSchema()

root
 |-- letters: string (nullable = true)
 |-- numbers: integer (nullable = true)

【讨论】:

【参考方案4】:

您还可以使用 Python List 快速构建 DataFrame 原型。这个想法是基于Databricks的教程。

df = spark.createDataFrame(
    [(1, "a"), 
     (1, "a"), 
     (1, "b")],
    ("id", "value"))
df.show()
+---+-----+
| id|value|
+---+-----+
|  1|    a|
|  1|    a|
|  1|    b|
+---+-----+

【讨论】:

【参考方案5】:

试试这个:

dict_lst = ['letters': 'a', 'numbers': 10, 
            'letters': 'b', 'numbers': 20, 
            'letters': 'c', 'numbers': 30]
df_dict = sc.parallelize(dict_lst).toDF()  # Result as expected

输出:

>>> df_dict.show()
+-------+-------+
|letters|numbers|
+-------+-------+
|      a|     10|
|      b|     20|
|      c|     30|
+-------+-------+

【讨论】:

如果他的dict_lst 不采用这种格式,这实际上是不可扩展的。【参考方案6】:

最有效的方法是使用 Pandas

import pandas as pd

spark.createDataFrame(pd.DataFrame(dict_lst))

【讨论】:

问题中说“不使用 Pandas”。

以上是关于来自 Python 字典的 PySpark 数据框,没有 Pandas的主要内容,如果未能解决你的问题,请参考以下文章

将标准 python 键值字典列表转换为 pyspark 数据框

将字典保存为 pyspark 数据框并加载它 - Python、Databricks

将列字典从不同的数据帧转换为数据帧:pyspark

pyspark:来自rdd的包含列表列表的数据框

pyspark 从 pyspark sql 数据框创建字典数据

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