`iloc`について教えてください。

`for i in range(len(predict_data)):` とした場合、`i` に入るのは整数なので、`.iloc[i]`
とすべきだと思ったのですが、解答では `iloc` を使わず、下記のようになっておりました。  
なぜ、`iloc` 省略なのでしょうか。  
できれば初学者用に分かりやすく教えていただけると幸いです。  
よろしくお願いいたします。

```

    for i in range(len(predict_data)):
    　　    delta = relativedelta(predict_data["now_date"][i], predict_data["start_date"][i])
    
```
CC BY-SA 4.0
2022-10-08T06:47:59.807
91496
2022-10-11T07:46:29.383
2022-10-08T08:11:16.380
3060
54758
question
python python3 pandas
relativedelta使用時のilocについて
質問のやり方は行番号では無く「インデックス値」によるアクセスです。  
インデックス値が`0からの連番`で付加されているため、行番号で行を指定したのと同等の処理になった訳です。

pandasのドキュメントでは以下に記述されています。  
[Indexing and selecting
data](https://pandas.pydata.org/docs/user_guide/indexing.html)

> **Note**  
>  The Python and NumPy indexing operators`[]`and attribute operator`.`provide
> quick and easy access to pandas data structures across a wide range of use
> cases.

[Basics](https://pandas.pydata.org/docs/user_guide/indexing.html#basics)

> the primary function of indexing with`[]`(a.k.a.`__getitem__`for those
> familiar with implementing class behavior in Python) is selecting out lower-
> dimensional slices.
>
> **Object Type** | **Selection** | **Return Value Type**  
> ---|---|---  
> Series | `series[label]` | scalar value  
> DataFrame | `frame[colname]` | `Series` corresponding to colname  
  
こんな日本語の解説記事もあります。  
[インデックスに基づく選択 - pandas – Series のインデックス操作まとめ](https://pystyle.info/pandas-
indexing-series/#outline__4_1)

* * *

質問の出展はこちらだと思われますが  
[Python実践データ分析100本ノック
（単行本）](https://www.shuwasystem.co.jp/book/9784798058757.html)

> 第4章 顧客の行動を予測する10本 ノック  
>  ノック37：特徴となる変数を付与しよう  
>  [サンプルファイルのダウンロード -
> Python実践データ分析100本ノック](https://www.shuwasystem.co.jp/support/7980html/5875.html)

他に多数の人が記事を書いていて例えばこんな解説があります  
[【Python実践データ分析100本ノック】ノック36－40](https://minarai-engi.com/python-
analytics100knock-8/)

質問の行近辺の`predict_data.head()`の結果や、直前の`predict_data["period"]=None`が実行された時点で単に`predict_data["now_date"]`とか`predict_data["start_date"]`として内容を表示してみれば分かりますが、各データには`0`～`15112`という`数値(整数)によるインデックス`が付いています。

```

    >>> predict_data.head()
           年月 customer_id  count_pred  count_0  count_1  count_2  count_3  count_4  count_5
    0  201810    AS002855           3      7.0      3.0      5.0      5.0      5.0      4.0
    1  201810    AS009373           5      6.0      6.0      7.0      4.0      4.0      3.0
    2  201810    AS015315           4      7.0      3.0      6.0      3.0      3.0      6.0
    3  201810    AS015739           5      6.0      5.0      8.0      6.0      5.0      7.0
    4  201810    AS019860           7      5.0      7.0      4.0      6.0      8.0      6.0
    ...
    >>> predict_data['now_date']
    0       2018-10-01
    1       2018-10-01
    2       2018-10-01
    3       2018-10-01
    4       2018-10-01
               ...
    15108   2019-03-01
    15109   2019-03-01
    15110   2019-03-01
    15111   2019-03-01
    15112   2019-03-01
    Name: now_date, Length: 15113, dtype: datetime64[ns]
    ...
    >>> predict_data['start_date']
    0       2016-11-01
    1       2015-11-01
    2       2015-07-01
    3       2017-06-01
    4       2017-10-01
               ...
    15108   2015-09-01
    15109   2018-09-01
    15110   2016-06-01
    15111   2017-03-01
    15112   2017-04-01
    Name: start_date, Length: 15113, dtype: datetime64[ns]
    
```

なので、`predict_data["now_date"][i]`とか`predict_data["start_date"][i]`とすると、各Seriesデータ中の`iの数値をインデックス値に持つデータ`にアクセス出来ることになります。
CC BY-SA 4.0
2022-10-09T23:52:50.540
91519
2022-10-10T00:33:01.017
2022-10-10T00:33:01.017
26370
26370
91496
answer
元データが `DataFrame` (2次元)だった場合, その中から一つの項目を取り出すには

  * 行(ROW)・列(COLUMN) を同時に指定する
  * あるいは 一つずつ指定することができる  
一つずつの場合にも どの軸を先に指定するかで(当然)指定方法が異なる

    * `df[COLUMN][ROW]`
    * `df.loc[ROW][COLUMN]`

`df[カラム名][n]` のような指定では, カラム名にて 1列分 `Series` を取り出しその中から `[n]`で項目を取り出す手順  
(複数続けるので) chained indexing とも呼ばれる  
`[n]` の指定は, `DataFrame`に対するものではなく **途中** 結果の `Series` に対する指定  
(なので `loc` / `iloc` は必要ない)

#### chained indexing

chained indexing は(理解して使う分にはよいが) 問題点もある

  * 内部でコピーが発生する可能性がある (ので微妙に遅くなるかも知れない)
  * 暗黙の型変換が発生する場合がある (誤差が生じる場合がある)
  * 新しい値の代入時に 想定外の結果になる可能性がある

以下の例は, 複数(3種類)の型のデータが `df.iloc[1]` で `object` 型に纏められた様子  
(コピーが発生したはずで, (型変換で)誤差も発生するかも知れない)

```

    import pandas as pd
    import numpy as np
    import io
    csv = io.StringIO('''
    idx,日付,整数値項目,少数点数項目
    A,2022-10-1,100,3.2
    B,2022-10-2,200,0.1
    C,2022-10-3,100,
    D,2022-10-4,100,1.2
    ''')
    df = pd.read_csv(csv, index_col=0, parse_dates=[1])
    print(df.dtypes)
    # 日付        datetime64[ns]
    # 整数値項目              int64
    # 少数点数項目           float64
    # dtype: object
    
    df.iloc[1]
    # 日付        2022-10-02 00:00:00
    # 整数値項目                     200
    # 少数点数項目                    0.1
    # Name: B, dtype: object
    
```

… なので, `df.loc[ROW][COLUMN]` の chained indexing は(データにもよるが) **避けたほうがよい**  
(`df['整数値項目']` のような指定であれば, `int64` のまま, 変換は行われない)

* * *

#### 行・列を同時に指定

ちなみに  
2次元 (matrix あるいは DataFrame) から値を取り出す場合, 以下の方法があります  
(どちらかの軸 片方が番号の場合, `.index`, `.columns` など利用して変換するとよいでしょう)

＼ | ラベルで指定 | 番号で位置指定 | 備考  
---|---|---|---  
単独(single value)および  
複数の要素の値 | [`loc`](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.loc.html) |
[`iloc`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html)
| 行だけの指定の場合 行を取り出す  
単独(single value)の要素の値 | [`at`](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.at.html) |
[`iat`](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.iat.html) |  
  
Table: `DataFrame`の場合 (`Series`の同名メソッドは 別ページ)
CC BY-SA 4.0
2022-10-10T06:32:51.100
91525
2022-10-11T07:46:29.383
2022-10-11T07:46:29.383
43025
43025
91496
answer