【Pandas】GroupByオブジェクトのループ処理について　no.27

![見出しを追加 (65).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/16a64dac-0f33-0f85-6a91-ebc24d441130.png)

こんにちは、まゆみです。

Pandasについてシリーズで記事を書いています。

今回は第27回目になります。

[前々回の記事](https://qiita.com/Mayumi_Pythonista/items/30bab64ba08fa216313e)と[前回の記事](https://qiita.com/Mayumi_Pythonista/items/711dc8623da30a16540f)でPandasの<font color="Red">GroupByオブジェクト</font>について記事を書いて来ました。


今回の記事では

<ul>
<li>グループ化されたGroupByオブジェクトにfor loop処理をするにはどうすればいいのか</li>
<li>どうしてそのようなコードになるかの理由</li>
</ul>

を書いていこうと思います。

ではさっそく始めていきますね。

#今回使うデータ

今回も前回に引き続き、[世界各地域別のゲームの売上高に関するデータ](https://www.kaggle.com/gregorut/videogamesales)を使っていきます

Genre(ジャンル)のコラムをグループ化しました。

下記がその結果になります。
![スクリーンショット 2021-04-02 083215.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/757bc597-685d-45bd-8d6c-84fa22a09229.jpeg)

グループ化されたオブジェクトを、genresという変数に代入しましたが、genreを表示させても、GroupByオブジェクトというオブジェクト名と、そのオブジェクトが保存されているロケーションしか表示されません。(下記参考)

![スクリーンショット 2021-04-02 084100.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/2489effc-c2ab-7625-8392-6e818db446a3.jpeg)

ですが、<font color="Red">コンピューターの裏側では、同じ値の物がまとめられています。</font>(下記参考)
![見出しを追加 (62).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/b43dd8e7-f0e9-243c-675d-f577bbd59630.png)

では、このGroupByオブジェクトを使って、

各ジャンルごとの日本での売り上げがトップの物を取り出してみましょう

#.max()メソッドでは、最大値は取り出せるがDataFrame全体が表示されない

最大値を取り出すと言って、真っ先に思いつくのは.max()メソッドと思います

![スクリーンショット 2021-04-02 084507.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/b1d4864c-606c-96dd-a54a-1bb954db6c88.jpeg)

ただ、.max()メソッドだと、最大値自体は表示させることができますが、<font color="Red">DataFrameとしては表示する事ができません。</font>


そこで、

GroupByオブジェクトに対して<font color="Red">for loop を使う</font>

ことで、その問題を解決する事ができます

#GroupByオブジェクトをループ処理する

![見出しを追加 (63).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/d8f12d8b-db90-e8e5-d90d-998654758cf5.png)
こんな疑問がわいてきますよね。

先ほど、言及したようにコンピューターの裏側ではグループ化されたオブジェクトが作られどこかに保存されています。(この記事の後半に、参考になる英語文献を翻訳して載せています)

イメージで言えばこんな感じです。
![見出しを追加 (64).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/7ee41856-293a-eef8-e381-03e4a881cd62.png)

今回はジャンル (genresという変数に代入している) ごとにグループ化しているので、そのグループ一つ一つを (genre) として、一つ一つのグループに対してループ処理をしましょう。

これをfor loop の一つ目の変数にします(下記のコードの変数genre)

```
for genre in genres
```

ただ、各々のグループのなかで、さらに最高値を探す必要があるので、DataFrameの値そのものにもループさせます。

なので、<font color="Red">for loop の2つ目の変数</font>としてdataを付け加えます。

```
for genre data in genres
```
GroupByオブジェクトのループ処理になぜ２つの変数が要るのかについての理由が書かれている情報の引用をしておきますね。
![スクリーンショット 2021-04-02 092721.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/5e9f9c35-f707-41ea-e8c2-462ae6a614a7.jpeg)
引用元：[kite](https://www.kite.com/python/answers/how-to-loop-over-a-grouped-pandas-dataframe-in-python)

#そもそもGroupByオブジェクトってどうなってるの？
では、一歩下がって、GroupByオブジェクト自体一体何なの？を考えることが、なぜfor loop に２つの変数が必要なのかを考える助けになると思うので、参考文献を下記に記します。

大事な部分だけ翻訳して載せておきますね。(引用元：[Real Python](https://realpython.com/pandas-groupby/#how-pandas-groupby-works))

##split ステージ
![スクリーンショット 2021-04-02 102629.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/49e8c8ed-ef6b-8076-71a8-d6e49f6a161a.jpeg)


>翻訳：
GroupByオブジェクトとは一体何か？
GroupByオブジェクトの理解を難しくしている理由の一つに、GroupByオブジェクトは元来、怠惰であることがあげられる。
あなたが指示を出すまで、有益な結果を返すような処理を施さないのである。

>GroupByオブジェクトについてたびたび使われる用語のひとつに、『split-apply-combine』(分割して-適応して-くっつける)というものがある。これは、連なった3つのステップについてのことである。

>そのステップとは


>①テーブルデータ(csvやexcelのようにテーブルの形式になったデータ)をグループに分ける
②その小さく分割されたテーブルデータそれぞれに処理を行う
③結果を結合させる

>GroupByオブジェクト自体を可視化する事は難しい。
なぜならば、あなたがGroupByオブジェクト に対して何かをするまでは、実質的にGroupByオブジェクトは何もしないからである。
あなたがGroupByオブジェクトに対して何かのメソッドを呼び出すまでは、split-apply-combine のプロセスはされずに先送りされることになる。

>では、その各々のステージが起こっているのを目にすることができないのに、split-apply-combineの各ステージに対してどのようにして心理的な区切りをつけていけばいいのか？

>GroupByオブジェクトのsplitが実際に起こっているのを調べる1つの方法としては、反復処理をさせることである。
![スクリーンショット 2021-04-02 105244.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/351a97bc-1351-06fd-2d8a-afb5c92ffc54.jpeg)

>注意
iterate through は『反復処理する』と翻訳されますが、for loop と同義後です。

##apply ステージ
![スクリーンショット 2021-04-02 110012.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/f0d71a23-ad10-fe8f-5af2-2d7af75ca852.jpeg)

>翻訳：
では、次にapplyについてはどうか？
このステップは、splitステージで作り出された　各々の"sub-table" (筆者は、sub-tableとは小さくグループ分けされたテーブルデータのことを指しています。専門用語でsub-tableと呼ぶのかについては疑問だがとも言っています)に対して、同じ処理を施すことだと考えてみましょう

>GroupByオブジェクトに反復処理をすると、2つの変数に展開することのできる値を取り出すことができます

##combine ステージ
![スクリーンショット 2021-04-02 111305.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/f844c47d-ec40-0088-40d1-e1ddfa63f139.jpeg)

>翻訳：
最後のステップ、すなわちcombineは、これまでのステップのなかで一番明白であろう。
このステップでは、シンプルにsub-table別に処理がなされた結果を取り出し、それらを一緒に結合させます。


では、いよいよGroupByオブジェクトを使って、各ジャンルごとの日本での売り上げがトップの物を取り出してみましょう(前置きが長くなってすみません<(_ _)>)

#GroupByオブジェクトにfor loop を使う

先ほど説明したように、2つの変数を使ってfor loopを書きます

```
for genre , data in genres:
```

dataにループ処理をする中で、一番値の大きい物を取り出したいので、.nlargesta()メソッドを使います

***
for genre , data in genres:
&emsp; highest_sale = data.nlargest(1, "JP_Sales")
***

この取り出した、各ジャンルの最高値をどこかに入れなくてはいけないですね。

なので、<font color="Red">インデックスのみで、値が何も入っていない『空のDataFrame』</font>を作っておきます

```
df = pd.DataFrame( columns= video_sale.columns )
df
```
実行結果は下記のようになります

![スクリーンショット 2021-04-02 121026.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/45d88afd-98c0-5f6e-f9ef-6bbc37a9925b.jpeg)

オリジナルのDataFrameのコラムのみを引数として渡し、<font color="Red">コラム名だけのDataFrame</font>を作りました。

このDataFrame に先ほどのループ処理で取り出した最大値を付け加えていきましょう。

付け加えるのには<font color="Red">『append』</font>を使います。

![スクリーンショット 2021-04-02 121328.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/fe3a0f51-9c4b-bc60-8296-fb6b039e29a6.jpeg)

上記のように、各ジャンルの中で、日本の売り上げがトップの物のDataFrameが出来上がりました。


#まとめ

今回の記事はこれくらいで終わりにします。

今回の記事はいつもより少し長めになってしまいました。<(_ _)>

これに懲りずに、次回以降もどうぞよろしくお願いしますっ！