hatunina’s blog

メモと日記です

pandasのSettingWithCopyWarningの対処法

事象

こんな感じのデータフレームがあった時

import pandas as pd

df = pd.DataFrame({'A': ['a', 'b', 'c', 'd', 'e'], 'B': [1, 1, 1, 2, 2]})

print(df)

# 実行結果
   A  B
0  a  1
1  b  1
2  c  1
3  d  2
4  e  2


列Bが1のとこだけ抽出して新しい列を追加したいな〜
えいや

df_2= df[df['B'] == 1]
df_2['C'] = 100

print(df_2)

# 実行結果
   A  B    C
0  a  1  100
1  b  1  100
2  c  1  100
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead


できた!が、
SettingWithCopyWarningというWarningが出てしまう。。。

原因

どうやらシャローコピーをいじっている時に出るらしい
参照のコピーなので参照先が変更された場合にコピー先も変更されちゃうからよくないよ!という警告

シャローコピー、ディープコピーについてはこちら

miningoo.com

対処

警告文通りに.locを使っても良いが今回の例のように列ごと変えたい場合は使えない。
ということでassignを使います。
assignは内部でcopyを使ってディープコピーを作るのでうまくやってくれます。
ただ、メモリを食うので大きいデータフレームを扱うときは要注意です。

pandas.DataFrame.assign — pandas 0.22.0 documentation

df_2 = df[df['B'] == 1]
df_2 = df_2.assign(C=100)

print(df_2)

# 実行結果
 A  B    C
0  a  1  100
1  b  1  100
2  c  1  100


警告が出ずに綺麗にできた!新しい列を追加したい時に便利!
場合によっては、lambda式が使えるのでさらに便利!