山pの楽しいお勉強生活

勉強の成果を垂れ流していきます

PySparkでjsonカラムを縦持ちに変換する

正確には文字列でjsonが入っている時にパースして縦持ちにする方法。
また使いそうだが、すぐ忘れそうなのでメモ

データ

元データ

+---+--------------------------------------------------------------+
|id |json                                                          |
+---+--------------------------------------------------------------+
|100|[{"label": "男", "value": "1"},{"label": "女", "value": "2"}] |
|200|[{"label":"YES", "value":"10"},{"label":"NO", "value":"20"}]  |
+---+--------------------------------------------------------------+

処理後

+---+-----+-----+
| id|label|value|
+---+-----+-----+
|100|   男|    1|
|100|   女|    2|
|200|  YES|   10|
|200|   NO|   20|
+---+-----+-----+

コード

from pyspark.sql import functions as f
from pyspark.sql import types as t
df = spark.createDataFrame([
  ['100','[{"label": "男", "value": "1"}, {"label": "女", "value": "2"}]'],
  ['200','[{"label":"YES", "value":"10"},{"label":"NO", "value":"20"}]']
], ['id','json'])
df.show(100, False)
json_schema = t.ArrayType(t.StructType([t.StructField("label", t.StringType()),t.StructField("value", t.StringType())]))
print(json_schema)
df = (df
      .withColumn('json2', f.explode(f.from_json(f.col('json'), json_schema)))
      .withColumn('label', f.col('json2.label'))
      .withColumn('value', f.col('json2.value'))
      .drop('json', 'json2')
     )
df.show()

メモとか

  • f.from_jsonjsonをパース
  • schemaは↓でもとれるようだが、今回の場合は正しく作れなかったため自分で作成
    • json_schema = spark.read.json(df.rdd.map(lambda row: row.json)).schema
    • ↑のコードで作成 : StructType(List(StructField(label,StringType,true),StructField(value,StringType,true)))
    • 自力で作成 : ArrayType(StructType(List(StructField(label,StringType,true),StructField(value,StringType,true))),true)
  • f.explodeはリスト型の場合に行を作ってくれる
    • カンマやスペース区切りのデータの場合でもsplitしてから使用する事で、同様に使えそう。
  • 通常の?jsonだとf.json_tupleとか便利そう

参考