1. 概要
pandas の concat
関数を使用していて、 InvalidIndexError: Reindexing only valid with uniquely valued Index objects
に出会したのだが、心当たりがなく、原因究明に時間を要したので記事にしておく。
2. 前提
item | version など |
---|---|
python | 3.10 |
pandas | 2.2.0 |
3. 発生原因
3-1. エラーにならないパターン
これは OK。
import pandas as pd
# サンプルのDataFrame
data = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]
},index=pd.RangeIndex(0, 3))
pd.concat([data, data], axis=0)
# 結果
A B C
0 1 4 7
1 2 5 8
2 3 6 9
0 1 4 7
1 2 5 8
2 3 6 9
エラーメッセージには Index
という文言が入っているが、 Index が重複していてもエラーにはならない。
そして、なんと驚くことに、単に列名が重複していている場合にもエラーにならない。
pd.concat([data, data], axis=1)
# 結果
A B C A B C
0 1 4 7 1 4 7
1 2 5 8 2 5 8
2 3 6 9 3 6 9
じゃあ何がエラー原因なんだい?
3-2. わかりやすいエラー原因
3-2-1. concat 前から Index 重複
元々 Index が1つ以上重複する DataFrame を axis=1
方向に concat しようとすると発生する。以下のような状況。
df1 = pd.DataFrame(
{"体重": [50.1, 69.3], "身長": [163.4, 178.1]},
index =["たじまさん", "Kevin"]
)
df2 = pd.DataFrame(
{"学歴": ["大卒", "大卒"], "総資産": [1e10, 1.2e12]},
index =["たじまさん", "たじまさん"] # concat 前から index 重複
)
pd.concat([df1, df2], axis=1)
# 結果
InvalidIndexError: Reindexing only valid with uniquely valued Index objects
どうやら、 concat で結合する前から index が重複しているとエラーになるらしい。
3-2-2. concat 前から columns 重複
元々 Columns が名1つ以上重複する DataFrame を axis=0
方向に concat しようとしてもエラーが発生する。以下のような状況。
サンプルデータを作るのが少し難しいが、以下のようなパターンがありうる。
df1 = pd.DataFrame(
{"体重": [50.1, 69.3], "身長": [163.4, 178.1]},
index =["たじまさん", "Kevin"]
)
df1
# 結果
体重 身長
たじまさん 50.1 163.4
Kevin 69.3 178.1
上の DataFrame はよくある形式。
一方、下のような DataFrame は、手を入れないと作れない。
seriesA = pd.Series([42.6, 48.5], name="体重")
seriesB = seriesA.copy()
df2 = pd.concat([seriesA, seriesB], axis=1)
df2.index = ["よこたさん", "Comet"]
df2
# 結果
体重 体重
よこたさん 42.6 42.6
Comet 48.5 48.5
こういうのを縦 (axis=0
) に concat するとエラーが出る。
pd.concat([df1, df2], axis=0)
# 結果
InvalidIndexError: Reindexing only valid with uniquely valued Index objects
ここまでは色々な記事に書かれているので、これが原因だったらすぐに気がつけると思う。
3-3. 見落としがちなパターン
ここからは、なかなか気がつきにくいパターン。
再度、同じ列名を含む DataFrame に登場してもらう。
seriesA = pd.Series([1, 2, 3], name='A')
seriesB = pd.Series([4, 5, 6], name='A')
df_A = pd.concat([seriesA, seriesA, seriesB], axis=1)
df_A
# 結果
A A A
0 1 1 4
1 2 2 5
2 3 3 6
実は、こういう DataFrame も、縦 (axis=0) 方向に結合できる。
pd.concat([df_A, df_A], axis=0)
# 結果
A A A
0 1 1 4
1 2 2 5
2 3 3 6
0 1 1 4
1 2 2 5
2 3 3 6
自分の場合はこうした上記のような処理を書いていた。
ところが、入力データの形式によって、たまたま、1列だけ列名が変わることがあった。
出来上がったデータはこんな感じ。
seriesA = pd.Series([1, 2, 3], name='A')
seriesC = pd.Series([7, 8, 9], name='C')
df_C = pd.concat([seriesA, seriesA, seriesC], axis=1)
df_C
# 結果
A A C
0 1 1 7
1 2 2 8
2 3 3 9
これを df_A と縦に concat したら、以下のようになりそうなのだけど、、、
A A A C
0 1 1 4 Nan
1 2 2 5 Nan
2 3 3 6 Nan
0 1 1 Nan 7
1 2 2 Nan 8
2 3 3 Nan 9
実際は InvalidIndexError になる。
pd.concat([df_A, df_C], axis=0)
# 結果
InvalidIndexError: Reindexing only valid with uniquely valued Index objects
4. 考察
要は、 「Reindexing (自動での Index や Columns 書き換え)」 が肝なのだろう。
- 「Reindexing」がなければ、 Index、 Columns が重複してようが問題ない
- 「Reindexing」が pandas 内で自動で実行されるときは、重複した Index や Columns を持ってきてはならない
ということだと思われる。
つまり、 Columns や Index の書き換えが発生せずに、元のままで結合後の DataFrame が作られる時は、エラーは発生しない。