こんな人にオススメ
ネストされた
dict
配列をpandas
のDataFrame
に変換したいんだけどどうしたらいい?最近、以下のような、辞書の一部の中にさらに辞書の入っている形式の辞書をtxtファイルに保存する機会があった。その時に使用した辞書から
pandas
のDataFrame
への変換方法について今回は紹介する。
import numpy as np import pandas as pd import sys dct = { 'name': 'name', # valがネストされている 'val': { 'a': [1, 2, 3], 'b': [10, 20, 30], } }
python環境は以下。
- Python 3.9.2
- numpy 1.20.1
- pandas 1.2.3
データの作成とDataFrame
化
まずは辞書型のデータを作成する。その後、その辞書をpandas
のDataFrame
に変換する。
データ作成
今回は多項式を1つのx
で作成し、多項式の部分をネストする形式とする。
# 最終データを入れる辞書を作成 data = {} # 横軸 x = np.arange(-2, 2 + 0.01, 0.01) data['x'] = x # 縦軸 # 字数の英語名称 name = { 1: 'linear', 2: 'quadratic', 3: 'cubic', 4: 'quartic', 5: 'quintic', } data['y'] = {} for order in range(1, 6): data['y'][name[order]] = x ** order
dataから派生するkeyの一覧は以下の通り。
'x', 'y', ['y']['linear'], ['y']['quadratic'], ['y']['cubic'], ['y']['quartic'], ['y']['quintic']
DataFrame
に変換
前節で辞書型を作成したので、ここではpandas
のDataFrame
に変換する。まずはそのままpd.DataFrame
に入れる。しかしdata
はネストの構造になっているのでそのままではエラー。
# 単純にDataFrameにする # df0 = pd.DataFrame(data) # ValueError: Mixing dicts with non-Series may lead to ambiguous ordering.
ではネスト部分だけ取り出したらどうかというとそれは可能。しかし、横軸を担うx
の情報が消える。
# yだけにするとエラーは出ないが、xがない df1 = pd.DataFrame(data['y']) print(df1) # linear quadratic cubic quartic quintic # 0 -2.00 4.0000 -8.000000 16.000000 -32.000000 # 1 -1.99 3.9601 -7.880599 15.682392 -31.207960 # 2 -1.98 3.9204 -7.762392 15.369536 -30.431682 # 3 -1.97 3.8809 -7.645373 15.061385 -29.670928 # 4 -1.96 3.8416 -7.529536 14.757891 -28.925465 # .. ... ... ... ... ... # 396 1.96 3.8416 7.529536 14.757891 28.925465 # 397 1.97 3.8809 7.645373 15.061385 29.670928 # 398 1.98 3.9204 7.762392 15.369536 30.431682 # 399 1.99 3.9601 7.880599 15.682392 31.207960 # 400 2.00 4.0000 8.000000 16.000000 32.000000 # [401 rows x 5 columns]
そこで、1つのDataFrame
にするためにx
部分とy
部分を新たな辞書の中で展開してDataFrame
にする。この場合はエラーが出ずにクリア。しかし、インデックスが「0 1 2 ...」のように行番号になっている。
# 辞書の中で展開して、xをDataFrameに入れる df2 = pd.DataFrame({**{'x': data['x']}, **data['y']}) print(df2) # x linear quadratic cubic quartic quintic # 0 -2.00 -2.00 4.0000 -8.000000 16.000000 -32.000000 # 1 -1.99 -1.99 3.9601 -7.880599 15.682392 -31.207960 # 2 -1.98 -1.98 3.9204 -7.762392 15.369536 -30.431682 # 3 -1.97 -1.97 3.8809 -7.645373 15.061385 -29.670928 # 4 -1.96 -1.96 3.8416 -7.529536 14.757891 -28.925465 # .. ... ... ... ... ... ... # 396 1.96 1.96 3.8416 7.529536 14.757891 28.925465 # 397 1.97 1.97 3.8809 7.645373 15.061385 29.670928 # 398 1.98 1.98 3.9204 7.762392 15.369536 30.431682 # 399 1.99 1.99 3.9601 7.880599 15.682392 31.207960 # 400 2.00 2.00 4.0000 8.000000 16.000000 32.000000 # [401 rows x 6 columns]
ということで、x
がインデックスとなるように指定した。この場合はインデックスが行番号ではなくなるのでスッキリした見た目になる。
# indexはxであると指定 df3 = pd.DataFrame({**{'x': data['x']}, **data['y']}).set_index('x') print(df3) # linear quadratic cubic quartic quintic # x # -2.00 -2.00 4.0000 -8.000000 16.000000 -32.000000 # -1.99 -1.99 3.9601 -7.880599 15.682392 -31.207960 # -1.98 -1.98 3.9204 -7.762392 15.369536 -30.431682 # -1.97 -1.97 3.8809 -7.645373 15.061385 -29.670928 # -1.96 -1.96 3.8416 -7.529536 14.757891 -28.925465 # ... ... ... ... ... ... # 1.96 1.96 3.8416 7.529536 14.757891 28.925465 # 1.97 1.97 3.8809 7.645373 15.061385 29.670928 # 1.98 1.98 3.9204 7.762392 15.369536 30.431682 # 1.99 1.99 3.9601 7.880599 15.682392 31.207960 # 2.00 2.00 4.0000 8.000000 16.000000 32.000000 # [401 rows x 5 columns]
データの書き込みと読み込み
前章で辞書をDataFrame
に変換した。ここでは作成したDataFrame
をtxtファイルに書き込み、そしてそのファイルを再度読み込む。
書き込み
前章で作成したDataFrame
をtxtファイルに書き込む。まずはdf1
。df1
はインデックスが行番号でかつ、x
の情報が抜け落ちてしまっている。そのため、df1
を使用する際にはx
を別途指定しなければならない。
# yとインデックスの0, 1, 2, 3,... df1.to_csv('dict_pandas1.txt', sep='\\t') # linear quadratic cubic quartic quintic # 0 -2.0 4.0 -8.0 16.0 -32.0 # 1 -1.99 3.9601 -7.880599 15.68239201 -31.2079600999 # 2 -1.98 3.9204 -7.762392 15.36953616 -30.431681596799997 # 3 -1.97 3.8809 -7.645372999999999 15.06138481 -29.670928075699997 # 4 -1.96 3.8415999999999997 -7.529535999999999 14.757890559999998 -28.925465497599998 # 5 -1.95 3.8024999999999998 -7.414874999999999 14.459006249999998 -28.195062187499996 # 6 -1.94 3.7636 -7.301384 14.164684959999999 -27.479488822399997 # 7 -1.93 3.7249 -7.189056999999999 13.874880009999998 -26.778518419299996 # 8 -1.92 3.6864 -7.077887999999999 13.589544959999998 -26.091926323199996
df2
でもインデックスが行番号であるが、今回はx
の情報も存在する。実際に使用する際にはx
とy
、そしてインデックスの情報をうまく分けないといけない。
# x, yとインデックスの0, 1, 2, 3,... df2.to_csv('dict_pandas2.txt', sep='\\t') # x linear quadratic cubic quartic quintic # 0 -2.0 -2.0 4.0 -8.0 16.0 -32.0 # 1 -1.99 -1.99 3.9601 -7.880599 15.68239201 -31.2079600999 # 2 -1.98 -1.98 3.9204 -7.762392 15.36953616 -30.431681596799997 # 3 -1.97 -1.97 3.8809 -7.645372999999999 15.06138481 -29.670928075699997 # 4 -1.96 -1.96 3.8415999999999997 -7.529535999999999 14.757890559999998 -28.925465497599998 # 5 -1.95 -1.95 3.8024999999999998 -7.414874999999999 14.459006249999998 -28.195062187499996 # 6 -1.94 -1.94 3.7636 -7.301384 14.164684959999999 -27.479488822399997 # 7 -1.93 -1.93 3.7249 -7.189056999999999 13.874880009999998 -26.778518419299996 # 8 -1.92 -1.92 3.6864 -7.077887999999999 13.589544959999998 -26.091926323199996
df3
の場合はインデックスがx
になっているので、データを見たときに一番左にx
があるから横軸だなとわかりやすい。しかし、txtファイルにした時点でDataFrameのインデックスとしての機能はなくなっているので、読み込むときはインデックスの指定をしなければいけない。
# xをインデックスにしたy df3.to_csv('dict_pandas3.txt', sep='\\t') # x linear quadratic cubic quartic quintic # -2.0 -2.0 4.0 -8.0 16.0 -32.0 # -1.99 -1.99 3.9601 -7.880599 15.68239201 -31.2079600999 # -1.98 -1.98 3.9204 -7.762392 15.36953616 -30.431681596799997 # -1.97 -1.97 3.8809 -7.645372999999999 15.06138481 -29.670928075699997 # -1.96 -1.96 3.8415999999999997 -7.529535999999999 14.757890559999998 -28.925465497599998 # -1.95 -1.95 3.8024999999999998 -7.414874999999999 14.459006249999998 -28.195062187499996 # -1.94 -1.94 3.7636 -7.301384 14.164684959999999 -27.479488822399997 # -1.93 -1.93 3.7249 -7.189056999999999 13.874880009999998 -26.778518419299996 # -1.92 -1.92 3.6864 -7.077887999999999 13.589544959999998 -26.091926323199996
また、df3
で書き込み時にindex
を指定したとしてもtxtファイル上では何も変化はない。
# xをインデックスにしたy。xをindex指定しても上記とは変わらない df3.to_csv('dict_pandas3_2.txt', sep='\\t', index='x') # x linear quadratic cubic quartic quintic # -2.0 -2.0 4.0 -8.0 16.0 -32.0 # -1.99 -1.99 3.9601 -7.880599 15.68239201 -31.2079600999 # -1.98 -1.98 3.9204 -7.762392 15.36953616 -30.431681596799997 # -1.97 -1.97 3.8809 -7.645372999999999 15.06138481 -29.670928075699997 # -1.96 -1.96 3.8415999999999997 -7.529535999999999 14.757890559999998 -28.925465497599998 # -1.95 -1.95 3.8024999999999998 -7.414874999999999 14.459006249999998 -28.195062187499996 # -1.94 -1.94 3.7636 -7.301384 14.164684959999999 -27.479488822399997 # -1.93 -1.93 3.7249 -7.189056999999999 13.874880009999998 -26.778518419299996 # -1.92 -1.92 3.6864 -7.077887999999999 13.589544959999998 -26.091926323199996
データの読み込み
データの読み込みに関しては、df2
とdf3
の場合で解説する。まずはdf2
。この場合はx
と行番号が両立しているので行番号を使用せず、x
をインデックスとするように指定する。
# 使用するインデックスはxと各他国式の列なので、1-6列目を使用 # インデックスにする列はそのうちの0列目に該当 df_read2 = pd.read_csv( 'dict_pandas2.txt', sep='\\t', index_col=0, usecols=[1, 2, 3, 4, 5, 6], ) print(df_read2) # linear quadratic cubic quartic quintic # x # -2.00 -2.00 4.0000 -8.000000 16.000000 -32.000000 # -1.99 -1.99 3.9601 -7.880599 15.682392 -31.207960 # -1.98 -1.98 3.9204 -7.762392 15.369536 -30.431682 # -1.97 -1.97 3.8809 -7.645373 15.061385 -29.670928 # -1.96 -1.96 3.8416 -7.529536 14.757891 -28.925465 # ... ... ... ... ... ... # 1.96 1.96 3.8416 7.529536 14.757891 28.925465 # 1.97 1.97 3.8809 7.645373 15.061385 29.670928 # 1.98 1.98 3.9204 7.762392 15.369536 30.431682 # 1.99 1.99 3.9601 7.880599 15.682392 31.207960 # 2.00 2.00 4.0000 8.000000 16.000000 32.000000 # [401 rows x 5 columns]
一方で、df3
はインデックスがすでにx
の状態で出力したので、インデックスの位置を指定するだけ。
# インデックスに使用するのは0列目のx df_read3 = pd.read_csv('dict_pandas3.txt', sep='\\t', index_col=0,) print(df_read3) # linear quadratic cubic quartic quintic # x # -2.00 -2.00 4.0000 -8.000000 16.000000 -32.000000 # -1.99 -1.99 3.9601 -7.880599 15.682392 -31.207960 # -1.98 -1.98 3.9204 -7.762392 15.369536 -30.431682 # -1.97 -1.97 3.8809 -7.645373 15.061385 -29.670928 # -1.96 -1.96 3.8416 -7.529536 14.757891 -28.925465 # ... ... ... ... ... ... # 1.96 1.96 3.8416 7.529536 14.757891 28.925465 # 1.97 1.97 3.8809 7.645373 15.061385 29.670928 # 1.98 1.98 3.9204 7.762392 15.369536 30.431682 # 1.99 1.99 3.9601 7.880599 15.682392 31.207960 # 2.00 2.00 4.0000 8.000000 16.000000 32.000000 # [401 rows x 5 columns]
グラフ化
最後に読み込んだデータをグラフ化する。グラフ化する方法は下記記事に書いている、即席plotly
のコードで行う。
-
-
【随時更新 備忘録】plotlyのグラフ即席作成コード
続きを見る
即席コードのあるディレクトリは2つ親なので、sys.path.apped('../../')
で階層を登っている。また、ファイル名はplotly_layout_template.py
。
sys.path.append('../../') import plotly_layout_template as template # グラフ化用にデータ整形 lst = [] for name, val in df_read3.items(): print(name) dct = {'x': df_read3.index, 'y': val.values, 'name': name} lst.append(dct) # グラフ化 template.graph( data=lst, title='polynominal', xtitle='x', ytitle='y', pic=True, save=True, filename='dict_pandas', )
便利にすると複雑化
今回はy
がネストされた辞書をpandas
のDataFrame
に変換し、書き込み・読み込み・グラフ化を行なった。
ネストさせることでデータ構造的にはわかりやすくはなるが扱うのが難しくなる。色々なアプローチ方法があるのでみなさま個人で最適と思われる方法を見つけてほしい。
-
-
【plt&pandas】df.plot()でmatplotlibのグラフを作成
2022/8/19
こんな人にオススメ pandasのデータフ& ...
-
-
【Python&Excel】openpyxlでフォルダ内の複数csv→1つのExcelへ
2022/8/19
こんな人にオススメ 複数のcsvのデ ...
-
-
【plotly&pandas】df.plot()でPlotlyのグラフを作成
2022/8/19
こんな人にオススメ pnadasのデータフ& ...
-
-
【python&Excel】pandasでエクセルファイルを読み込み・書き出し
2022/8/19
こんな人にオススメ pandasを使用してc ...