知りたいのです、pandasで、ある列の最大値の行でグループを代表させる方法を

## はじめに
pandasを触り始めました。
groupごとにmaxを求める上で気になったことがあったので手を動かして調べてみました。

(2018/01/28)もくもく会で質問した内容をもとに暫定解をアップデートしました。
今後は[atsushi_bgさんからいただいたコメント](https://qiita.com/ftnext/items/48b7baa49217fdc37ae4#comment-8f7d0214dd2abdc18977)をもとにアップデートします。

## やりたいこと
データを列Aでグループ化し、各グループを列Bの最大値の行で代表させたい。

例えば、`select_max_sample-3.csv`として保存された以下のようなデータ[^1]を
config_idでグループ化し、各グループはsalesdateの最大値（最新値）の行で代表させたい。

|id|no|config_id|salesdate|
|:--|:--|:--|:--|
|1|1|1|2011-11-12|
|2|3|3|2011-12-03|
|3|2|1|2012-02-10|
|4|1|2|2012-01-04|
|5|2|3|2012-06-03|
|6|1|3|2011-08-04|

以下の結果がほしいわけです。

|id|no|config_id|salesdate|
|:--|:--|:--|:--|
|3|2|1|2012-02-10|
|4|1|2|2012-01-04|
|5|2|3|2012-06-03|

## 暫定解(2018/01/28更新)

```python:
import pandas as pd
df3 = pd.read_csv('select_max_sample-3.csv', sep=',', header=0, index_col=None)
salesdate_max = df3.groupby('config_id').max()['salesdate']
pd.DataFrame([df3[(df3['config_id'] == i) & (df3['salesdate'] == salesdate_max[i])].values[0] for i in range(1, len(salesdate_max)+1)], columns=df3.columns)
```

## 暫定解の動き

`salesdate_max`は`config_id`のグループごとの`salesdate`の最大値を格納したSeries。
`salesdate_max`の各要素にはfor文でアクセス可能。

`df3[(df3['config_id'] == i) & (df3['salesdate'] == salesdate_max[i])`では
`config_id`が`i`でかつ、`config_id`が`i`のグループの`salesdate`に`salesdate`が等しい行が`df3`から抽出される。
抽出結果のうちの1番目にアクセスし、それをリストに集める。
`i`が`3`のときは`array([5, 2, 3, '2012-06-03'], dtype=object)`がリストに入る。

リストをもとにDataFrameを作成する。作成時に、`df3`と同じカラム名を設定する。

## 私の解答

```python:
import pandas as pd
df3 = pd.read_csv('select_max_sample-3.csv', sep=',', header=0, index_col=None)
df3_configid_group = df3.groupby('config_id')

max_by_group = []
for i in range(1, 4):
    max_by_group.append(df3[(df3['config_id']==i) & (df3['salesdate']==df3_configid_group['salesdate'].max().loc[i])])
pd.concat(max_by_group)
```

抽出条件が複雑になってしまっているんですよね。。
`config_id`の最大値に合わせてfor文の`range`を書き直す必要があるのでいけていません。
（抽出条件についてはもっといい書き方が見つかったら更新します。改善案をコメントいただけると大変嬉しいです）

## 私の解答の動き

`df3[(df3['config_id']==i) & (df3['salesdate']==df3_configid_group['salesdate'].max().loc[i])]`について：
例えば、`i=3`で考えると、`config_id`が`3`の`df3`の行で、かつ、
`config_id`が`3`のレコードの中の最大の`salesdate`に`salesdate`が等しい`df3`の行を取り出しています。

`df3_configid_group['salesdate'].max()`は`config_id`ごとの最大の`salesdate`を返します。（＊）

```
config_id
1    2012-02-10
2    2012-01-04
3    2012-06-03
Name: salesdate, dtype: object
```

（＊）から`config_id`ごとに`salesdate`の最大値を取り出すため、`config_id`を逐次`loc`で指定しました。

こうして`config_id`ごとに取得した`salesdate`が最大となる`df3`の行を`concat`で一つにまとめています。

## 単にmaxを使わなかった理由

maxはidの最大値、noの最大値、salesdateの最大値からなる行を新たに作って返すため。

```python:
df3_max_salesdate1 = df3_configid_group.max()
df3_max_salesdate1.head()
```

これを実行すると次のような出力となります。（太字箇所に注目）

|id|no|config_id|salesdate|
|:--|:--|:--|:--|
|3|2|1|2012-02-10|
|4|1|2|2012-01-04|
|**6**|**3**|3|2012-06-03|

maxは以下のような動きと理解しました。[^2]（`config_id=3`の例）

<img width="327" alt="pandas_max動作_20180127.png" src="https://qiita-image-store.s3.amazonaws.com/0/82132/a93d3717-a837-bdae-9c9f-262e744aa3b2.png">


## 動作環境

- Python 3.5.1
- `pip install pandas jupyter`を実行し、`pandas==0.22.0`、`jupyter==1.0.0`をインストール

## 脚注
[^1]: このデータは[order byでハマったこと -order by、group byの処理順序-](http://pplace.jp/2012/03/613/)を参考にしました。
[^2]: [「groupby の初歩と python（DataFrame）によるサンプル」というサイトの "max を適用すると"](http://ailaby.com/groupby_easy/#id1_3)が参考になりました。