DataFrameのコピー方法による挙動の違いを確認してみる(=, copy(), copy(deep=False)

# 目的
DataFrameのコピーに関して仕様が理解できていない部分があったので、改めてまとめてみる。

# ライブラリ
| 項目 | 情報 |
| ---- | ---- |
| pandas | 1.5.3 |

# 動作確認
## 事前準備
ライブラリのimportとサンプルのDataFrameを作成する関数を定義しておく。

### ソースコード
``` python
import pandas as pd

def create_sample_df():
    df = pd.DataFrame({
        'col_1': ['A', 'B', 'C'],
        'col_2': ['I', 'J', 'K'],
        'col_3': ['X', 'Y', 'Z']
    })
    
    return df

display(create_sample_df())
```

### 出力
|   | col_1 | col_2 | col_3 |
|---|-------|-------|-------|
| 0 | A     | I     | X     |
| 1 | B     | J     | Y     |
| 2 | C     | K     | Z     |

## `=`でコピーする
- `=`でコピーすると、参照渡しとなる
- コピー先のdfに変更を加えると、コピー元のdfにも変更が反映される

### ソースコード
``` python
df = create_sample_df()

df_copy = df

# 追加
df_copy['col_4'] = 'add'
df_copy.loc[3] = 'add'

# 更新
df_copy['col_2'] = 'update'
df_copy.loc[1] = 'update'
df_copy.loc[0, 'col_1'] = 'update'

# 削除
df_copy.drop('col_3', axis=1, inplace=True)
df_copy.drop(2, inplace=True)

# コピー先のDF
display(df_copy)

# コピー元のDF
display(df)
```

### 出力
コピー先
|   | col_1 | col_2 | col_4 |
|---|-------|-------|-------|
| 0 | update| update| add   |
| 1 | update| update| update|
| 3 | add   | update| add   |

コピー元
|   | col_1 | col_2 | col_4 |
|---|-------|-------|-------|
| 0 | update| update| add   |
| 1 | update| update| update|
| 3 | add   | update| add   |

## `DataFrame.copy`でコピーする(デフォルト)
- `DataFrame.copy`でコピーすると、値渡しとなる(deep copy)
- コピー先のdfに変更を加えても、コピー元のdfには変更が反映されない

### ソースコード
``` python
df = create_sample_df()

df_copy = df.copy()

# 追加
df_copy['col_4'] = 'add'
df_copy.loc[3] = 'add'

# 更新
df_copy['col_2'] = 'update'
df_copy.loc[1] = 'update'
df_copy.loc[0, 'col_1'] = 'update'

# 削除
df_copy.drop('col_3', axis=1, inplace=True)
df_copy.drop(2, inplace=True)

# コピー先のDF
display(df_copy)

# コピー元のDF
display(df)
```

### 出力
コピー先
|   | col_1 | col_2 | col_4 |
|---|-------|-------|-------|
| 0 | update| update| add   |
| 1 | update| update| update|
| 3 | add   | update| add   |

コピー元
|   | col_1 | col_2 | col_3 |
|---|-------|-------|-------|
| 0 | A     | I     | X     |
| 1 | B     | J     | Y     |
| 2 | C     | K     | Z     |

## `DataFrame.copy`でコピーする(deep=False)
- `DataFrame.copy`の`deep`パラメータを`False`にすると、shallow copyとなる
- 値の更新はコピー元のdfにも反映される
- メタデータの変更(列の追加や削除)を行ってもコピー元のdfには反映されない
- メタデータの変更を加えると、値の更新も反映されなくなる

※このあたりの理解が浅いので、もし理解が誤っていたらコメントで指摘いただけますと幸いです。

### ソースコード
``` python
df = create_sample_df()

df_copy = df.copy(deep=False)

# 更新(初回)
df_copy.loc[0, 'col_1'] = 'update1'

# 追加
df_copy['col_4'] = 'add'
df_copy.loc[3] = 'add'

# 更新2回目
df_copy['col_2'] = 'update'
df_copy.loc[1] = 'update'
df_copy.loc[0, 'col_1'] = 'update2'

# 削除
df_copy.drop('col_3', axis=1, inplace=True)
df_copy.drop(2, inplace=True)

# コピー先のDF
display(df_copy)

# コピー元のDF
display(df)
```

### 出力
コピー先
|   | col_1  | col_2 | col_4 |
|---|--------|-------|-------|
| 0 | update2| update| add   |
| 1 | update | update| update|
| 3 | add    | update| add   |


コピー元
|   | col_1  | col_2 | col_3 |
|---|--------|-------|-------|
| 0 | update1| I     | X     |
| 1 | B      | J     | Y     |
| 2 | C      | K     | Z     |



# 参考
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.copy.html

https://qiita.com/analytics-hiro/items/e8fdf8652869817851cd