Pythonの数値計算プロジェクトを新規作成する

この記事は[株式会社ネクスト(Lifull) Advent Calendar 2016](http://qiita.com/advent-calendar/2016/lifull)の18日目です。

こんにちは、デジタルマーケティングUの二宮です。

最近、社内のいくつかの部署で、統計処理や数値計算にPythonを使うプロジェクトが誕生しています。

これまでは同じグループの @wakuteka さんを中心としてR言語を利用しており、[ドキュメントやノウハウもそれなりにまとまっていた](http://qiita.com/wakuteka/items/54f81f32baf50e243461)のですが、

* [R言語はファンキーな仕様](https://twitter.com/search?q=%23R%E8%A8%80%E8%AA%9E%E3%81%AE%E6%A7%8B%E9%80%A0&src=typd)が多く、
引き継ぎや外部とのやり取りがつらい
* 汎用的な言語としても (例えばWeb開発言語) 使いたい
* 使えるライブラリが異なるので選択肢を広く持ちたい

というニーズもあったようです。

（もちろんR言語を貶めているのではなく、[tidyverse](https://blog.rstudio.org/2016/09/15/tidyverse-1-0-0/)と呼ばれるライブラリ群を用いたインタラクティブな分析・可視化の用途はR言語のほうが使い勝手が良いです。道具は使い所ってことですね。）

私は趣味でPythonを使っており、レビューやアドバイス(というと大げさなのですが)の形で、いくつかのプロジェクトにも関わる機会がありました。

その中で得られた知見や、参考にしていった記事などをまとめていこうと思います。

ただし、試行錯誤しながら進めていったため、もっといい方法があるかもしれませんし、記事の内容も開発全体を網羅しているわけではありません。もしそういう点を見つけた場合は、コメント等で教えて頂けるとうれしいです。

# Pythonの環境を用意する

「[Pythonをまじめに書こうと思って作った開発環境](http://qiita.com/ara_ta3/items/ce8852c1933aae6c4959)」という記事が参考になりました。

統計用ライブラリも抱え込んだ[Anaconda](https://www.continuum.io/downloads)というPythonディストリビューションが有名ですが、本番環境では使っていません。
（開発・分析環境では使っています。）

それは「[pyenvが必要かどうかフローチャート](http://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7)」という記事にもある通り、

> Anacondaの/binをパスに設定するのですが、Anacondaがなかで持っているツール(openssl/curl/python)がOSの持っているツールを覆い隠してしまいます。
あと、BASH前提になりすぎてて、zsh使ってると色々直さないと動きません。

実運用上で、この辺の挙動が不安だったからです。

# 開発

レビューする必要があったので、コーディング規約やDocStringsの書き方などを勉強しなおしました。

## （必要に応じて）パッケージとして切り出す

部署独自の数値計算などは、グループ用のgitリポジトリを使って、pipを用いてインストールできるようにしました。

その際、これらの記事を参考にしました。

* [（インターン向けに書いた）Pythonパッケージを作る方法](http://qiita.com/Kensuke-Mitsuzawa/items/7717f823df5a30c27077)
* [wacode5/python1](https://github.com/wacode5/python1)
* [【Python】データサイエンティストのためのPython開発記事紹介](http://kiito.hatenablog.com/entry/2016/11/16/020454)

## コーディング規約

[PEP8](https://www.python.org/dev/peps/pep-0008/)や[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html)が参考になると思います。

ただし、コーディング規約を目見でチェックするのも手で直すのもつらいので、[flake8](https://pypi.python.org/pypi/flake8)や[autopep8](https://pypi.python.org/pypi/autopep8)も適宜使っています。ただし、PEP8は割と厳しめのコーディング規約なので、適宜相談しながら進めています。

ここでは以下の記事を参考にしました。

* [Pythonのスタイルガイドとそれを守るための各種Lint・解析ツール5種まとめ！](http://blog-ja.sideci.com/entry/python-lint-pickup-5tools)
* [Python のソースコードを自動で PEP8 に準拠させるツール autopep8](http://momijiame.tumblr.com/post/42168625947/python-%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E8%87%AA%E5%8B%95%E3%81%A7-pep8-%E3%81%AB%E6%BA%96%E6%8B%A0%E3%81%95%E3%81%9B%E3%82%8B%E3%83%84%E3%83%BC%E3%83%AB-autopep8)


## DocStringsの記述
また、関数やメソッドの入出力をわかりやすくするため、[GoogleスタイルのDocStrings](http://www.sphinx-doc.org/ja/stable/ext/example_google.html)も書いてもらっています。
他にもNumpyスタイル等もあるようです。

Python3.5以降で[型アノテーション](http://qiita.com/icoxfog417/items/c17eb042f4735b7924a3)を利用する場合はこう、

```python
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
    """Example function with PEP 484 type annotations.
 
    Args:
        param1: The first parameter.
        param2: The second parameter.
 
    Returns:
        The return value. True for success, False otherwise.
  
    """
```

型アノテーションを利用しない場合はこうです。

```python
def function_with_types_in_docstring(param1, param2):
    """Example function with types documented in the docstring.
 
    Args:
        param1 (int): The first parameter.
        param2 (str): The second parameter.
 
    Returns:
        bool: The return value. True for success, False otherwise.
 
    """
```

ただし、レビューしたコードの中にtupleで多値を返す関数があったのですが、（自分が調べた範囲では）GoogleスタイルのDocStringsはReturnsで多値を返す書き方に対応していないようでした。
こちらの[stack overflowの回答](http://stackoverflow.com/questions/29221551/can-sphinx-napoleon-document-function-returning-multiple-arguments/35979352#35979352)を元に以下のように記述してもらいました。

```Python
import pandas as pd

def _postprocess_data(output_data, market):
    """アラート用、ファイル出力用のデータに成形する

        Args:
            output_data (pd.DataFrame): 計算後のデータフレーム
            market (str): 不動産マーケット名

        Returns:
            tuple: 以下の値を多値で返す
                - output_data (pd.DataFrame): アウトプットのデータ
                - monthly_data (pd.DataFrame): 月次データ

    """
```

型アノテーションと[mypyを使った静的解析](http://qiita.com/t2y/items/2a1310608da7b5c4860b)はまだ試していませんが、機会を作って試してみようと思います。

## テストコードの記述

小さなプロジェクトだったので、unittestで簡単なテストをいくつか書いてある程度です。

unittest以外にも[いくつかのフレームワークがあるらしい](http://docs.python-guide.org/en/latest/writing/tests/)のでこれも機会を作ろうと思います。

今は「jupyter notebookで試行錯誤した関数を、エディターに貼り付ける」みたいな感じで進めています。
必要に応じてTDD（的なもの）と使い分けられるようにしたいです。

## pandasのデータフレームについて

Pythonでデータ分析を行う際には、pandasを使ってR言語のようなデータフレーム型を導入することになると思います。

R言語ではdplyrやtidyrなどのライブラリで、データの処理の流れをパイプライン演算子を使って簡潔に表現することができるのですが、pandasで同じように行うには少々慣れが必要そうです。
（また、なんでもデータフレームで表現するRと違って、辞書型との使い分けも試行錯誤しています。）

ただし、こちらの記事にpandasのイケてる書き方がまとまっていたので、これから使い始める方はぜひ読んでください。

* [Python/pandasのデータ処理で再帰代入撲滅委員会](http://qiita.com/piroyoung/items/dd209801ca60a0b00c11)


# まとめ

データ分析ライブラリを使ったPythonプロジェクトで試行錯誤した（またはしている最中の）結果を簡単にまとめました。これを読んでいるどなたかのお役に立てればと思います。

記事の内容も開発全体を網羅しているわけではありません。もしそういう点を見つけた場合は、コメント等で教えて頂けるとうれしいです。

また、[弊社のAdventCalendar](http://qiita.com/advent-calendar/2016/lifull)も、引き続きご注目いただければと思います。