Pythonでlist型やdict型のデータをDataFrameに変換する

Pythonのプログラミング中にlist型のデータをDataFrameにすると便利なときってありますよね。やり方を忘れやすいので、記事にしてみました。

listからDataFrameへの変換が理解しずらい理由に、リストの次元の理解度があると思っています。

あと、データを扱うときに辞書型とDataFrameのどちらを使うか迷うときがありますよね。私は軽いデータは辞書型で、量が多いデータはDataFrameで扱っています。いつでもDataFrameでもいいと思います。この記事では辞書型(dict型)をDataFrameに変換する方法も書きました。

list型をDataFrameに変換する

3行1列のリストをDataFrameに変換する

まずは、基本から始めます。
[0, 1, 2] をDataFrameに変換してみます。
[0, 1, 2] は行列的に言うと3行1列です。

l = [0, 1, 2]

print(l)
print(json.dumps(l, indent=4))
print(type(l))

# [0, 1, 2]
# [
#     0,
#     1,
#     2
# ]
# <class 'list'>

リストのサイズを見てみます。
[0, 1, 2] のサイズは3です。

# リストのサイズを見る。
l = [0, 1, 2]

print('size:{}'.format(len(l)))
# size:3

list型をnumpy.ndarray型に変換してみます。
[0, 1, 2] は [0 1 2] になりました。

# list型をnumpy.ndarray型に変換する。
l = [0, 1, 2]
n = np.array(l)

print(n)
print(type(n))
# [0 1 2]
# <class 'numpy.ndarray'>

次元数と各次元のサイズを見てみます。
[0 1 2] は1次元で、1次元目のサイズは3でした。

# 次元数と各次元のサイズを見る。
print('ndim:{}'.format(n.ndim))
print('shape:{}'.format(n.shape))

# [0 1 2]は1次元で、1次元目のサイズは3である。
# ndim:1
# shape:(3,)

では、lis型の [0, 1, 2] をDataFrameに変換する方法です。

l = [0, 1, 2]
df = pd.DataFrame(
    data=l,
    )

print(df)
#    0
# 0  0
# 1  1
# 2  2

Index名とカラム名を付ける場合の変換方法です。
3行1列なので、Rowの名前が3つで、Columnの名前が1つです。

l = [0, 1, 2]
df = pd.DataFrame(
    data=l,
    index=['r1', 'r2', 'r3'],
    columns=['c1'],
    )

print(df)
#     c1
# r1   0
# r2   1
# r3   2

1行3列のリストをDataFrameに変換する

3行1列の変換ができたので、1行3列を変換してみます。

1行3列のリストは [[0, 1, 2]] を例に説明します。

l = [[0, 1, 2]]

print(l)
print(json.dumps(l, indent=4))
print(type(l))

# [[0, 1, 2]]
# [
#     [
#         0,
#         1,
#         2
#     ]
# ]
# <class 'list'>


# リストのサイズを見る。
print('size:{}'.format(len(l)))
# size:1
[[0, 1, 2]] をnumpy.ndarray型に変換すると [[0 1 2]] になります。

# list型をnumpy.ndarray型に変換する。
l = [[0, 1, 2]]
n = np.array(l)

print(n)
print(type(n))

# [[0 1 2]]
# <class 'numpy.ndarray'>
[[0 1 2]] の次元は2で、1次元目のサイズは1で、2次元目のサイズは3となります。

# 次元数と各次元のサイズを見る。
print('ndim:{}'.format(n.ndim))
print('shape:{}'.format(n.shape))

# [[0 1 2]]は2次元で、1次元目のサイズは1で、2次元目のサイズは3である。
# ndim:2
# shape:(1, 3)

list型の [[0, 1, 2]] をDataFrameに変換する方法です。

l = [[0, 1, 2]]
df = pd.DataFrame(
    data=l,
    )

print(df)
#    0  1  2
# 0  0  1  2

Index名とカラム名を付ける場合は、以下のようにします。

l = [[0, 1, 2]]
df = pd.DataFrame(
    data=l,
    index=['r1'],
    columns=['c1', 'c2', 'c3'],
    )

print(df)
#     c1  c2  c3
# r1   0   1   2

2行3列のリストをDataFrameに変換する

続いて、2行3列のリストをDataFrameに変換してみます。

2行3列のリストの例は [[0, 1, 2], [3, 4, 5]] とします。

l = [[0, 1, 2], [3, 4, 5]]

print(l)
print(json.dumps(l, indent=4))
print(type(l))

# [[0, 1, 2], [3, 4, 5]]
# [
#     [
#         0,
#         1,
#         2
#     ],
#     [
#         3,
#         4,
#         5
#     ]
# ]
# <class 'list'>

# リストのサイズを見る。
print('size:{}'.format(len(l)))
# size:2

list型をnumpy.ndarray型に変換してみます。

# list型をnumpy.ndarray型に変換する。
l = [[0, 1, 2], [3, 4, 5]]
n = np.array(l)

print(n)
print(type(n))
# [[0 1 2]
#  [3 4 5]]
# <class 'numpy.ndarray'>

次元と各次元のサイズを見てみます。

# 次元数と各次元のサイズを見る。
print('ndim:{}'.format(n.ndim))
print('shape:{}'.format(n.shape))

# [[0 1 2] [3 4 5]]は2次元で、1次元目のサイズは2で、2次元目のサイズは3である。
# ndim:2
# shape:(2, 3)

list型の [[0, 1, 2], [3, 4, 5]] をDataFrameにする方法です。

l = [[0, 1, 2], [3, 4, 5]]
df = pd.DataFrame(
    data=l,
    )

print(df)
#    0  1  2
# 0  0  1  2
# 1  3  4  5

Index名とカラム名を付ける変換方法です。2行3列なので

l = [[0, 1, 2], [3, 4, 5]]
df = pd.DataFrame(
    data=l,
    index=['r1', 'r2'],
    columns=['c1', 'c2', 'c3'],
    )

print(df)
#     c1  c2  c3
# r1   0   1   2
# r2   3   4   5

dict型をDataFrameに変換する

辞書型(dict型)をDataFrameに変換する方法です。

シンプルな辞書データの場合は、辞書のキーをDataFrameのIndex(行)にするのか、カラム(列)にするのか、という問題が発生します。

例えば、{‘a’: 0, ‘b’: 1, ‘c’: 2} というデータだとa, b, cというキーをIndexで持ちたいのかカラムでヘッダとして持ちたいのかという問題です。

辞書型の {‘a’: 0, ‘b’: 1, ‘c’: 2} をサンプルにして、DataFrameに変換してみます。

辞書型のキーは辞書.keys()で、値は辞書.values()で取得できます。

d = {'a': 0, 'b': 1, 'c': 2}

print(json.dumps(d, indent=4))
print(type(d))
# {
#     "a": 0,
#     "b": 1,
#     "c": 2
# }
# <class 'dict'>

# 辞書型のキーと値を表示する。
print(d.keys())
print(d.values())
# dict_keys(['a', 'b', 'c'])
# dict_values([0, 1, 2])

そのままDataFrameに変換すると、ValueErrorになってしまいます。
ValueError: If using all scalar values, you must pass an index

d = {'a': 0, 'b': 1, 'c': 2}
df = pd.DataFrame(
        data=d,
        )

# 以下のエラーになる。
# ValueError: If using all scalar values, you must pass an index

辞書.values() を入れるだけだと、キー情報をDataFrameに渡すことができません。

d = {'a': 0, 'b': 1, 'c': 2}
df = pd.DataFrame(
        data=d.values(),
        )

print(df)
#    0
# 0  0
# 1  1
# 2  2

辞書型のキーをDataFrameのIndex(行)にして変換する

辞書のキーをIndexにしたい場合の変換方法です。index=辞書.keys() を使います。

d = {'a': 0, 'b': 1, 'c': 2}
df = pd.DataFrame(
        data=d.values(),
        index=d.keys(),
        )

print(df)
#    0
# a  0
# b  1
# c  2

辞書型のキーをDataFrameのカラム(列)にして変換する

辞書のキーをカラムにしたい場合の変換方法です。データ部分の辞書.values()はリストの大括弧([])で囲み、columns=辞書.keys()とします。

d = {'a': 0, 'b': 1, 'c': 2}
df = pd.DataFrame(
        data=[d.values()],
        columns=d.keys(),
        )

print(df)
#    a  b  c
# 0  0  1  2

中身が辞書のリストをDataFrameに変換する

次は変速で、リストの中身が辞書型になっているデータをDataFrameに変換します。
REST APIを使ってデータを収集するときなどに出くわすと思います。

中身の辞書のキーが同じ

リストの中身が辞書のデータで辞書のキーが同じサンプルとして、以下のようなデータを使います。キーはa, b, cで同じです。

l = [{'a': 0, 'b': 1, 'c': 2}, {'a': 3, 'b': 4, 'c': 5}]

print(json.dumps(l, indent=4))
print(type(l))

# [
#     {
#         "a": 0,
#         "b": 1,
#         "c": 2
#     },
#     {
#         "a": 3,
#         "b": 4,
#         "c": 5
#     }
# ]
# <class 'list'>

辞書のキーはカラムに使うとします。変換方法の一例を示しますが、このやり方ではなく次に説明する方法でもできます。

# リストの中身の辞書のキーと値を取得する。リスト内包表記を使用する。
l = [{'a': 0, 'b': 1, 'c': 2}, {'a': 3, 'b': 4, 'c': 5}]
k = [x.keys() for x in l]
v = [x.values() for x in l]

print(k)
print(v)
# [dict_keys(['a', 'b', 'c']), dict_keys(['a', 'b', 'c'])]
# [dict_values([0, 1, 2]), dict_values([3, 4, 5])]

df = pd.DataFrame(
        data=v,
        columns=k[0],
        )

print(df)
#    a  b  c
# 0  0  1  2
# 1  3  4  5

中身の辞書のキーが異なる

リストの中身が辞書でキーが異なるデータとは、以下のようなデータです。片方はa, b, cがキーで、もう片方はa, b, dがキーとなっています。この場合は変換後のDataFrameのカラムがa, b, c, dになることが正解となります。

l = [{'a': 0, 'b': 1, 'c': 2}, {'a': 3, 'b': 4, 'd': 6}]

このようなデータの場合は、リストの要素ごとにDataFrameに変換して、pd.concat()で縦方向につなげていくとDataFrameを作成できます。

l = [{'a': 0, 'b': 1, 'c': 2}, {'a': 3, 'b': 4, 'd': 6}]

df = pd.DataFrame()
for x in l:
    df_add = pd.DataFrame(
                data=[x.values()],
                columns=x.keys(),
                )
    df = pd.concat([df, df_add], axis='index')

# Indexの通し番号をリセットする。
df = df.reset_index(drop=True)

print(df)
#    a  b    c    d
# 0  0  1  2.0  NaN
# 1  3  4  NaN  6.0