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_jsonでjsonをパース
- 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とか便利そう