まだExcelで消耗してるの？Pythonによる自動集計ガイド 基礎編

ちょっとしたデータの加工や集計に、ExcelやGoogle Spreadsheetは便利ですが、それが日常的な作業になってしまったら自動化したいですよね？

そこでお勧めなのが[pandas](http://pandas.pydata.org/)です。
Pandasは Python 用のデータ処理パッケージであり、ExcelファイルやCSVなどの表形式データを読みこみ、加工や集計した上で、出力するといったことがプログラムで記述できます。また開発環境を用意しなくとも、Googleが提供する無料の開発環境である[Colaboratory](https://colab.research.google.com/)上で、すぐに試すことができます。

そしてPythonは、Office 98以降20年以降更新されていないVBAに代わる新たなスクリプト言語として、Microsoftが採用を検討しているという話もあります。

> [ExcelにPython搭載、マイクロソフトが検討。アンケートを実施中](https://www.publickey1.jp/blog/17/excelpython.html)

## まずPandasの全体像を掴んでみる

Pandasでは、1次元データのことをSeries、2次元をDataFrame、3次元をPanelと呼びます。DataFrameはExcelでいうテーブルあるいはピボットテーブルに相当します。Pandas公式のチートシートの邦訳版は、全体像を掴む上で役立つでしょう。以下は、下記リンク先の資料をそのまま画像化したものになります。

> [Pandas 公式チートシートを翻訳しました](https://qiita.com/s_katagiri/items/4cd7dee37aae7a1e1fc0)

![Pandas_Cheat_Sheet_ja_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/31788/1cba91dc-d2da-67dc-499e-169af1a4e632.png)
![Pandas_Cheat_Sheet_ja_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/31788/305214aa-211c-6e69-1601-ae4e3948252b.png)

以下は、下記の記事を一部抜粋し、翻訳したものです。

> [Common Excel Tasks Demonstrated in Pandas](https://pbpython.com/excel-pandas-comp.html)

## 集計列を加える
始めに、まず[リンク先](https://pbpython.com/extras/excel-comp-data.xlsx)のexcelデータをpandasの DataFrameに読み込みます。

```python
import pandas as pd
import numpy as np
df = pd.read_excel("excel-comp-data.xlsx")
df.head()
```

DataFrameとして格納したdfの先頭5行をhead()で求めると、以下のようになります。

<div style="max-width:100%;overflow:auto;">
<table border="1" class="table table-condensed">
<thead>
<tr style="text-align: right;">
<th></th>
<th>account</th>
<th>name</th>
<th>street</th>
<th>city</th>
<th>state</th>
<th>postal-code</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td> 211829</td>
<td>  Kerluke, Koepp and Hilpert</td>
<td>                   34456 Sean Highway</td>
<td>      New Jaycob</td>
<td>         Texas</td>
<td> 28752</td>
<td>  10000</td>
<td>  62000</td>
<td> 35000</td>
</tr>
<tr>
<th>1</th>
<td> 320563</td>
<td>              Walter-Trantow</td>
<td>                    1311 Alvis Tunnel</td>
<td>   Port Khadijah</td>
<td> NorthCarolina</td>
<td> 38365</td>
<td>  95000</td>
<td>  45000</td>
<td> 35000</td>
</tr>
<tr>
<th>2</th>
<td> 648336</td>
<td>  Bashirian, Kunde and Price</td>
<td> 62184 Schamberger Underpass Apt. 231</td>
<td>  New Lilianland</td>
<td>          Iowa</td>
<td> 76517</td>
<td>  91000</td>
<td> 120000</td>
<td> 35000</td>
</tr>
<tr>
<th>3</th>
<td> 109996</td>
<td> D’Amore, Gleichner and Bode</td>
<td>          155 Fadel Crescent Apt. 144</td>
<td>      Hyattburgh</td>
<td>         Maine</td>
<td> 46021</td>
<td>  45000</td>
<td> 120000</td>
<td> 10000</td>
</tr>
<tr>
<th>4</th>
<td> 121213</td>
<td>               Bauch-Goldner</td>
<td>                  7274 Marissa Common</td>
<td> Shanahanchester</td>
<td>    California</td>
<td> 49681</td>
<td> 162000</td>
<td> 120000</td>
<td> 35000</td>
</tr>
</tbody>
</table>
</div>

ここで "Jan", "Feb", "Mar"の合計列"total"を追加するケースを考えます。Excelなら下記画像のように、sum(G2:I2)の列を加えることになりますね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31788/956ec4ce-e2e5-cc09-7c81-09b2afe1432a.png)

一方、pandasでは次のように記述します。

```python
df["total"] = df["Jan"] + df["Feb"] + df["Mar"]
df.head()
```

<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<table border="1" class="table table-condensed">
<thead>
<tr style="text-align: right;">
<th></th>
<th>account</th>
<th>name</th>
<th>street</th>
<th>city</th>
<th>state</th>
<th>postal-code</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th>total</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td> 211829</td>
<td>  Kerluke, Koepp and Hilpert</td>
<td>                   34456 Sean Highway</td>
<td>      New Jaycob</td>
<td>         Texas</td>
<td> 28752</td>
<td>  10000</td>
<td>  62000</td>
<td> 35000</td>
<td> 107000</td>
</tr>
<tr>
<th>1</th>
<td> 320563</td>
<td>              Walter-Trantow</td>
<td>                    1311 Alvis Tunnel</td>
<td>   Port Khadijah</td>
<td> NorthCarolina</td>
<td> 38365</td>
<td>  95000</td>
<td>  45000</td>
<td> 35000</td>
<td> 175000</td>
</tr>
<tr>
<th>2</th>
<td> 648336</td>
<td>  Bashirian, Kunde and Price</td>
<td> 62184 Schamberger Underpass Apt. 231</td>
<td>  New Lilianland</td>
<td>          Iowa</td>
<td> 76517</td>
<td>  91000</td>
<td> 120000</td>
<td> 35000</td>
<td> 246000</td>
</tr>
<tr>
<th>3</th>
<td> 109996</td>
<td> D’Amore, Gleichner and Bode</td>
<td>          155 Fadel Crescent Apt. 144</td>
<td>      Hyattburgh</td>
<td>         Maine</td>
<td> 46021</td>
<td>  45000</td>
<td> 120000</td>
<td> 10000</td>
<td> 175000</td>
</tr>
<tr>
<th>4</th>
<td> 121213</td>
<td>               Bauch-Goldner</td>
<td>                  7274 Marissa Common</td>
<td> Shanahanchester</td>
<td>    California</td>
<td> 49681</td>
<td> 162000</td>
<td> 120000</td>
<td> 35000</td>
<td> 317000</td>
</tr>
</tbody>
</table>
</div>

## 集計行を加える

次に、各列の合計値を求めるケースを考えます。Excelの場合、SUM(G2:G16)という記述を集計したい列ごとに記入する必要があります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31788/b347c1f3-4b8e-84cf-1441-13dc43148cd0.png)

pandasなら次のように記述できます。

```python
df["Jan"].sum(), df["Jan"].mean(),df["Jan"].min(),df["Jan"].max()
```
```
(1462000, 97466.666666666672, 10000, 162000)
```

あるいは次のように記述することで、Seriesとして結果を取り出すことができます。

```python
sum_row=df[["Jan","Feb","Mar","total"]].sum()
```
```
sum_row
Jan      1462000
Feb      1507000
Mar       717000
total    3686000
dtype: int64
```
sum_rowの型はこの時点ではSeriesですが、DataFrameの型に変換し、転置することで、一行の表になります。

```python
df_sum=pd.DataFrame(data=sum_row).T
df_sum
```

<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<table border="1" class="table table-condensed">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th>total</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td> 1462000</td>
<td> 1507000</td>
<td> 717000</td>
<td> 3686000</td>
</tr>
</tbody>
</table>
</div>

先ほど求めたdf_sumを、dfの列に対応付けてみましょう。するとdf_sumは次のような内部状態となります。※ NaNはExcelでいう#N/A

```python
df_sum=df_sum.reindex(columns=df.columns)
df_sum
```

<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<table border="1" class="table table-condensed">
<thead>
<tr style="text-align: right;">
<th></th>
<th>account</th>
<th>name</th>
<th>street</th>
<th>city</th>
<th>state</th>
<th>postal-code</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th>total</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td> 1462000</td>
<td> 1507000</td>
<td> 717000</td>
<td> 3686000</td>
</tr>
</tbody>
</table>
</div>

最後に、次のようにdfとdf_sumを結合できます。

```python
df_final=df.append(df_sum,ignore_index=True)
df_final.tail()
```
以下は、結合したdf_finalの末尾5行をtail()で表したものです。

<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<table border="1" class="table table-condensed">
<thead>
<tr style="text-align: right;">
<th></th>
<th>account</th>
<th>name</th>
<th>street</th>
<th>city</th>
<th>state</th>
<th>postal-code</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th>total</th>
</tr>
</thead>
<tbody>
<tr>
<th>11</th>
<td> 231907</td>
<td>                   Hahn-Moore</td>
<td> 18115 Olivine Throughway</td>
<td>   Norbertomouth</td>
<td> NorthDakota</td>
<td> 31415</td>
<td>  150000</td>
<td>   10000</td>
<td> 162000</td>
<td>  322000</td>
</tr>
<tr>
<th>12</th>
<td> 242368</td>
<td> Frami, Anderson and Donnelly</td>
<td>          182 Bertie Road</td>
<td>     East Davian</td>
<td>        Iowa</td>
<td> 72686</td>
<td>  162000</td>
<td>  120000</td>
<td>  35000</td>
<td>  317000</td>
</tr>
<tr>
<th>13</th>
<td> 268755</td>
<td>                  Walsh-Haley</td>
<td>     2624 Beatty Parkways</td>
<td>    Goodwinmouth</td>
<td> RhodeIsland</td>
<td> 31919</td>
<td>   55000</td>
<td>  120000</td>
<td>  35000</td>
<td>  210000</td>
</tr>
<tr>
<th>14</th>
<td> 273274</td>
<td>                McDermott <span class="caps">PLC</span></td>
<td>    8917 Bergstrom Meadow</td>
<td> Kathryneborough</td>
<td>    Delaware</td>
<td> 27933</td>
<td>  150000</td>
<td>  120000</td>
<td>  70000</td>
<td>  340000</td>
</tr>
<tr>
<th>15</th>
<td>    NaN</td>
<td>                          NaN</td>
<td>                      NaN</td>
<td>             NaN</td>
<td>         NaN</td>
<td>   NaN</td>
<td> 1462000</td>
<td> 1507000</td>
<td> 717000</td>
<td> 3686000</td>
</tr>
</tbody>
</table>
</div>

いかがでしたか？
本記事が好評でしたら、テーブルのフィルタや並び変え、ピボットテーブル編も書いてみたいと思います！