如何不使用withcolumn将列添加到数据框

时间:2019-03-28 12:48:32

标签: pyspark

我需要遍历一个json文件,展平结果,并在每个循环中使用各自的值向数据框添加一列。但是最终结果将有大约2000列。因此,使用withColumn添加列非常慢。他们是否还有其他选择可将列添加到数据框?

样本输入json:

[
  {
    "ID": "12345",
    "Timestamp": "20140101",
    "Usefulness": "Yes",
    "Code": [
      {
        "event1": "A",
        "result": "1"
      }
    ]
  },
  {
    "ID": "1A35B",
    "Timestamp": "20140102",
    "Usefulness": "No",
    "Code": [
      {
        "event1": "B",
        "result": "1"
      }
    ]
  }
]

我的输出应该是:


ID     Timestamp  Usefulness  Code_event1  Code_result

12345  20140101   Yes          A           1
1A35B  20140102   No           B           1 

我正在处理的json文件很大,并且包含许多列。因此,在我的情况下,withColumn不可行。

编辑:

示例代码:

# Data file
df_data = spark.read.json(file_path)  

# Schema file
with open(schemapath) as fh:
    jsonschema = json.load(fh,object_pairs_hook=OrderedDict)

我正在遍历架构文件,并且在循环中我正在从数据DF(df_data)访问特定键的数据。我这样做是因为我的数据文件有多个记录,所以我无法遍历数据json文件,否则它将遍历每条记录。

def func_structs(json_file):
    for index,(k,v) in enumerate(json_file.items()):
        if isinstance(v, dict):
           srccol = k
           func_structs(v)
        elif isinstance(v, list):
           srccol = k
           func_lists(v) # Separate function to loop through list elements to find nested elements
        else:
            try:
                df_data = df_data.withColumn(srcColName,df_Data[srcCol])
            except:
                df_data = df_data.withColumn(srcColName,lit(None).cast(StringType()))

func_structs(jsonschema)

我正在向数据DF(df_data)本身添加列。

1 个答案:

答案 0 :(得分:0)

一种方法是使用Spark的内置json解析器将json读取到DF中:

df = (sqlContext
      .read
      .option("multiLine", True)
      .option("mode", "PERMISSIVE")
      .json('file:///mypath/file.json')) # change as necessary

结果如下:

+--------+-----+---------+----------+
|    Code|   ID|Timestamp|Usefulness|
+--------+-----+---------+----------+
|[[A, 1]]|12345| 20140101|       Yes|
|[[B, 1]]|1A35B| 20140102|        No|
+--------+-----+---------+----------+

然后第二步是分解Code列中的结构:

df = df.withColumn('Code_event1', f.col('Code').getItem(0).getItem('event1'))
df = df.withColumn('Code_result', f.col('Code').getItem(0).getItem('result'))
df.show()

给出

+--------+-----+---------+----------+-----------+-----------+
|    Code|   ID|Timestamp|Usefulness|Code_event1|Code_result|
+--------+-----+---------+----------+-----------+-----------+
|[[A, 1]]|12345| 20140101|       Yes|          A|          1|
|[[B, 1]]|1A35B| 20140102|        No|          B|          1|
+--------+-----+---------+----------+-----------+-----------+

编辑:

基于下面@pault的注释,这是一种捕获所需值的更巧妙的方法(在load语句后运行此代码):

df = df.withColumn('Code', f.explode('Code'))
df.select("*", "Code.*")