Tech カテゴリのイメージ

ValueError: If using all scalar values, you must pass an index の原因と直し方[pandas]

辞書からDataFrameを作ろうとしてこれが出ることがある。

ValueError: If using all scalar values, you must pass an index

再現はとても簡単になる。

import pandas as pd
df = pd.DataFrame({"name": "田中", "age": 30}) # ValueError

なぜ怒られるのか

pd.DataFrameに辞書を渡すと、キーが列名、値がその列の中身として解釈される。値がリストなら、その長さが行数になる。

pd.DataFrame({"name": ["田中", "佐藤"], "age": [30, 25]})
# 2行の表ができる

ところが値がスカラー(文字列や数値そのもの)だと、pandasは行数を決められない。1行なのか、100行に同じ値を並べるのか判断がつかない。だから「全部スカラーなら、行数を決めるindexを渡してほしい」と言ってくる。

つまり足りないのは行数の情報になる。

直し方1. リストで包む(推奨)

いちばん素直な方法になる。1行のDataFrameを作りたいなら、各値をリストに入れる。

df = pd.DataFrame({"name": ["田中"], "age": [30]})

長さが揃っていれば何行でも作れる。ここで長さが違うと別のエラーになるので、揃えておく。

直し方2. 辞書をリストに入れる

1行ぶんの辞書として渡す書き方もある。こちらのほうが意味が読みやすいことが多い。

df = pd.DataFrame([{"name": "田中", "age": 30}])

この形は複数行への拡張が自然になる。

rows = [
{"name": "田中", "age": 30},
{"name": "佐藤", "age": 25},
]
df = pd.DataFrame(rows)

APIのレスポンスやDBの取得結果を貯めていく処理では、この形がいちばん扱いやすい。キーが揃っていない行があっても、無い列は欠損として埋めてくれる。

直し方3. indexを渡す

エラーメッセージが言っているとおりの対処になる。

df = pd.DataFrame({"name": "田中", "age": 30}, index=[0])

行数はindexの長さで決まるので、同じ値を複数行に並べることもできる。

df = pd.DataFrame({"name": "田中", "age": 30}, index=[0, 1, 2])
# 同じ内容が3行できる

直し方4. from_dictを使う

キーを行にしたい場合はfrom_dictが便利になる。

d = {"田中": 30, "佐藤": 25}
df = pd.DataFrame.from_dict(d, orient="index", columns=["age"])

orient="index"で辞書のキーが行のラベルになる。既定のorient="columns"はキーが列名になるので、目的に応じて選ぶ。

直し方5. Seriesにする

そもそも1次元でよければ、DataFrameである必要はない。

s = pd.Series({"name": "田中", "age": 30})

集計結果を1件だけ持ちたいときは、Seriesのほうが素直なことが多い。あとからto_frame().Tで1行のDataFrameにもできる。

df = s.to_frame().T

混在しているときの注意

スカラーとリストが混ざっている場合は、このエラーは出ない。スカラーのほうがリストの長さに合わせて自動で複製される。

pd.DataFrame({"name": ["田中", "佐藤"], "dept": "営業"})
# dept は2行とも「営業」になる

これは便利だが、意図しない複製が起きることもある。1件だけのつもりが、別の列の長さに引きずられて増えることがあるので、作ったあとにshapeを確認しておくと安心になる。

print(df.shape)

ループで溜めるときの定石

1件ずつconcatappendでつなぐのは遅いので、リストに溜めて最後に一度だけDataFrameにする書き方が定石になる。

rows = []
for item in items:
rows.append({"id": item.id, "name": item.name})
df = pd.DataFrame(rows)

この形なら、そもそも今回のエラーに出会わない。行数はリストの長さで自然に決まる。

なおDataFrame.appendはすでに廃止されているので、古い記事を参考にしている場合は注意したい。詳細はpandasのappendが使えなくなった話に書いた。

📘 DataFrameの組み立て方を実戦の文脈で学ぶなら、Kaggleで勝つデータ分析の技術

まとめ

・値が全部スカラーだと行数が決まらないので、pandasがindexを要求している
・1行なら各値をリストで包むか、辞書自体をリストに入れる
index=[0]を渡す方法もある。indexの長さぶん同じ内容が並ぶ
・キーを行にしたいならfrom_dict(orient="index")
・スカラーとリストが混ざるとスカラーが自動複製される。作成後にshapeを確認する
・ループで溜めるときはリストに貯めて最後に一度だけDataFrame化するのが速くて安全

※本記事にはアフィリエイト広告を含みます。