http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html
- 演算子[]と.は便利だが最適化されたものではないので、productionでは別のものを使うべき
- set演算に伴い参照とコピーのどちらが返るかは文脈に依存する。chained assignment と呼ばれるもので避けるべき。 詳しくはhttp://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-view-versus-copy
- float型によるindexingについてはversion 0.18.0に定義された。
- .loc operator: 基本はlabelつまり文字列の指定を通してslicingする。整数を指定してもラベルとして用いられる。booleanや1引数のfunctionも受け付ける。
- .iloc operator: 基本は整数値を指定してslicingする。
- [] operator: 一応使えることになってはいるが、推奨ではないのでは???
多軸を持つオブジェクトに対するindexingによるデータ取得は、実質的に各軸すべてに対してindexingを行う必要がある。 何も書かない軸はすべてを対象としていることになり、null sliceである:を指定していることになる。
| Object Type | Indexers |
|---|---|
| Series | s.loc[indexer] |
| DataFrame | df.loc[row_indexer,column_indexer] |
| Panel | p.loc[item_indexer,major_indexer,minor_indexer] |
- ひとつのindexingで代入する。data[1][3] = "hoge"みたいなのはchained assignmentになってwarningがでる。 そしてdata.iloc[1,3]の値は更新されない...いつコピーが発生したのか...
- 次のようなものも結局複数回indexingして設定しているのでchained assignmentになる
x = data[:5]
x[3] = "fuga"
でwarningが出る。
-
仕様確認のためのサンプルコード
-
初期設定
x = pd.DataFrame(columns=["A","B"], data=np.transpose(np.array([[1,2,3],[4,5,6]])))
y = x[:2]
print(x)
print(y)
print(x.is_copy is not None, y.is_copy is not None)
print("x[:1][:2]", x[:1][:2])
print("x[:2][:3]", x[:2][:3])
print("x[:3][:2]", x[:3][:2])
print("x[:3][:3]", x[:3][:3])```
- 2段階のslicingで設定してみる
x[:3][1:2] = 100 print("x", x.is_copy, x[:3].is_copy, x[:3][2:3].is_copy, "\n", x)
これはxに100をセットできる。slicingによるアクセスであるためコピーされたデータフレームへのセットにならないようだ。
- 2段階目を個別要素指定にしてみる
x[:3][2] = 200 print("x", x.is_copy, x[:3].is_copy, "\n", x)
これはxは変化せずwarningが出る。x[:3]がコピーされたデータフレームを返しており、
その2番目(厳密には(2,:))の要素に200をセットする処理になる。xは変化しない。
- ilocを使って設定してみる
x.iloc[0,0] = 10 print("x",x) print("y",y)
x,yの変化を確認できる。素直に参照として扱っているので両方とも変化していることを確認できる。
- xのslicingであるyに対してilocで値を設定してみる
y.iloc[0,1] = 99 print("x", x) print("y", y)
これはwarningが出る。値はx,yの両方とも更新される。