【Pandas】データを集計する方法 | groupby/pivot_table

## 【はじめに】

Pythonライブラリの「Pandas」の中で、データを集計する方法として「groupby」、「pivot_table」があります。

どちらを使った方が良いのか分からない方のために、集計の目的に応じてどちらを使用するべきか分かりやすく紹介していきます。

### 本記事の内容

- pandasのインポート
- csvファイルの読み込み
- データを集計する | groupby
- データを集計する | pivot_table

## 【pandasのインポート】

```Python
import pandas as pd
```

## 【csvファイルの読み込み】

「1920年から2015年までの全国の人口推移のデータ」を使用します。

```Python
df = pd.read_csv('data.csv', encoding='shift-jis')
df
```

|                      | 都道府県コード | 都道府県名 | 元号 | 和暦（年） | 西暦（年） | 人口（総数） | 人口（男） | 人口（女） | 
| -------------------- | -------------- | ---------- | ---- | ---------- | ---------- | ------------ | ---------- | ---------- | 
| 0                    | 1              | 北海道     | 大正 | 9          | 1920       | 2359183      | 1244322    | 1114861    | 
| 1                    | 2              | 青森県     | 大正 | 9          | 1920       | 756454       | 381293     | 375161     | 
| 2                    | 3              | 岩手県     | 大正 | 9          | 1920       | 845540       | 421069     | 424471     | 
| 3                    | 4              | 宮城県     | 大正 | 9          | 1920       | 961768       | 485309     | 476459     | 
| 4                    | 5              | 秋田県     | 大正 | 9          | 1920       | 898537       | 453682     | 444855     | 
| ...                  | ...            | ...        | ...  | ...        | ...        | ...          | ...        | ...        | 
| 934                  | 43             | 熊本県     | 平成 | 27         | 2015       | 1786170      | 841046     | 945124     | 
| 935                  | 44             | 大分県     | 平成 | 27         | 2015       | 1166338      | 551932     | 614406     | 
| 936                  | 45             | 宮崎県     | 平成 | 27         | 2015       | 1104069      | 519242     | 584827     | 
| 937                  | 46             | 鹿児島県   | 平成 | 27         | 2015       | 1648177      | 773061     | 875116     | 
| 938                  | 47             | 沖縄県     | 平成 | 27         | 2015       | 1433566      | 704619     | 728947     | 
| 939 rows × 8 columns |                |            |      |            |            |              |            |            | 

私のGitHubに「data.csv」としてアップロードしてあるので、下記コマンドでダウンロードすれば簡単に準備できます。

```Shell
$ curl https://raw.githubusercontent.com/nakachan-ing/python-references/master/Pandas/data.csv -O
```

## 【データを集計する | groupby】

`groupby`メソッドを使用すると、DataFrameの要素をもとにデータをグループ分けして、簡単に集計することができます。

引数`by`にグループ分けしたカラムを指定します。

読み込んだcsvファイルから「都道府県別」に、「人口（総数）」、「人口（男）」、「人口（女）」それぞれを集計してみます。

```Python
df_mean1 = df.groupby(by='都道府県名').mean()[['人口（総数）', '人口（男）', '人口（女）']]
df_mean1.head(10)
```

|            | 人口（総数） | 人口（男） | 人口（女） | 
| ---------- | ------------ | ---------- | ---------- | 
| 都道府県名 |              |            |            | 
| 三重県     | 1534021.4    | 743366.55  | 790654.85  | 
| 京都府     | 2135317.95   | 1044093.7  | 1091224.25 | 
| 佐賀県     | 830574.25    | 395550.75  | 435023.5   | 
| 兵庫県     | 4233525      | 2067583.1  | 2165941.9  | 
| 北海道     | 4606104.3    | 2272235.25 | 2333869.05 | 
| 千葉県     | 3591668.1    | 1789946.8  | 1801721.3  | 
| 和歌山県   | 978371.25    | 471085.7   | 507285.55  | 
| 埼玉県     | 4040109.05   | 2023428.05 | 2016681    | 
| 大分県     | 1142165.05   | 544737.95  | 597427.1   | 
| 大阪府     | 6380772.25   | 3167758.65 | 3213013.6  | 

**ポイント**

- DataFrameに対して、はじめに「都道府県名」でグループ分けしてから、「人口（総数）」、「人口（男）」、「人口（女）」の平均を抽出しています。
- DataFrameに対して、はじめに「都道府県名」、「人口（総数）」、「人口（男）」、「人口（女）」のデータを抽出してから「都道府県名」でグループ分けして平均を求めることもできます。

```Python
df_mean2 = df[['都道府県名', '人口（総数）', '人口（男）', '人口（女）']].groupby(by='都道府県名').mean()
df_mean2.head(10)
```

|            | 人口（総数） | 人口（男） | 人口（女） | 
| ---------- | ------------ | ---------- | ---------- | 
| 都道府県名 |              |            |            | 
| 三重県     | 1534021.4    | 743366.55  | 790654.85  | 
| 京都府     | 2135317.95   | 1044093.7  | 1091224.25 | 
| 佐賀県     | 830574.25    | 395550.75  | 435023.5   | 
| 兵庫県     | 4233525      | 2067583.1  | 2165941.9  | 
| 北海道     | 4606104.3    | 2272235.25 | 2333869.05 | 
| 千葉県     | 3591668.1    | 1789946.8  | 1801721.3  | 
| 和歌山県   | 978371.25    | 471085.7   | 507285.55  | 
| 埼玉県     | 4040109.05   | 2023428.05 | 2016681    | 
| 大分県     | 1142165.05   | 544737.95  | 597427.1   | 
| 大阪府     | 6380772.25   | 3167758.65 | 3213013.6  | 

`groupby`メソッドで集計できるものとしては、

- mean（平均）
- sum（合計）
- count（個数）
- max（最大値）
- min（最小値）
- std（標準偏差）
- var（分散）

などがあります。

### 複数要素でグルーピングする

`groupby`メソッドの引数`by`にリストで複数のカラムを指定することで、複数要素での集計が可能です。

「都道府県名」と「元号」をリスト形式で指定して、「人口（総数）」、「人口（男）」、「人口（女）」それぞれの平均を集計してみます。

```Python
df_mean3 = df[['都道府県名', '元号', '人口（総数）', '人口（男）', '人口（女）']].groupby(by=['都道府県名', '元号']).mean()
df_mean3
```

|                      |      | 人口（総数） | 人口（男） | 人口（女） | 
| -------------------- | ---- | ------------ | ---------- | ---------- | 
| 都道府県名           | 元号 |              |            |            | 
| 三重県               | 大正 | 1.09E+06     | 5.35E+05   | 5.53E+05   | 
|                      | 平成 | 1.84E+06     | 8.93E+05   | 9.45E+05   | 
|                      | 昭和 | 1.46E+06     | 7.03E+05   | 7.53E+05   | 
| 京都府               | 大正 | 1.35E+06     | 6.84E+05   | 6.63E+05   | 
|                      | 平成 | 2.63E+06     | 1.27E+06   | 1.36E+06   | 
| ...                  | ...  | ...          | ...        | ...        | 
| 鳥取県               | 平成 | 6.02E+05     | 2.88E+05   | 3.14E+05   | 
|                      | 昭和 | 5.66E+05     | 2.71E+05   | 2.95E+05   | 
| 鹿児島県             | 大正 | 1.44E+06     | 6.98E+05   | 7.46E+05   | 
|                      | 平成 | 1.75E+06     | 8.19E+05   | 9.29E+05   | 
|                      | 昭和 | 1.75E+06     | 8.30E+05   | 9.20E+05   | 
| 141 rows × 3 columns |      |              |            |            | 

このままだと人口が指数表示となってしまい、ひと目では何人なのか分かりにくいですね。

※指数表現は数値を1桁にして、その分10を何乗したかで表現しています。

ひと目で人口が分かるように、`round(0)`とすることで、小数点以下を切り捨てて表現します。

```Python
df_mean3.round(0)
```

|                      |      | 人口（総数） | 人口（男） | 人口（女） | 
| -------------------- | ---- | ------------ | ---------- | ---------- | 
| 都道府県名           | 元号 |              |            |            | 
| 三重県               | 大正 | 1088481.0    | 535354.0   | 553126.0   | 
|                      | 平成 | 1838127.0    | 893168.0   | 944960.0   | 
|                      | 昭和 | 1456225.0    | 703135.0   | 753090.0   | 
| 京都府               | 大正 | 1346764.0    | 684122.0   | 662642.0   | 
|                      | 平成 | 2628425.0    | 1268325.0  | 1360099.0  | 
| ...                  | ...  | ...          | ...        | ...        | 
| 鳥取県               | 平成 | 602177.0     | 287885.0   | 314291.0   | 
|                      | 昭和 | 565924.0     | 270756.0   | 295169.0   | 
| 鹿児島県             | 大正 | 1443888.0    | 697972.0   | 745915.0   | 
|                      | 平成 | 1747640.0    | 818506.0   | 929134.0   | 
|                      | 昭和 | 1749826.0    | 829889.0   | 919936.0   | 
| 141 rows × 3 columns |      |              |            |            | 

### aggメソッドを使って集計する

`agg`メソッドは平均や合計などを同時に集計することができます。

集計したい計算方法を`agg`メソッドの引数にリストで指定します。

「都道府県名」と「元号」をリスト形式で指定して、「人口（総数）」、「人口（男）」、「人口（女）」それぞれの平均、最大値、最小値を集計してみます。

```Python
df_culc1 = df[['都道府県名', '元号', '人口（総数）', '人口（男）', '人口（女）']].groupby(by=['都道府県名', '元号']).agg(['mean', 'max', 'min'])
df_culc1.round(0)
```

|                      |      | 人口（総数） |           |           | 人口（男） |         |         | 人口（女） |         |         | 
| -------------------- | ---- | ------------ | --------- | --------- | ---------- | ------- | ------- | ---------- | ------- | ------- | 
|                      |      | mean         | max       | min       | mean       | max     | min     | mean       | max     | min     | 
| 都道府県名           | 元号 |              |           |           |            |         |         |            |         |         | 
| 三重県               | 大正 | 1088481.0    | 1107692.0 | 1069270.0 | 535354     | 544752  | 525957  | 553126     | 562940  | 543313  | 
|                      | 平成 | 1838127      | 1866963.0 | 1792514.0 | 893168.0   | 907214  | 869515  | 944960     | 959749  | 922999  | 
|                      | 昭和 | 1456225      | 1747311.0 | 1157407.0 | 703135.0   | 847420  | 571000  | 753090     | 899891  | 586407  | 
| 京都府               | 大正 | 1346764.0    | 1406382.0 | 1287147.0 | 684122     | 717464  | 650780  | 662642     | 688918  | 636367  | 
|                      | 平成 | 2628425      | 2647660   | 2602460   | 1268325    | 1278142 | 1248972 | 1360099    | 1374667 | 1334840 | 
| ...                  | ...  | ...          | ...       | ...       | ...        | ...     | ...     | ...        | ...     | ...     | 
| 鳥取県               | 平成 | 602177.0     | 615722.0  | 573441.0  | 287885     | 294899  | 273705  | 314291     | 320823  | 299736  | 
|                      | 昭和 | 565924       | 616024.0  | 484390.0  | 270756.0   | 297015  | 233964  | 295169     | 320513  | 250182  | 
| 鹿児島県             | 大正 | 1443888.0    | 1472193.0 | 1415582.0 | 697972     | 713702  | 682243  | 745915     | 758491  | 733339  | 
|                      | 平成 | 1747640      | 1797824.0 | 1648177.0 | 818506.0   | 842474  | 773061  | 929134     | 955350  | 875116  | 
|                      | 昭和 | 1749826      | 2044112   | 1538466   | 829889     | 985617  | 699455  | 919936     | 1058495 | 803046  | 
| 141 rows × 9 columns |      |              |           |           |            |         |         |            |         |         | 

**ポイント**
​
統計量を算出したい場合は、`agg`メソッドの引数に`describe`を指定します。
​
「都道府県名」と「元号」をリスト形式で指定して、「人口（総数）」の平均、最大値、最小値を集計してみます。

```Python
df_culc2 = df[['都道府県名', '元号', '人口（総数）']].groupby(by=['都道府県名', '元号']).agg('describe')
df_culc2.round(0)
```

|                      |      | 人口（総数） |           |          |           |           |         |         |         | 
| -------------------- | ---- | ------------ | --------- | -------- | --------- | --------- | ------- | ------- | ------- | 
|                      |      | count        | mean      | std      | min       | 25%       | 50%     | 75%     | max     | 
| 都道府県名           | 元号 |              |           |          |           |           |         |         |         | 
| 三重県               | 大正 | 2.0          | 1088481.0 | 27168.0  | 1069270   | 1078876   | 1088481 | 1098086 | 1107692 | 
|                      | 平成 | 6            | 1838127   | 28505.0  | 1792514.0 | 1822238.0 | 1848041 | 1856685 | 1866963 | 
|                      | 昭和 | 12           | 1456225   | 194973.0 | 1157407.0 | 1345410.0 | 1485318 | 1563813 | 1747311 | 
| 京都府               | 大正 | 2.0          | 1346764.0 | 84312.0  | 1287147   | 1316956   | 1346764 | 1376573 | 1406382 | 
|                      | 平成 | 6            | 2628425   | 18362    | 2602460   | 2615163   | 2632842 | 2642316 | 2647660 | 
| ...                  | ...  | ...          | ...       | ...      | ...       | ...       | ...     | ...     | ...     | 
| 鳥取県               | 平成 | 6.0          | 602177.0  | 17328.0  | 573441    | 593253    | 610150  | 614519  | 615722  | 
|                      | 昭和 | 12           | 565924    | 49776.0  | 484390.0  | 545030.0  | 580582  | 601188  | 616024  | 
| 鹿児島県             | 大正 | 2.0          | 1443888.0 | 40030.0  | 1415582   | 1429735   | 1443888 | 1458040 | 1472193 | 
|                      | 平成 | 6            | 1747640   | 59686.0  | 1648177.0 | 1717976.0 | 1769686 | 1792216 | 1797824 | 
|                      | 昭和 | 12           | 1749826   | 161160   | 1538466   | 1590966   | 1756886 | 1827838 | 2044112 | 
| 141 rows × 8 columns |      |              |           |          |           |           |         |         |         | 

小数点以下を切り捨てたことで見やすくなっていますが、桁区切り表示させることでより分かりやすくできます。

`applymap`メソッドと`format`メソッドを使って3桁区切りにします。

```Python
df_culc2.applymap('{:,.0f}'.format)
```

|                      |      | 人口（総数） |           |         |           |           |           |           |           | 
| -------------------- | ---- | ------------ | --------- | ------- | --------- | --------- | --------- | --------- | --------- | 
|                      |      | count        | mean      | std     | min       | 25%       | 50%       | 75%       | max       | 
| 都道府県名           | 元号 |              |           |         |           |           |           |           |           | 
| 三重県               | 大正 | 2            | 1,088,481 | 27,168  | 1,069,270 | 1,078,876 | 1,088,481 | 1,098,086 | 1,107,692 | 
|                      | 平成 | 6            | 1,838,127 | 28,505  | 1,792,514 | 1,822,238 | 1,848,041 | 1,856,685 | 1,866,963 | 
|                      | 昭和 | 12           | 1,456,225 | 194,973 | 1,157,407 | 1,345,410 | 1,485,318 | 1,563,813 | 1,747,311 | 
| 京都府               | 大正 | 2            | 1,346,764 | 84,312  | 1,287,147 | 1,316,956 | 1,346,764 | 1,376,573 | 1,406,382 | 
|                      | 平成 | 6            | 2,628,425 | 18,362  | 2,602,460 | 2,615,163 | 2,632,842 | 2,642,316 | 2,647,660 | 
| ...                  | ...  | ...          | ...       | ...     | ...       | ...       | ...       | ...       | ...       | 
| 鳥取県               | 平成 | 6            | 602,177   | 17,328  | 573,441   | 593,253   | 610,150   | 614,519   | 615,722   | 
|                      | 昭和 | 12           | 565,924   | 49,776  | 484,390   | 545,030   | 580,582   | 601,188   | 616,024   | 
| 鹿児島県             | 大正 | 2            | 1,443,888 | 40,030  | 1,415,582 | 1,429,735 | 1,443,888 | 1,458,040 | 1,472,193 | 
|                      | 平成 | 6            | 1,747,640 | 59,686  | 1,648,177 | 1,717,976 | 1,769,686 | 1,792,216 | 1,797,824 | 
|                      | 昭和 | 12           | 1,749,826 | 161,160 | 1,538,466 | 1,590,966 | 1,756,886 | 1,827,838 | 2,044,112 | 
| 141 rows × 8 columns |      |              |           |         |           |           |           |           |           | 

## 【データを集計する | pivot_table】

`groupby`メソッドではカラム（縦方向）でグルーピングして集計をしましたが、`pivot_table`メソッドでは横方向にも項目を追加して集計することができます。

引数`index`には縦方向に表示させたい項目、`columns`には横方向に表示させたい項目を指定します。

引数`values`に集計するデータのカラムを指定します。

引数`aggfunc`には集計方法を指定します。

`index`に「都道府県名」、`columns`に「元号」を指定して、「人口（総数）」の平均を集計してみます。

```Python
df_pivot1 = df.pivot_table(index='都道府県名', columns='元号', values='人口（総数）', aggfunc='mean')
df_pivot1.round(0).head(10)
```

| 元号       | 大正    | 平成      | 昭和      | 
| ---------- | ------- | --------- | --------- | 
| 都道府県名 |         |           |           | 
| 三重県     | 1088481 | 1838127.0 | 1456225.0 | 
| 京都府     | 1346764 | 2,628,425 | 2,020,190 | 
| 佐賀県     | 679363  | 864,635   | 838,746   | 
| 兵庫県     | 2378239 | 5,511,838 | 3,903,583 | 
| 北海道     | 2428931 | 5,589,153 | 4,477,442 | 
| 千葉県     | 1367706 | 5,962,486 | 2,776,920 | 
| 和歌山県   | 768961  | 1037736.0 | 983590.0  | 
| 埼玉県     | 1356997 | 6,936,328 | 3,039,185 | 
| 大分県     | 887709  | 1,210,304 | 1,150,505 | 
| 大阪府     | 2823674 | 8,809,791 | 5,759,113 | 

### 複数のデータを集計する

複数データを同時に集計することができます。

`index`に「都道府県名」、`columns`に「元号」を指定して、「人口（総数）」、「人口（男）」、「人口（女）」人口の平均を集計してみます。

```Python
df_pivot2 = df.pivot_table(index='都道府県名', columns='元号', values=['人口（総数）', '人口（男）', '人口（女）'], aggfunc='mean')
df_pivot2.round(0).head(10)
```

|            | 人口（女） |           |           | 人口（男） |           |           | 人口（総数） |           |           | 
| ---------- | ---------- | --------- | --------- | ---------- | --------- | --------- | ------------ | --------- | --------- | 
| 元号       | 大正       | 平成      | 昭和      | 大正       | 平成      | 昭和      | 大正         | 平成      | 昭和      | 
| 都道府県名 |            |           |           |            |           |           |              |           |           | 
| 三重県     | 553126     | 944,960   | 753,090   | 535,354    | 893,168   | 703,135   | 1,088,481    | 1,838,127 | 1,456,225 | 
| 京都府     | 662642     | 1,360,099 | 1,028,217 | 684,122    | 1,268,325 | 991,973   | 1,346,764    | 2,628,425 | 2,020,190 | 
| 佐賀県     | 346270     | 456,442   | 439,106   | 333,092    | 408,192   | 399,640   | 679,363      | 864,635   | 838,746   | 
| 兵庫県     | 1170863    | 2,861,527 | 1,983,996 | 1,207,376  | 2,650,310 | 1,919,587 | 2,378,239    | 5,511,838 | 3,903,583 | 
| 北海道     | 1154034    | 2,923,372 | 2,235,757 | 1,274,898  | 2,665,781 | 2,241,685 | 2,428,931    | 5,589,153 | 4,477,442 | 
| 千葉県     | 693601     | 2974638.0 | 1399949.0 | 674105.0   | 2987847   | 1376970   | 1367706      | 5962486   | 2776920   | 
| 和歌山県   | 386836     | 547,112   | 507,447   | 382,124    | 490,624   | 476,143   | 768,961      | 1,037,736 | 983,590   | 
| 埼玉県     | 695390     | 3,443,448 | 1,523,513 | 661,606    | 3,492,880 | 1,515,672 | 1,356,997    | 6,936,328 | 3,039,185 | 
| 大分県     | 450706     | 638,774   | 601,207   | 437,003    | 571,531   | 549,297   | 887,709      | 1,210,304 | 1,150,505 | 
| 大阪府     | 1354138    | 4,517,115 | 2,870,776 | 1,469,536  | 4,292,676 | 2,888,337 | 2,823,674    | 8,809,791 | 5,759,113 | 

### 複数の集計方法を同時に実行する

引数`aggfunc`にリストで集計方法を指定することで、複数の集計方法を同時に実行することができます。

`index`に「都道府県名」、`columns`に「元号」を指定して、「人口（総数）」の平均、最大値、最小値を集計してみます。

```Python
df_pivot3 = df.pivot_table(index='都道府県名', columns='元号', values='人口（総数）', aggfunc=['mean', 'max', 'min'])
df_pivot3.round(0).head(10)
```

|            | mean    |           |           | max       |           |           | min       |           |           | 
| ---------- | ------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | 
| 元号       | 大正    | 平成      | 昭和      | 大正      | 平成      | 昭和      | 大正      | 平成      | 昭和      | 
| 都道府県名 |         |           |           |           |           |           |           |           |           | 
| 三重県     | 1088481 | 1,838,127 | 1,456,225 | 1,107,692 | 1,866,963 | 1,747,311 | 1,069,270 | 1,792,514 | 1,157,407 | 
| 京都府     | 1346764 | 2,628,425 | 2,020,190 | 1,406,382 | 2,647,660 | 2,586,574 | 1,287,147 | 2,602,460 | 1,552,832 | 
| 佐賀県     | 679363  | 864,635   | 838,746   | 684,831   | 884,316   | 973,749   | 673,895   | 832,832   | 686,117   | 
| 兵庫県     | 2378239 | 5,511,838 | 3,903,583 | 2,454,679 | 5,590,601 | 5,278,050 | 2,301,799 | 5,401,877 | 2,646,301 | 
| 北海道     | 2428931 | 5,589,153 | 4,477,442 | 2,498,679 | 5,692,321 | 5,679,439 | 2,359,183 | 5,381,733 | 2,812,335 | 
| 千葉県     | 1367706 | 5962486.0 | 2776920.0 | 1399257.0 | 6222666   | 5148163   | 1336155   | 5555429   | 1470121   | 
| 和歌山県   | 768961  | 1,037,736 | 983,590   | 787,511   | 1,080,435 | 1,087,206 | 750,411   | 963,579   | 830,748   | 
| 埼玉県     | 1356997 | 6,936,328 | 3,039,185 | 1,394,461 | 7,266,534 | 5,863,678 | 1,319,533 | 6,405,319 | 1,459,172 | 
| 大分県     | 887709  | 1,210,304 | 1,150,505 | 915,136   | 1,236,942 | 1,277,199 | 860,282   | 1,166,338 | 945,771   | 
| 大阪府     | 2823674 | 8,809,791 | 5,759,113 | 3,059,502 | 8,865,245 | 8,668,095 | 2,587,847 | 8,734,516 | 2,800,958 | 


## 【さいごに】

今回はデータを集計する方法として「groupby」、「pivot_table」を紹介しました。

特に「pivot_table」はシンプルかつ非常に分かりやすいデータ分析手法です。

これを機に覚えてしまいましょう。

使用したCSVファイルやJupyter NotebookはGitHubに公開しています。
Jupyter Notebookは下記コマンドでダウンロードできるので、自由に使って是非練習してみてください。

```Shell
$ curl https://raw.githubusercontent.com/nakachan-ing/python-references/master/Pandas/pandasでデータ集計する.ipynb -O
```

https://github.com/nakachan-ing/python-references/tree/master/Pandas