会社に優秀な後輩が入ってきて、優秀な先輩(私でゎない)の助けを得ながら、立派な分析者・Rプログラマーとして成長しつつあります。
しかし、R言語だけで全ての作業が完結できるわけではありません。手元でデータを加工・分析するための環境としては素晴らしいのですが、大規模な計算では遅かったり(パフォーマンスを上げるにしても工夫が必要だったり)、クラスベースのオブジェクト指向が無いため、プログラムが大きくなるにつれて関数の整理が難しかったり、言語としてつらい面も多いです。
また、データ分析して作ったモデルをサービスに乗せる際には別の言語を使う必要があると思います。一応、shinyというWEBアプリを作るためのライブラリもあるものの、「社外向けのサービスでバリバリ使ってるぜ!」という話は聞いたことがありません。
というわけで、R言語メインのプログラマーが、一歩進んでスクリプト言語(Python)が抵抗なく使い始められるようにサポートするための記事を書きました。
こちらの記事の逆バージョンですね。
ただし、自分の環境であるPython 3.4.3 :: Anaconda 2.0.1 (x86_64)
で確認していますが、バージョン(特に2.*系)によって微妙に異なる部分があるかもしれませんのでご了承ください。
Pythonの情報源・入門書
Pythonの書き方自体は難しくありません。入門書を読めば優秀なRプログラマーであればなんとなく分かると思います。 適当な入門書を読んだ後は、Dive Into Python 3 日本語版を読むと理解が深まるでしょう。
ただし、それだけで分析・開発できるようになるわけではありません。 数値計算や可視化のライブラリや、ツールとしての使い方を勉強する必要があります。
今となってはPythonのバージョン等がちょっと古いですが、それでも網羅的に紹介されています。
Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理
- 作者: Wes McKinney,小林儀匡,鈴木宏尚,瀬戸山雅人,滝口開資,野上大介
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/12/26
- メディア: 大型本
- この商品を含むブログ (12件) を見る
上記の本で古くなった部分は、『IPythonデータサイエンスクックブック』でアップデートできると思います。 が、私もちゃんとこの本は読んでいないのできちんと紹介できません。
ただ、Pythonの高速化の例の中で、CやCythonに混じってJuliaが紹介されていたのは驚きました。
IPythonデータサイエンスクックブック ―対話型コンピューティングと可視化のためのレシピ集
- 作者: Cyrille Rossant,菊池彰
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/25
- メディア: 大型本
- この商品を含むブログ (1件) を見る
少し毛色は違いますが、『Pythonプロフェッショナルプログラミング』もいい本です。 PythonでのWEB開発のもろもろを書いた本で、課題管理やレビュー等、Pythonを使って開発している人が悩むことがとりあえず全部書かれているような本です。
- 作者: ビープラウド
- 出版社/メーカー: 秀和システム
- 発売日: 2015/02/27
- メディア: 単行本
- この商品を含むブログ (4件) を見る
Pythonの分析環境構築
Anacondaをインストールしましょう。Anacondaとはpythonのディストリビューションの一つで、nupyやscipy、matplotlib等の数値計算やデータ分析で必要な主要ライブラリをオールインワンでインストールできます。
これらの記事を参考にインストールしてください。
Anacondaはデータマイニングの便利なライブラリを集めて一括でインストール・利用できるようにしたパッケージです。内包されているライブラリは様々な数値解析、機械学習、自然言語処理、可視化、DB連携、データハンドリング、さらには最近話題のディープラーニングなど多岐に渡り、これを入れておけばデータマイニングを行う大抵の場面で対応できるでしょう。
RプログラマーはRStudioを利用している方がほとんどでしょうが、Pythonでデータ分析する際に便利なのがjupyter notebookです。 かつてipython notebookと呼ばれていたツールが、他言語でも利用できる形になったものです。
詳しい話は以下の記事を読んでください。
for文でイライラしない方法
Rのプログラマーはほとんどfor文は使わないと思います。 もし使うとしても、「シミュレーションで1000ステップ計算する」というような場面に限られており、データの操作にfor文は不要です。
数値計算であればベクトル演算を使い、リストの操作もlapply等の汎関数(高階関数)を利用していることと思います。 例えば、1から10までの数を2倍したベクトルを得るには、Rであれば簡単に書けます。
1:10 * 2 # [1] 2 4 6 8 10 12 14 16 18 20
ところが、他の大抵の言語にはベクトル型は無く、リストや配列が用意されています。 そのため、for文を使って次のようなコードを書くことが多く、「Rであればもっと簡潔に書けるのに」とイライラしていることと思います。
result = [] for i in range(1, 11): # 第二引数を10にすると、1:9までしか得られないので注意! result.append(i * 2) print(result) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] # 第三引数で増分が指定できるから、 # list(range(2, 22, 2))でも同じ値は得られるんだけどね
このような場合、Pythonであればリスト内包表記を使うか、numpyという数値計算のライブラリを使ってベクトル型を導入しましょう。
まず、numpyを使った例です。
import numpy as np np.arange(1, 11) * 2 # array([ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
次にリスト内包表記です。これは関数型言語(たしかHaskell)を参考にして導入された書き方です。
Pythonではfor等の手続き型言語の書き方を流用しているのでわかりづらいですが、{f(x) | x ∈ A}
(Aという集合の中のxという変数にfという計算を適用する)という数式を[f(x) for x in A]
と表現しています。ちなみにHaskellの書き方のほうが、元々の数式に近くて分かりやすいです。
[i*2 for i in range(1, 11)] # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
「何度もリストに対して計算を行う場合、リスト内包表記を使って何度もループさせると遅くなるんじゃないの?」と疑問に思うかもしれませんが、Pythonはイテレータを遅延評価させる機能があります。 とりあえず覚えなくても問題ないので詳しくは説明しませんが、以下の記事や『Effective Python』を読んでください。
Python のジェネレータ (1) - 動作を試す | すぐに忘れる脳みそのためのメモ
Effective Python ―Pythonプログラムを改良する59項目
- 作者: Brett Slatkin,石本敦夫,黒川利明
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/01/23
- メディア: 大型本
- この商品を含むブログ (4件) を見る
はじめてのクラス
R言語のプログラマーが他言語に行って戸惑うのが、クラスベースのオブジェクト指向だと思います。
たとえば、Rでの分析しか経験してこなかったプログラマーが、 「ルーチンの分析処理をバッチ処理で自動化したい!」と思って開発にも携わるようになると、 クラスという見慣れない概念が出てきて戸惑うことになると思います。
# クラスを作る class MyClass: # クラスのインスタンスを作る際に呼び出させる関数(initializeの略) def __init__(self, config): # インスタンス変数に設定(conf)を保存する self._config = config # 設定をprintする def print_conf(self): print(self._config) if __name__ == '__main__': instance = MyClass('variable') instance.print_conf()
Rのプログラマーはクラスという概念に慣れていないため、「そんなものなくても関数を細かく区切っていけばそれほど困らないよ」「継承とかカプセル化とか難しい用語がいっぱいでわからないよ(もっと難しい統計用語は使いこなしているクセして!)」と思いがちですが、実際使えると便利な機能です。
(これだけが全てだとは思いませんが、)クラスとは概ね「デカいプログラムを整理するためのもの」です。 たしかに関数を細かく区切ることで分かりやすい、似たような機能をたくさん実装する場合など、オブジェクト指向の機能を使うとコードを整理することができます。
一例として、私は最近作った、社内の様々なレポートを取得するRのコードを残しておきます。クラスの機能を導入するために、R6
ライブラリを使いました。
実際には「売上レポートを取得するための機能」の他に「コンバージョン率のレポートを取得する機能」などをたくさん作っており、そちらではreplaceQueryYear
の代わりにreplaceQueryDate
が必要だったりと、「この関数ってどこに使ってたんだっけ?」「似たような名前の関数がたくさんできちゃったよ」とごちゃごちゃしそうだったのでクラスを作って整理しました。
なんとなくクラスを覚える利点(の一つ)を感じてもらえればと思います。
# PythonではなくRだよ! # 「SQLのファイルを読み込む」など、いろいろなクラスで共通で使う関数をまとめたクラス AbstructReporter <- R6::R6Class("AbstructReporter", private = list( db_config = NA, scanQuery = function(query_path) { return ( # query_pathにあるSQLファイルからクエリを読み込む ) }, execQuery = function(sql) { return ( # sqlを実行する ) } ) ) # 売上レポートを取得するためのクラス SalesReporter <- R6::R6Class("SalesReporter", inherit = AbstructReporter, # 共通で使うクラスを継承 initialize = function(db_config) { private$db_config = db_config # DBの設定を }, public = list( getSalesReport = function(target_year) { sql <- private$scanQuery("example/file/path.sql") %>% private$replaceQueryYear(target_year) return ( private$execQuery(sql) ) } ), private = list( replaceQueryYear = function(sql, target_year) { return ( # SQLの対象期間(年)を置き換える ) } ) ) # 実行プログラム db_config <- "DBの設定" instance <- SalesReporter$new(db_config) sales_report <- instance$getSalesReport("2016") # 2016年のレポートを取得する
RでもR3とかR4とかいくつかのオブジェクト指向的な機能が実装されているようなのですが、『R言語徹底解説』を読んでもサッパリ分かりません。誰か助けてください。
また、「オブジェクト指向」という概念は、以下の記事を読めば分かる通り、いろいろなプログラミングの概念がごった煮になった一筋縄ではいかないものです。 いろいろな言語に触ってがんばっていきましょう(私もがんばります)。
Pythonは関数の第一引数にself
が必要だったり変な感じがするので、オブジェクト指向周りの概念はRubyで勉強するのが近道かなと思います(Python入門なのに)。Rubyは最初からオブジェクト指向言語を目指して作られているので、スッキリ学びやすかったです。
『メタプログラミングRuby 第2版』の前半で、Rubyのオブジェクト指向の仕組みが説明されています。
Pythonな人だけど「メタプログラミングRuby」を読んでみた | TRIVIAL TECHNOLOGIES 4 @ats のイクメン日記
- 作者: Paolo Perrotta,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/10/10
- メディア: 大型本
- この商品を含むブログ (2件) を見る
もしかするとJavaのほうがいいのかもしれませんが、私はJavaをほとんど触ったことがないので分かりません。
ファイルを読み込む
Rでファイルを読み込む場合、分析用ファイルであればread.csv
や(私はよく知らないですが)データを読み込む高速なライブラリの関数を、テキストファイルであればscan
やreadLines
等の関数を利用していると思います。
ファイルを読み込む際にプログラマーが気をつけることは、「(特にエラーが発生したときに)ファイルを閉じ忘れない」ということです。 そのため、大抵の言語ではファイルの閉じ忘れを防ぐ機能を持っています。
Pythonでは、with
構文でその機能を提供しています。withブロックを抜ける(エラーが発生した場合でも)と、自動でファイルを閉じてくれます。
プログラミングでは、ファイルのインプット/アウトプットで特にエラーが発生しやすいため、このような処理が用意されています。
他の言語でも同様の機能が用意されているものが多く、Rubyの場合ブロックを使ってこの機能を実現しています。
with open('./example.txt', 'r') as f: text = f.read() print(text) # テキストファイルの中身を表示!
open
関数の第二引数の'r'はread=読み込みの意味です。ファイルに書き込む場合は'w'にします。
csvを読み込む際は、標準ライブラリであるcsv
を利用します。公式のドキュメントにあるサンプルコードを引っ張ってきました。
import csv with open('some.csv', newline='') as f: reader = csv.reader(f) for row in reader: print(row)
with
構文についていまいちピンと来ていない場合、ちょっと古いですが、こちらの記事が参考になると思います。
「おれはread.csv
したいだけなのに面倒だなあ」「Rみたいにデータフレーム使いたいよ」という場合は、pandas
ライブラリを利用しましょう。
もちろんread.csv
にあたる操作も用意されています。
import pandas as pd sampledata = pd.read_csv('./example.csv')
また、write.csv
に当たる操作は、データフレーム型の変数からto_csv
メソッドを呼び出す形で操作します。
sampledata.to_csv('output.csv', index = False)
pandasの使い方の詳しくは、以下のサイトを参照してください。
既存のライブラリを使う
R言語のプログラマーは、自分で計算のロジックを実装することは(周囲から思われているよりは)あまり無く、CやC++で作成された高速なライブラリを組み合わせて分析を行うことが多いと思います。
Pythonであれば、科学計算のscipy
や機械学習のscikit-learn
等、Rほどではないですが充実したライブラリを利用することができます。
これらのライブラリについて調べれば、利用したい処理が既に実装されていることも多いでしょう。
例えば、以下の記事ではscipy
による高速フーリエ変換(FFT)の例が紹介されています。
記事を見てもらえばわかると思いますが、フーリエ変換のような自分で実装するとややこしい処理が、fft
関数を呼び出すだけで完了してしまっていることがわかると思います。
# 離散フーリエ変換
yf = fft(y)
プロットする
自分の持っている仮説を検証するには、集計・解析結果をグラフにプロットしてPDCAを回す必要があります。
Rでは標準でplot
やhist
等の関数を使ってグラフを可視化できますが、Pythonでは同等の機能をmatplotlib
を利用します。これはMATLAB風のプロットが簡単にできるライブラリです。
Jupyter notebook上でインタラクティブに可視化でき、Rのプログラマーでも特に違和感なく利用できると思います。
ただし、最近はseaborn
やbokeh
等の新しい可視化ライブラリが現れてきているようです。特にseaborn
は、Rのggplot2
に近いおしゃれな感じのプロットが簡単にできるそうなので、今度触ってみます。
この辺の話は『IPythonデータサイエンスクックブック』にきちんと書いてあるそうです。