我需要遍历一个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)本身添加列。
答案 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.*")