カテゴリー

Python基礎

【辞書&pandas】dict{name: , val: {a: [~], b:[~]}}のpandas化

2021年4月10日

多項式関数のグラフ

こんな人にオススメ


ネストされたdict配列をpandasDataFrameに変換したいんだけどどうしたらいい?

最近、以下のような、辞書の一部の中にさらに辞書の入っている形式の辞書をtxtファイルに保存する機会があった。その時に使用した辞書からpandasDataFrameへの変換方法について今回は紹介する。

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
スポンサーリンク
スポンサーリンク

運営者のメガネです。TwitterInstagramも運営してます。

自己紹介はこちらから、お問い合わせはこちら。

運営者メガネ

データの作成とDataFrame

まずは辞書型のデータを作成する。その後、その辞書をpandasDataFrameに変換する。

データ作成

今回は多項式を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に変換

前節で辞書型を作成したので、ここではpandasDataFrameに変換する。まずはそのまま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ファイルに書き込む。まずはdf1df1はインデックスが行番号でかつ、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の情報も存在する。実際に使用する際にはxy、そしてインデックスの情報をうまく分けないといけない。

# 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

データの読み込み

データの読み込みに関しては、df2df3の場合で解説する。まずは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がネストされた辞書をpandasDataFrameに変換し、書き込み・読み込み・グラフ化を行なった。

ネストさせることでデータ構造的にはわかりやすくはなるが扱うのが難しくなる。色々なアプローチ方法があるのでみなさま個人で最適と思われる方法を見つけてほしい。

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-Python基礎
-, ,