この記事は freee Engineers Advent Calendar 2016 の 19 日目です。
今年2016年の7月からfreeeにやってきました、@ami_o です。
freeeにはAnalyticsというエンジニアとビジネスの狭間のポジションがありまして、
そこでSQLを叩いたり、Salesforceに手を出したり、スプレッドシートと格闘したりしています。
調理師免許は持っていません。
#コンサルからfintechに来ました
前職はいわゆる外資系経営コンサルティング会社で、いかに多くのエクセル&パワポショートカットキーを覚えるかに全力を費やしていた時期もありました。
しかし、もはやそうして極めたショートカットキー達も、freeeに来てPCはmacになり、エクセルはgoogleスプレッドシートになり、ほとんど意味を為さなくなってしまいました。
入社前に弊社COOに「コンサル時代に学んだ基本的な問題解決の考え方は今も役立ってるけど、それ以外は、ほとんど役立たないよ(ニコニコ)」と言われたのを日々実感しています。
freee engineersのadvent calenderで一体何を書いたものやら、と悩んでいましたが、freeeに来てから頻繁に触れるようになった機械学習やビッグデータという(私にとって)ホットな話題について、前職から未だ引きずっている「80:20」とか「仮説思考」といったザ・コンサル的な考え方とどう折り合いをつけていくかについて書きたいと思います。
#freeeでの分析はデータを取ってくるところから
さて、freeeで分析を行うにあたってまず大変だったのは、分析に使うデータを自分で取ってこないといけない事です。
前職ではクライアントさんに「これこれこういうデータください。できれば明日中に」というメールを一本送ると翌日には調理を待つだけの新鮮な魚が届けられてきたのです。
しかしfreeeでは「営業系のデータはSalesforceのレポートから出せるし、プロダクト系のデータはredshiftに入っているからpgwebかre:dashでSQL叩いて出してください」と言われて、もう何が何だかわからないまま気が付いたらマグロ漁船のボートに乗せられていました。
##SQLは扱うテーブルの構造理解が9割、文法の理解が1割
そんな感じで大海に投げ出されたSQL初心者でしたが、データ抽出だけ見るとSQLは文法的な難度は低いと思います。
**それよりも、扱うテーブルの構造を知る事の方が100倍大事!**というのが6ヶ月間の学びです。
個人的にはGROUP BY
の概念が曲者でした。
Excelユーザーとしては、感覚的にidが縦に並んで横に項目が並んで〜という2次元テーブルを思い浮かべてしまうのですが、freeeの場合、ユーザーさんの情報が[id×日付×項目]
という恐怖の3次元データで格納されていまして、それをちゃんと理解するまでに2週間くらいかかりました。
データ構造が分かれば、あとはパズルが待っています。どういうロジックにしたら欲しいデータが出てくるかを、SQLの気持ちになって考えます。
構文をかっこよく磨いていくのはその後。今もウィンドウ関数や、サブクエリの勉強中です。
ちなみに私がいつもre:dashに言われているエラーの8割は、以下の雑魚キャラ的エラーです。
1.Error running query: syntax error at or near "from" LINE 5: from companies ^
→ 大抵、fromの直前に不要なコンマがある
2.Error running query: column "companies.id" must appear in the GROUP BY clause or be used in an aggregate function
→ group byしなきゃいけないのにしてない/しなくていいのにしてる
3.その他、絶対間違っていないのにErrorが出るとき
→ 全角スペースが紛れこんでいる
#ビッグデータ解析とイシューからはじめよの狭間で
さて、無事マグロも獲れるようになってきたけど、調理場が魚で溢れてるよ?!どうやって調理しよう?というのが現状。
freeeはおかげさまで60万事業所を超えるお客様にご利用いただいております。
ということは、60万件分のレコードが毎日、毎アクション、蓄えられていっているのです!!
これを流行りのビッグデータ解析すれば、なんだかすごい結果が出るに違いない!!
...と、無条件で思えないのが辛いところ。
「イシューからはじめよ」で安宅さんが言っているように、そもそも「本当に解くべき課題」を特定し、仮説を立て、その仮説検証のために必要な分析を設計し、それから初めて手を動かすべき、と3年間叩き込まれ続けてきました。
言うなれば、作るメニューをあらかじめ決めてから必要最低限の食材探しをしに行く方法に慣れてしまっているです。以下、これを**「省エネ分析」**と呼びます。
一方で、その対になる**「バリバリデータ解析」、こちらはとにかくたくさん食材を集めて、勝手に調理してくれるオーブンに端から突っ込んでいく方法**です。
ともすれば否定されがちなこの方法を、実用しているのは小売業の陳列やオンラインショップのリコメンデーションだけではなくなって来ているという現実もあります。
折良く先週のSalesforce World Tour 2016で、話題のSalesforceの機械学習機能Einsteinの話を聞いてきました。
Sales cloudとマーケティングツールPardotにEinsteinを組み込んで使うと、例えば
- お客様のデモグラフィ情報とウェブアクティビティから、リアルタイムでリードのスコアリングができる
- お客様との電話の内容を自然言語処理し、ベストなフォローアップ方法と日程と時間を自動提案してくれる
と、人が全く頭を使わなくても勝手に最適なセールスができるようになる仕組みのよう。
これがもう製品化されているんです。
ただ、そう言われると、全く頭を使わなくてよい営業は、私たちが目指すところなのか?という疑問も出てきますよね。
##「分析→現場への適応」をどういうスパンで回すかが分析手法を選ぶ鍵?
結局、どう調理するか、どういう料理人になりたいか、は状況と目的に依る、としか言えないのだと思います。
ではどういう時に「バリバリデータ解析」して、どういう時に「省エネ分析」するべきなのでしょうか。
###分析結果を鵜呑みにして高速で[アウトプット→思考]サイクルを回す
まず言えるのは、バリバリデータ解析は、ノーロジックだからこその「やってみてから考えよう」感が、スピード重視の企業にマッチするのではないでしょうか。
数字が出てくるとどうしても裏にあるロジックを考えたくなりがちなのですが、バリバリデータ解析に求められるのは、「メニューを考えている暇もない。とにかくオーブンに突っ込んで、出て来た料理を食べてから考えよう」という姿勢です。
やってみて、成果が出たら継続すれば良いですし、成果が出なかったら、別の方法を探る。
そういう意味で、部署単位で閉じていて小回りが効く戦略に適用したほうがリスクが少ないです。
そして同様に、バリバリデータ解析は、刻一刻と結果が変わっていくリアルタイム性に強みがあるのかと思います。
例えば、お客様のデモグラフィの話をすると、ある地域だけ一時的に成約率が高まるという状況が起こりえるかもしれません。それはたまたま競合がテレビCMをストップしたとか、地域情報誌に記事が載ったとか、本社の営業が気がつかない何かがあったとします。
それを、省エネ分析は見逃してしまいますが、バリバリデータ解析ならば、一時的にその地域のリードスコアが高くなって、営業リソースを集中させる事ができます。
バリバリデータ解析ではロジックを超越した真理が見える事もあります。
以前@fuji_tip さんがfreeeプロダクトの「エンゲージメントスコア」を、生存時間との重み付け相関を用いて設定した時、頻繁に使っていればいるほどスコアがマイナスになる機能がありました。
普通だったらどんな機能であれ、使えば使うほど「エンゲージメント」は高くなるはずだと考えるものです。
しかし実は、あまりに頻繁にその機能を使っているユーザーは、とある理由でその後解約する確率が高い、という傾向が潜んでいたのです。
このように、これまで考えられなかった因果関係がデータ分析の側から見えてきたりします。特に新しいサービスを展開している場合には、新たな発見があります。
たまに、なんで祖先はこれを食べようと思ったんだ?と感じる料理がありますが、納豆だって、そういうやり方で生み出された至極の一品だと思います。
###結果から論理を解き明かして得たインサイトを他の戦略に反映させる
一方で省エネ分析は、中長期的な意思決定を迅速に行う時には欠かせないかと思います。
それは、ただ単に「データがそう言っている」だけでは人は納得させられないからです。
でも出てきたデータを見てからなぜそうなっているかを考えると、時間がかかります。であれば先に論理立った仮説を立てて、その仮説が正しいか間違っているかを見るためにデータを分析する方が、全体としてかかる時間が短縮できるのです。
また、会社として得たインサイトの伝搬をするためにも、省エネ分析的な考え方は必要です。たまたまヒットしたのか、それともしっかりした理由でターゲットとしている顧客層に受け入れられたのか、を紐解いて初めて、次の戦略の道筋が見えてくるのだと思います。
そして得られたインサイトを元に、先手を打つのも、省エネ分析の得意なところです。
データ解析は、過去のデータを解析して過去の状態を読む事はできますが、統計モデルに沿った動きをしない事象、過去にデータがない事象に対しては、将来予測ができません。
例えばオンラインショップに全く新しい製品が扱われる事になったとして、それをどのお客様にリコメンドすればいいかは、ある程度の類推が必要になります。
#結論:いいとこ取りしよう
無理にポジション取る必要もないので、思うままに書き綴れば、**目的のために使える手法はどんどん取り込みたい!**です。数字の解析からしか発見できない新たな気づきもあるでしょうし、でも、人を納得させるにはロジックが必要ですし。
双方向でチューニングしながら、もやっとしたものに対して形を与えていくような、そういう分析がしたいなと思っています。
ちなみに、未だに記憶に残っているのは、「良いマネージャーはあらかじめメニューを何通りか考えられて、万一失敗しても別の料理にできるように仕込みを指示できる人。でも良いマネージャーばかりではないから、いざという時のために、冷蔵庫をぱかっと開けて残った食材からそれなりに美味しい料理を作り出せないといけないがディレクター」
という言葉です。
主婦は強しって事ですね。
そんなfreeeでは食材探しの旅からご一緒して頂くデータサイエンティストを絶賛募集中です。リアルなデータを心ゆくまで分析しながら、日本のスモール&ミドルビジネスを応援していきませんか?
はて、このまま何もエンジニアっぽい内容がないと来年のadvent calenderにAnalyticsが呼んでもらえなくなってしまいますので、以下にRでちょこちょこやった時の事を追記します。
明日は、freeeのISU(いい感じにスピードアップ)会のピンクのペンギンといえばこの方、@foostan さん、よろしくお願いいたします!
#備忘録としてのRでのアソシエーション分析の手順
複数の顧客デモグラフィの中で、どの項目の組み合わせが、契約獲得可能性に大きく影響しているのか?
を判定したい場合を想定します。
ロジスティク回帰分析も使えますが、アソシエーション分析したかったので備忘録。
##データテーブルを用意する
まず、分析したいデータを準備します。よくあるバスケット形式は他にも解説がありますので、今回は下のような形。
一番右の"契約有無"がある値(1)を取る場合の、左側の項目の寄与を調べます。
性別 | 役職 | 地域 | 業種 | 訪問回数 | ... | 契約有無 |
---|---|---|---|---|---|---|
男 | 役員 | 東京 | 飲食 | 5 | ... | 0 |
女 | 経営者 | 東京 | IT | 2 | ... | 1 |
女 | 役員 | 大阪 | 建設 | 1 | ... | 0 |
男 | 営業部長 | 東京 | IT | 2 | ... | 1 |
男 | 経営者 | 神奈川 | 建設 | 2 | ... | 1 |
- csv形式で用意します ("testdata.csv")
- 空欄にはNAなど適当な値を入れておいた方が良いです
- この時点では数字もテキストも混ざっていてOK
##Rで分析準備
次にRを立ち上げ、アソシエーション分析の準備をします。
1.下記のコマンドで、arulesというライブラリをインストールします
> install.packages('arules')
> library(arules)
途中、「ミラーサイトを選んでください」というポップアップが出るので、JAPANを選んでみましょう。
arulesの使い方についてはこちらが詳しいです
2.分析したいデータファイルが入っているフォルダに移動します
今いる場所(ディレクトリ)を確認してから
> getwd( )
> list.files()
狙ったフォルダに移動
> setwd("/Users/Ohsugi/Documents/R")
↑はユーザーネームOhsugiの、書類フォルダの中のRというフォルダにデータが入っている場合です。
3.準備していたデータファイルを読み込みます
csvファイルの中身を、Rで処理するためのテーブルに読み込みます(名前はtesttableとしています)
> testtable <- read.csv("testdata.csv", sep=",", header=TRUE, fileEncoding='cp932')
(fileEncoding='cp932'
は、Shift_JIS読み込み用で、macユーザーは必須です。
うまくいかなければ'UTF-8'または'UCS-2LE'なども試してみてください。)
次に読み込んだtesttableをトランザクション型のデータに変換します
> as(testtable, 'transactions')
↑この一行だけなのですが、そのままでは上手く行かないことが多いです。
こんなこと言われたりします
asMethod(object) でエラー: column(s) 5, 8, 9 not logical or a factor. Discretize the columns first.
5、8、9列目がfactor型じゃないよ。と言っています。じゃあ何型なのさ、と思って
> class(testtable[,5])
と打つと、[1] "integer"
だよって教えてくれます。
トランザクション型はinteger(整数)もすべてfactor型というテキスト型に変換しないと扱ってくれません。なので
> testtable[,5]<-factor(testtable[,5])
> testtable[,8]<-factor(testtable[,8])
...というのを該当する整数型のカラムに一列一列適用していって、完了したら改めて
> as(testtable, 'transactions')
と打つと、
transactions in sparse format with
10000 transactions (rows) and
150 items (columns)
と返ってきて、無事、分析のための読み込みが完了です。
##いざアソシエーション分析を実行
ここから先はウェブ上に良い説明があるので駆け足で。
R {arules} によるアソシエーション分析をちょっと詳しく 1
アソシエーション分析(1)
aprioriでアソシエーションルールを抽出
> rules <- apriori(testtable)
たくさんのルールの中で、欲しい結果(契約有無が1)のルールに限定
> subset(rules, subset = rhs %in% '契約有無=1')
ルールが思った数出てこなかった場合、 confidenceの下限値を調整して再度aprioriでルール抽出
> r <- apriori(tran, parameter = list(confidence = 0.5, target = "rules"), control = inspect(r)
デフォルト値はsupport =0.1, confidence=0.8, maxlen=5になっているようです。
後はでてきた数字を眺めて満足するまでRにコマンドを打ち込みましょう。