nikkie-ftnextの日記

イベントレポートや読書メモを発信

pandasのDataFrameのlocインデクサは行、列の順で絞り込む(例:df.loc[df["b"]>12, "a"])

はじめに

いくおです。 nikkieです。

Today(※最近) I learned です。

目次

動作環境

% uv version
uv 0.4.27 (Homebrew 2024-10-25)
% uv run --python 3.12 --with pandas python
>>> import pandas as pd
>>> pd.__version__
'2.2.3'

[]を2回使って行と列を指定するも、そこに代入できていない

DataFrameを作ります

>>> df = pd.DataFrame({"a": [11, 21, 31], "b": [12, 22, 32], "c": [13, 23, 33]})
>>> df
    a   b   c
0  11  12  13
1  21  22  23
2  31  32  33

b列が12より大きい行(すなわち、インデックスが1と2の行)を取り出すと

>>> df[df["b"]>12]
    a   b   c
1  21  22  23
2  31  32  33

そのa列は

>>> df[df["b"]>12]["a"]
1    21
2    31
Name: a, dtype: int64

以上から、b列が12より大きい行のa列の値を書き換えようとすると

>>> df[df["b"]>12]["a"] = 99
<stdin>:1: 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

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

例外が送出されたわけではないですが、dfは変わっていません(dfのコピーでだけa列の値が変わったのかな?)

>>> df
    a   b   c
0  11  12  13
1  21  22  23
2  31  32  33

locを使ってアクセス・代入してみる

警告で案内された.loc[row_indexer,col_indexer]を試します1
今回理解したのは、.loc[行を絞る,列を絞る] ということです。

b列が12より大きい行

>>> df.loc[df["b"]>12]
    a   b   c
1  21  22  23
2  31  32  33

b列が12より大きい行のa列

>>> df.loc[df["b"]>12, "a"]
1    21
2    31
Name: a, dtype: int64

書き換えられます!!

>>> df.loc[df["b"]>12, "a"] = 99
>>> df
    a   b   c
0  11  12  13
1  99  22  23
2  99  32  33

『pandasクックブック』にあたる

古い本ですが、手元の『pandasクックブック』よりdf.loc[rows, columns]という書式について

カンマの左側の選択は、行インデックスによる行選択、カンマの右側は常にカラムインデックスによるカラム選択だ。(p.79)

またクックブックでは、

  • df[]をインデックス演算子
  • df.loc[].locインデクサ

と呼んでいました (p.73)

終わりに

pandasのDataFrameでlocインデクサは行->列の順で絞れる(df.loc[rows, columns])ことを理解しました。
今回の例では、df["b"]>12行を絞り、それらの列を"a"で指定しました。
インデックス演算子で指定して値を代入したところ元が書き換わりませんでしたが、locインデクサを使うと書き換えられました!

pandasを知ってからlocインデクサは自分のものにできていない感じでしたが、今回で完全に理解しました!