Python統計テクニック集 ～Pythonで抗う統計解析～



これは、[Open and Reproducible Science Advent Calendar 2019](https://adventar.org/calendars/4523)：13日目の記事です。

# 記事の目的
統計解析といえばRです。
しかし私のようにPythonだけでなんでもやりたい人もいます。
そんな人に向けて、Pythonで統計解析を行う上で便利なライブラリやテクニックをご紹介します。
同じテーマの記事や書籍も多々ありますが、他ではあまり紹介されていないものを中心にまとめるつもりです。
各ライブラリ・テクニックの詳細についてはなるべく別記事を紹介する方針です。

対象：Pythonを使ったことはあるけれどガチではない人

# Jupyter Notebook / Lab
様々な記事で紹介されているド定番ですが、一応ご紹介します。

なぜ私たちはSPSSのようなGUIベースでなく、PythonやRのようなプログラムベースの統計ソフトを使うのか。
それは~~高価だから~~**結果の再現性**を確保するためです。
雑に言い換えれば、ある結果がどのような操作・解析から得られたのかを後から確認できるようにするためです。

Jupyter Notebookは、実行結果を逐一確認しながらプログラムを書くためのツールです。
RでいうところのR Markdown、MATLABでいうところのライブスクリプトです。
それぞれの解析結果がどういったプログラムによって導かれたのかを振り返ることが容易になります。
Pythonでデータ解析を行うなら必須とも言えるツールでしょう。
詳細は、[このあたりの記事](https://qiita.com/takuyanin/items/8bf396e7b6b051670147)がわかりやすいかなと思います。

Jupyter Lab は、Jupyter Notebookの進化版です。
2019年6月、ついにver1.0が公開されました。
Notebookと比べて決定的な違いはないと思いますが、様々な点で使い勝手が上がっています。
詳細については、[このあたりの記事](https://qiita.com/kirikei/items/a1639954ce5ccaf7ac3c)がおススメです。

個人的には、ルーラー機能が気に入っています。
Pythonでは「一行の長さを79文字以内にするとイイヨ」という規約（[PEP8](https://pep8-ja.readthedocs.io/ja/latest/#)）があります。
必ずこの規約を守らなくてはならないわけではありませんが、一行の長さを適切に守ると後から読み直しやすいです。
ルーラー機能を使うと、どこまでが79文字かすぐわかります。

Notebookでも拡張機能を入れれば表示できましたが（[参照](https://qiita.com/simonritchie/items/88161c806197a0b84174#ruler)）、Labでは設定をいじるだけで実装できます（[参照](https://stackoverflow.com/questions/49322559/how-can-i-add-a-ruler-vertical-line-to-codemirror-editors-in-jupyterlab)）

# 関数に切り分ける
上述の通り、主な解析コードは Jupyter Notebook / Lab で`.ipynb`ファイル上に書くのがおススメです。
しかし、ややこしいコードは適宜関数として切り分けて別の`.py`ファイルに書き込みましょう。
`.ipynb`からはそれを`import`して使うのみにすると、可読性がグッと上がります。

自分で関数を作ったり、それを`import`できるようにする方法については[こちらの記事](https://qiita.com/ren094275/items/5d42f7c6be8c5d3cd014)をご覧ください。

ところが、`.py`ファイルの更新を`.ipynb`に反映させるためには一度 Restart Kernel させてやる必要があります。
変数がいったんすべてリセットされてしまうのでなかなか面倒です。
それを防ぐためには、下記のコードを`.ipynb`の頭に入れてやりましょう。

```python
%reload_ext autoreload
%autoreload 2
```

これで、Restart　Kernelをしなくても`.py`ファイルの変更が即時反映されます。

## Docstringを残す
Docstringとは、あるフォーマットに則って書かれた、関数の使い方についてのメモです。

自分の書いた解析スクリプトを一年後くらいに読んでみると、内容がまるでちんぷんかんぷんだったりします。
時間をかければ解読することもできるでしょうが、Docstringを残しておくとラクに振り返ることができます。
書き方については[この記事](https://qiita.com/simonritchie/items/49e0813508cad4876b5a#%E3%81%9D%E3%82%82%E3%81%9D%E3%82%82docstring%E3%81%A3%E3%81%A6)を読めばバッチリです。

## コメントを残す…？

Docstring以外にも、コメントを適宜残して解析の内容が後からすぐわかるようにしましょう。
…と、よく言われますが、議論があるようです（[参照](https://qiita.com/hiro-hori/items/1cf28a6ac75db077c8f3
)）。
つまるところ、コメントを残さなくても変数名や関数名から内容がすんなりわかればそれがベストということのようです。

私見：
少なくとも`.ipynb`は、コメント等を残さなくてもすんなりコードが読めるようにしましょう（見出しはつけましょう）。
後から見返した時すんなり読み解けないなと思ったら、関数として切り分けてコメントやDocstringを残しましょう。

## Gitを（少なくとも程々に）使う
Pythonに限らない話ですが…

Gitは、ソースコードのバージョンを管理するためのシステムです。
Gitといえば[GitHub](https://github.com/)というサイトが有名ですね。
これは（乱暴に言えば）Gitで管理されているデータを保存するためのクラウドストレージのようなものです。
適切にGitを使うことによって、過去の時点におけるソースコードを確認することができます。

GitおよびGitHubの使い方は、[このあたりの記事](https://qiita.com/nnahito/items/565f8755e70c51532459)がわかりやすかったです。

Gitを使ってこまめに変更履歴を記録していくことは、プログラマにとって必須の技術のようです。
…が、私のようなモノグサ人間には逐次記録を残していくことが中々しんどいです。
せめて、**研究室・勉強会・学会大会・論文等で解析結果を発表したとき**だけでも履歴を記録するようにしましょう。
それらの発表で使われた解析結果が、どういったコードによって得られたのかを振り返ることができます。

## breakpoint() を使ったデバッグ
プログラムのエラーを直すときには、エラーの原因を探ることが第一歩になります。
そんなとき、そのエラー周辺の変数の中身を確認したり、コードの流れをワンステップづつ確認させてくれるのがデバッグ機能です。
Pythonのデバッグ機能の使い方は、[こちらの記事](https://qiita.com/musaprg/items/d9f091957475e3088f0e)をご確認ください。
ただし、この記事等で紹介されている方法は、Jupyter Notebookからは使えません。
下記のように書き換えてください（[参照](https://qiita.com/makopo/items/170c939c79dcc5c89e12)）。

```python
# import pdb; pdb.set_trace() <- これの代わりに
from IPython.core.debugger import Pdb; Pdb().set_trace()    # <- これ
```

もしPython3.7以降のバージョンを使っているなら ↓ でもOKです。[（参照）](https://qiita.com/nakkun/items/62cc704af729893783f1)

```python
# import pdb; pdb.set_trace() <- これの代わりに
# from IPython.core.debugger import Pdb; Pdb().set_trace() <- これでもなく
breakpoint()    # <- たったこれだけ
```

`breakpoint()`、超便利です。

## 変数を別ファイルから読み込む
自身で定義した関数を別の`.py`ファイルから`import`できることは知っていましたが、
変数（定数）の定義もできることを最近まで知りませんでした。
やり方は[こちらの記事](https://qiita.com/xKxAxKx/items/9c9198a4e1665d624d88)をご覧ください。
大量のパラメータなどをずらっと羅列して記述する場合等は、この方法を使うと後から見やすいですね。

## Googleスプレッドシートを読み込む
アンケートを実施するために、Googleフォームを利用している人も多いでしょう。
Googleスプレッドシートに蓄えられたデータを解析するときは普通、一旦.csvとしてダウンロードしてからそれを読み込むかと思います。
しかし`oauth2client`というライブラリを使えば、スプレッドシートを直接Pythonに読み込ませることができます。
逐一途中経過を解析したいけど、いちいちファイルダウンロードするのが面倒な人におすすめです。

やり方は[こちら](https://qiita.com/AAkira/items/22719cbbd41b26dbd0d1)でご紹介されています。

↓みたいな感じで関数にしておくと便利です。

```python
import pandas as pd
from oauth2client.service_account import ServiceAccountCredentials
import gspread


def fetch_spread_sheet(spreadsheet_name, worksheet_num, json_path):
    """
    指定したGoogleスプレッドシートをDataFrame型として読み込む

    Parameters
    ----------
    worksheet_name: str
        読み込むスプレッドシートの名前
    worksheet_num: int
        スプレッドシートのうち、読み込むワークシートの番号
    json_path: str
        GoogleDrive API managerからDLしてきたjsonファイルのパス
    """
    scopes = ['https://www.googleapis.com/auth/drive']
    credentials = ServiceAccountCredentials.from_json_keyfile_name(
        json_path, scopes=scopes)
    gc = gspread.authorize(credentials)
    workbook = gc.open(spreadsheet_name)
    sheet = workbook.get_worksheet(worksheet_num)
    return pd.DataFrame(sheet.get_all_values())
```

## 統計ライブラリ Pingouin
Pingouin（パングワン、フランス語でペンギンのこと）は、Pythonで使える統計パッケージです（[公式サイト](https://pingouin-stats.org/index.html)）。
2018年4月に初公開された、新しめのパッケージですね。

Pythonの統計パッケージといえば`StatsModels`や`scipy.stats`があります。
これらに対してPingouinのウリは、“シンプルかつ徹底的”なところです。
例えば`scipy.stats`の`ttest_ind`を使うと、ｔ検定を行ってｔ値とｐ値を返してくれます。
これに対して`pingouin.ttest`は、ｔ値、ｐ値、**自由度、エフェクトサイズ、95%信頼区間、検定力、Bayse Factor**までいっぺんに返してくれます。

pingouinの機能一覧は[公式サイト](https://pingouin-stats.org/api.html#)から確認しましょう。
他のライブラリではできなかったり、ややこしかったりする関数が揃っています。