93388


〇実行環境  
Windows 10  
Python 3.X  
pandas

こちらのリンクでの質問内容の続きになります。  
[pandasでの特定の条件下でのデータ取得ができない。](https://ja.stackoverflow.com/questions/93032/pandas%E3%81%A7%E3%81%AE%E7%89%B9%E5%AE%9A%E3%81%AE%E6%9D%A1%E4%BB%B6%E4%B8%8B%E3%81%A7%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%96%E5%BE%97%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84)  
〇リンク先の質問  
上記のリンクではpandasを使用して各idがカラムのどの「分類」に属しているかの質問をし、groupbyを使用して、各idごとの分類と数値を取得することができました。

〇質問内容  
上記の質問から次のようなdfxを取得することができました。

〇dfx(区切りが見やすいよう、csv形式にしています。）

[code]

    id,数値,分類
    aaa,3141,type2
    bbb,5926,type1
    ccc,5358,type3
    ddd,9793,type1
    eee,2384,type3
    fff,6264,type2
    ggg,3383,type2
    hhh,2795,type1
    iii, 288,type3
    jjj,4197,type1
    kkk,1693,type3
    lll,9937,type2
    mmm,5105,type2
    nnn,8209,type1
    
[/code]

このデータからカラム「分類」の三つの要素ごとに最大値、最小値を求めたいと考え、以下のコードを実行しました。

[code]

    dfx_max_min = dfx.groupby('分類').agg(['max','min'])
    print(dfx_max_min)
    
[/code]

print結果を確認しますと、以下のようなデータが取得できました。  
id、数値ともにそれぞれの分類の最大値最小値を取得しました。

[code]

            id         数値
           max  min   max   min
    分類
    type1  nnn  hhh  9793  2795
    type2  mmm  aaa  9937  3141
    type3  kkk  ccc  5358   288
    
    
[/code]

今回私は数値が最大、最小の時のidを最大、最小としてdfとして作成しなおしたいと考えております。  
type1の最大値9793の時のidはdddですのでtype1のidの最大値はdddになります。

〇成形したいデータ

[code]

            id         数値
           max  min   max   min
    分類
    type1  ddd  bbb  9793  2795
    type2  lll  aaa  9937  3141
    type3  ccc  iii  5358   288
    
    
[/code]

今回のようなデータ成形を行う場合pandasでどういった書き方ができますでしょうか？


CC BY-SA 4.0
2023-01-16T12:29:44.510
93384
2023-01-22T17:09:25.353
47546
question
python pandas
最大値、最小値の時のidを求めたい。


多少 結果の順序が異なります

**Update** (前とあまり変わらないが, とりあえず `agg` 使用してみた)

[code]

    def fn(sdf):
        df = pd.concat([dfx.loc[dfx['数値'] == v, ['id', '数値']].iloc[0]
                for v in sdf['数値'].agg(['max', 'min'])])
        df.index = pd.MultiIndex.from_product([('max', 'min'), ('id', '数値')])
        return df
    
    dfx.groupby('分類').apply(fn)
    
    #       max         min
    #       id  数値      id  数値
    # 分類                
    # type1 ddd 9793    hhh 2795
    # type2 lll 9937    aaa 3141
    # type3 ccc 5358    iii 288
    
[/code]

* * *

### 追記

> 今回のようなデータ成形を行う場合pandasでどういった書き方ができますでしょうか？

`agg()` を利用する場合, 最大値・最小値であればともかく, 平均では idを出しようもなく,
また最大・最小が複数のときも項目を選択する必要があります  
どちらかというと(このような整形は)ムリに出してる感じ

「成形したいデータ」の形式とは異なるけれど  
pandasでどういった書き方ができるか, と捉えるなら以下のようにもできます  
(該当する id も分かりやすいはず)

[code]

    (dfx.style
        .highlight_max(props='color:white;background-color:darkblue;', subset=idx[dfx['分類'] == 'type1', '数値'])
        .highlight_max(props='color:white;background-color:pink;',     subset=idx[dfx['分類'] == 'type2', '数値'])
        .highlight_max(props='color:white;background-color:purple;',   subset=idx[dfx['分類'] == 'type3', '数値'])
    )
    
[/code]

以下は colabでの結果  
(markdownで色指定できなかったので画像で)

[![最大値を
typeごとに色分け](https://i.stack.imgur.com/UABgj.png)](https://i.stack.imgur.com/UABgj.png)

**update**  
さらに別解。(色付けの表現の回答もありだと判断して)

分類ごとの 最大値と最小値と, それに平均未満のデータの色分け  
平均未満は少し薄めの文字色にしてるけど見えづらいようならすみません

[code]

    def highlight(s, maxprops='', minprops='', meanprops=''):
        grouped = s.groupby(level=1)
        return np.select([
            s == grouped.transform('max'),
            s == grouped.transform('min'),
            s <  grouped.transform('mean'),
            ], [maxprops, minprops, meanprops], default='')
    
    df = dfx.set_index('分類', append=True)
    df.style.apply(highlight, maxprops='background-color:pink;',
                              minprops='background-color:yellow',
                              meanprops='color:darkgray',
                   subset='数値')
    
[/code]

[![最大値と最小値と平均未満](https://i.stack.imgur.com/V0Nwp.png)](https://i.stack.imgur.com/V0Nwp.png)


CC BY-SA 4.0
2023-01-16T14:45:59.800
93388
2023-01-22T17:09:25.353
2023-01-22T17:09:25.353
43025
43025
93384
answer

[code]

    midx = pd.MultiIndex.from_product([['max', 'min'], dfx.columns[:2]])
    dfx_max_min = dfx.groupby('分類')['数値'].agg(['idxmax', 'idxmin'])\
                     .apply(lambda x: dfx.loc[x, dfx.columns[:2]].stack().set_axis(midx), axis=1)\
                     .swaplevel(axis=1).sort_index(axis=1, level=0)
    
    print(dfx_max_min)
    
    #         id       数値      
    #        max  min   max   min
    # 分類                       
    # type1  ddd  hhh  9793  2795
    # type2  lll  aaa  9937  3141
    # type3  ccc  iii  5358   288
    
[/code]


CC BY-SA 4.0
2023-01-16T14:56:42.680
93389
2023-01-16T14:56:42.680
47127
93384
answer