pandas.DataFrameに値を代入するとしばしばこういう警告が出てくる→
C:\anaconda\lib\site-packages\ipykernel_launcher.py:3: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
「(参照ではなく)コピーしたものに値を代入してるよ。元のDataFrameは変更されないけど大丈夫?」ということ。
例えば以下のように.locで1行とって代入すると、.locの時点でコピーが返るのでrowは変更されるが元のDataFrameは変更されない:
df = pd.DataFrame({
"string": ["aaa", "bbb", "ccc"],
"integer": [1, 2, 3]})
row = df.loc[0]
row["string"] = "hoge"
# コピーは変更される
print(row)
# string hoge
# string2 ddd
# Name: 0, dtype: object
# コピー元は変更されない
print(df)
# string string2
# 0 aaa ddd
# 1 bbb eee
# 2 ccc fff
よく使うテクニックとして、これを避けたければ次のよう1行で書けば良い:
df.loc[0, "string"] = "hoge"
print(df)
# string integer1
# 0 hoge 1
# 1 bbb 2
# 2 ccc 3
しかしながら、次のように全ての列が同じデータ型を持つ場合挙動が異なる。すなわち、.locは参照を返すので、rowの変更がDataFrameに反映される:
import pandas as pd
df = pd.DataFrame({"string": ["aaa", "bbb", "ccc"], "string2": ["ddd", "eee", "fff"]})
row = df.loc[0]
row["string"] = "hoge"
# 参照先が変更される
print(row)
# string hoge
# string2 ddd
# Name: 0, dtype: object
# 参照元も変更される!
print(df)
# string string2
# 0 hoge ddd
# 1 bbb eee
# 2 ccc fff
理由は分からないが、効率性を求めた結果苦肉の策でこういう仕様にしたような感じがしておもしろい。
.locだけでなく、.iterrows()や.valuesなども以下のように同様の挙動を示す。
- 型がそろっていないとコピーが返り、DataFrameは変更されない:
df = pd.DataFrame({
"string": ["aaa", "bbb", "ccc"],
"integer": [1, 2, 3]})
# iterrows: 2行目のbbbをhogeに変更
for i, row in df.iterrows():
if i==1:
row[0] = "hoge"
# 1行目のaaaをbarに変更
val = df.values
val[0,0] = "bar"
# -> コピー元は変更されない
print(df)
# string integer1
# 0 aaa 1
# 1 bbb 2
# 2 ccc 3
- 型がそろっていれば参照が返り、DataFrameは変更される:
df = pd.DataFrame({
"string": ["aaa", "bbb", "ccc"],
"string2": ["ddd", "eee", "fff"]})
# iterrows: 2行目のbbbをhogeに変更
for i, row in df.iterrows():
if i==1:
row[0] = "hoge"
# values: 1行目のaaaをbarに変更
val = df.values
val[0,0] = "bar"
# -> 参照元は変更される
print(df)
# string string2
# 0 bar ddd
# 1 hoge eee
# 2 ccc fff
これくらいの小さい例だとあまり怖さはないが、データフレームにあとから列を足して型の統一が崩れたりすると、それまで参照が返ると思い込んでいたところにコピーが返ってくるようになって見つけにくいバグになる。
「基本はコピー、型が揃っているときだけ参照が返る」という話でした。
参考:
https://stackoverflow.com/questions/47972633/in-pandas-does-iloc-method-give-a-copy-or-view