【问题标题】:PySpark Dataframe from Python Dictionary without Pandas来自 Python 字典的 PySpark 数据框,没有 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 的情况下做到这一点?

【问题讨论】:

    标签: pyspark pyspark-sql


    【解决方案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”。
            猜你喜欢
            • 2018-05-04
            • 2016-02-10
            • 2014-09-28
            • 2018-11-17
            • 2018-12-11
            • 2013-09-12
            • 2016-04-07
            相关资源
            最近更新 更多