「サブスクリプションミートアップ vol.1」に参加しました(全発表まとめ)
本日開催された「サブスクリプションミートアップ vol.1」に参加しました。サブスクリプション事業における知見共有を目的とした会で、中でもKPIの運用・計測などアナリスト的観点の話が中心でした。
subscription-meetup.connpass.com
開催趣旨は、当日も説明に使われた次のスライドにまとまっています。
- 残存率の推移シミュレーションによるLTV予測と費用対効果の可視化手法
- カスタマーサクセスの効果を可視化・定量化・KPI化した話
- 初心者アナリストのくせに継続率を爆上げした話
- サブスクリプションはなぜ失敗するのか
残存率の推移シミュレーションによるLTV予測と費用対効果の可視化手法
五島 陽さん / 株式会社ドワンゴ
やりたいこと=LTVの予測
- 投資判断基準の明確化のため
- 意識している点
- 回収期間を決める
- LTVは一つではない(組み合わせの切り口次第)
- 算出方法
- 機械学習的
- 数学的
- 統計的(本日はこれ)
費用対効果の可視化手法
- 「期待売上」「ROAS(期待売上/費用)」の散布図
- logを取ったり、偏差値に変換したり
所感
- 可視化時に対数を取るのはよくやるが、偏差値を取るのはあまり発想になかった
- 確かに一般に理解しやすい気がするので、機会があれば試してみたい
カスタマーサクセスの効果を可視化・定量化・KPI化した話
鎌田 真太郎さん / freee株式会社
やりたいこと/やったこと
反省とこれから
- 失敗
- 中間指標の中間指標が大量発生してしまった
- SaaS Matricsとの距離感が微妙
- 反省
- 複雑にしすぎた
- 「良くないものを減らす」は人間の感情的に良くないのかもしれない
- 増やす方向の指標の方が楽しい
所感
- 「KPIを新規作成する場合、減らすより増やす方向の指標の方が良さそう」という視点は、新鮮で面白かった
初心者アナリストのくせに継続率を爆上げした話
椋林 淳一さん / Retty株式会社
前提条件
- Rettyのミッション:レストラン情報で、個別最適
- サブスクリプションしてもらうのは、お店側
- 顧客には無料で使ってもらう
やったこと
- 継続率が上がっていない課題を発見
- サービスへの満足
- どれだけ送客できるか
- お店が来店実感しているかどうか
- サービスへの満足
- 顧客との関係性強化
- 介在価値(営業部門への関連)
- セグメンテーションして、とにかく仮説を出す
- A群:初回更新タイミングで更新している店舗
- B群:初回更新タイミングで解約している店舗
- プロダクトを触って、仮説を出す
- とにかく仮説を洗い出して、良い結果が出るまで仮説検証
結論
- "User Happy"なお店が良い
- 駄目な例(どんなお店か分からない)
- 写真がない
- 推しポイントが分からない など
送客、継続インパクトが大きかったもの
- ネット予約
- 送客が増えるだけでなく、来店実感もしてもらえる
- 来店したくなるコース
- 魅力的なコース情報を充実させる
結果
- 継続率成長率が160%に
- プロダクト側とビジネス側の両方の課題を解決
- プロダクト側:店舗情報が不十分だった
- ビジネス側:継続率向上のための施策が不明瞭だった
「Machine learning graph pitch #1」に参加しました(全発表まとめ)
本日開催された「Machine learning graph pitch #1」に参加しました。機械学習の中でも、特にグラフ関連の技術を実務で使っている5人の方々のLTをお聞きできました。
machine-learning-pitch.connpass.com
- Improving "People You May Know" on Directed Social Graph(Graph Embedding を用いた双方向つながり予測)
- GANを用いたリンク予測におけるネガティブサンプルの生成
- DAGの埋め込み手法とdisk embedding
- 論文レコメンドにおける Graph Convolutional Network を用いたlink prediction
- おわりに
Improving "People You May Know" on Directed Social Graph(Graph Embedding を用いた双方向つながり予測)
agata (@agatan_) さん
- Wantedly People の機械学習エンジニア。担当は、文字認識、記事推薦、つながりの推薦など。
やりたいこと
- Wantedly Peopleでのつながりを増やしたい
- 「もしかして知り合いかも?」の表示
- Link prediction: 繋がる可能性の予測
- 初期は「同じ会社」「共通のつながり人数」などルールベースでやってきた
- ルールで拾いきれないユーザにも推薦を出したい
Graph Embeddingを用いる利点
- 複雑な関係を表現できる
- エッジが2, 3億あるWantedlyのデータを1次元ベクトルとして扱えたら嬉しい
- 推薦候補の検索が高速に表現できる
- 全探索するとしてもない積を取るだけ
- embeddingの近傍情報を使って推薦候補を絞る
- (他のタスクへの応用)
- 別タスクの入力として使う
技術
- シンプルなdeep walkで試した
- 双方向ではないエッジを捨てているので、次の情報が落ちる
- つながりリクエストが拒否された情報
- 「単方向のつながり」を経由して弱く繋がっているという情報
- つながりの種類を表現することで、上記の情報も活用
- "Complex Embedding" を参考に実現
結果
- 「Top 50以内に繋がるユーザを推薦できる」ユーザ数が10.3%増加
- もともと推薦を出せていたユーザに対する推薦の質はほぼ同等
- 実運用上は、ルールベースは残しつつ、拾えないユーザにGraph Embeddingを用いた情報を出しているらしい
GANを用いたリンク予測におけるネガティブサンプルの生成
inuzuka (@studio_graph3) さん
- クックパッドのリサーチエンジニア。アルバイトを経て、2019年に新卒入社。
技術
- リンク予測
- スコアリング関数の定め方が大事(資料 p. 17)
- 2種類の方法
- 類似度に基づいた手法
- 類似度に基づかない手法
- 分類モデルでリンクの存在を直接予測
- 行列の因子分解を利用
やりたいこと
- 知識グラフにおけるリンク予測
- 訓練データに登場しないペアについてもリンクを予測する
- 知識グラフを連続ベクトル特徴空間に
- 知識グラフを計算可能に
- 意味的な類似性を内包させたい
技術的難しさ
- データセットには正例しか保持していない
- 訓練するとき
- 1: 訓練データから作られた正例
- 0: 人手で作られた負例
- マージンに基づいたランキングのlossを最小化
- 負例は人手で作っているので、決定境界から遠い負例を生成しがち
- 訓練に有効ではない
- モデル収束の邪魔になる
- → GANを基に、ネガティブサンプリング
提案手法の課題
- モデルが大きくなる
- GANを用いることで収束がやや困難に
- 精度は出るが時間がかかる
- 既存のネガティブサンプリング手法から得られた知見
- 全エンティティと関係の組についてスコアを計算
- (画像ではなく離散値を出力するので、Mode collapseの問題は検知しやすい)
DAGの埋め込み手法とdisk embedding
nunuki (@nunuki_) さん
- LAPRAS (旧 scouty)のMLエンジニア。
技術
- 自分でICML2019に通した論文を解説
- Directed Acyclic Graph (DAGs) の Embedding
- グラフの推移的な構造を保ったまま埋め込む手法
- Upper Cone と Lower Cone という構造で、包含関係扱える
- これまでは上位概念ほど小さくなっていくTreeのような構造を仮定してしまっていた
提案手法のContribution
- DAGの既存の埋め込み手法を統一する "Disk Embedding" というフレームワークを導入
- 全く新しいモデルである "Hyperbolic Disk Embedding" を提案
応用範囲
- 例えば論文などは、親も子も豊富に繋がりがあるので DAGs が使えそう
- Future Work になっている
論文レコメンドにおける Graph Convolutional Network を用いたlink prediction
vaaaaanquish (@vaaaaanquish) さん
- エムスリー株式会社のMLエンジニア。MLエンジンの開発が主務。
やりたいこと
- 医療関係者は時間がないので論文レコメンドしてあげたい
- プロジェクトの制約
- 興味を前提に医師が最も学べる論文を推薦したい
- いろいろな問題を扱いたいが、エンジニア的には統一的な枠組みでできると嬉しい
- 利用可能なデータとして「論文クリック」のような直接的な教師データがほぼない
- 興味を前提に医師が最も学べる論文を推薦したい
Graph Embeddingを用いる利点
- さまざまなタスクがあり、いろいろな評価関数があるので、多くの問題に適用できそう
- Link Predictionタスクは、半教師あり学習の形でも解くことができる
- (userとcontentsはpage viewで繋いでいるが、tag経由でも繋がっているのでcold start問題にも対応できる?)
おわりに
申込時に「最近読んだ面白かった機械学習関連の論文と理由」を聞いているだけあって、質疑応答の議論も多くかつ質が高く、よい勉強会でした。なお、申込時のアンケート結果は、事後のアンケート答えてくれた人には共有してくださるそうです。事前アンケートで参加者をフィルタリングして、事後アンケートに答えるモチベーションも作る良い方法だと感じました。
「Sports Analyst Meetup #2」を開催しました #spoana
「Sports Analyst Meetup #2」を開催しました。実務でスポーツのデータ分析をしている方のロングトーク2本に加え、LTも10本と盛りだくさんの内容でした。
2月末に開催した初回に続く、第2回の開催です。
発表資料はこちらにまとまっています(今後、資料が公開され次第追加していきます)。
Twitterの #spoana タグの付いた投稿は、下記にまとめています。
- ロングトーク①「遺伝的アルゴリズムを用いたエンデュランス競技の最適ペース探索と、アスリートへの提示方法」
- ロングトーク②「ブラインドサッカー日本代表チームのデータ分析サポートについて」
- LT
- 「戦略シミュレーション分析」(競技:バドミントン)
- 「大相撲優勝決定巴戦に見る不合理な分布」(競技:相撲)
- 「高校セーリング部のための「データ活用ツール」制作秘話」(競技:セーリング)
- 「1年目のTリーグ」(競技:卓球)
- 「富士登山競争を定量的に評価する」(競技:登山)
- 「サポーターの熱気を可視化する」(競技:サッカー)
- 「ボール保持力・奪取力マップから見るロシアW杯2018」(競技:サッカー)
- 「ポジショナルプレーの研究がしたいです」(競技:サッカー)
- 「バスケットボール, ハンドボール, ホッケー, バレーボール, 水球 リオオリンピックの球技の結果予測:統一予測モデルの構築について」
- 「部活とSports Analysis」
- おわりに
ロングトーク①「遺伝的アルゴリズムを用いたエンデュランス競技の最適ペース探索と、アスリートへの提示方法」
小山 浩之さん(合同会社アヘッドスポーツエンジニアリング)
LT
実際の発表順にタイトル・競技名・発表者名を列挙させていただきます。
ご興味あるものがあれば、発表資料やtogetterにまとめたtwitterの投稿などをご参照ください。
「戦略シミュレーション分析」(競技:バドミントン)
funain さん
「大相撲優勝決定巴戦に見る不合理な分布」(競技:相撲)
tomi_ さん
「1年目のTリーグ」(競技:卓球)
e-toppo さん
「サポーターの熱気を可視化する」(競技:サッカー)
Akira-Yama さん
「ボール保持力・奪取力マップから見るロシアW杯2018」(競技:サッカー)
saeeeeru さん
「ポジショナルプレーの研究がしたいです」(競技:サッカー)
gshirato さん
「部活とSports Analysis」
tetsuroito さん
おわりに
本イベントを支えてくださった参加者・発表者・運営メンバーの皆さま、会場をご提供いただいたデータスタジアム株式会社の皆さまに、改めてお礼申し上げます。本当にありがとうございました。次回開催も検討しておりますので、ご参加やご発表など、どうぞよろしくお願いいたします。
「diverta 2019 Programming Contest」をPythonで解く
A〜Dまで解きました。
A - Consecutive Integers(100点)
- サンプルなど、実際に具体的な数字で考えると良い
N, K = list(map(int, input().split())) print(N - K + 1)
B - RGB Boxes(200点)
R, G, B, N = list(map(int, input().split())) cnt = 0 for r in range(N//R + 1): for g in range((N - r*R)//G + 1): if (N-r*R-g*G) % B == 0: cnt += 1 print(cnt)
C - AB Substrings(400点)
- まずは結合前の各文字列内の'AB'の数を数えておく
- あとは結合でいくつ増やせるか
- 解説の場合分けを考えれば良い
- 'BCCCCA'が2つあっても、増やせる'AB'は2個ではなく1個
N = int(input()) S = [input() for i in range(N)] cnt_ab_from_S = sum([s.count('AB') for s in S]) start_from_b_and_end_at_a = sum([(s[0] == 'B') and (s[-1] == 'A') for s in S]) not_start_from_b_and_end_at_a = sum([(s[0] != 'B') and (s[-1] == 'A') for s in S]) start_from_b_and_not_end_at_a = sum([(s[0] == 'B') and (s[-1] != 'A') for s in S]) ans = cnt_ab_from_S if (start_from_b_and_end_at_a == 0): ans += min(not_start_from_b_and_end_at_a, start_from_b_and_not_end_at_a) elif (not_start_from_b_and_end_at_a + start_from_b_and_not_end_at_a == 0): ans += (start_from_b_and_end_at_a - 1) else: ans += (start_from_b_and_end_at_a + min(not_start_from_b_and_end_at_a, start_from_b_and_not_end_at_a)) print(ans)
D - DivRem Number(500点)
問題文の条件を数式で表すと、次のようになる。
(N - N%m)/m = N%m
ここで k = N%m と置いて整理すると、次の式を得る。
N = k(m + 1)
つまり、(m + 1) は N の約数である必要がある。ただしあくまで必要条件でしかないので、あとは候補の十分条件をそれぞれ確認する。
約数の候補を得るのは、次の実装などが高速。
N = int(input()) def make_divisors(n): divisors = [] for i in range(1, int(n**0.5)+1): if n % i == 0: divisors.append(i) if i != n // i: divisors.append(n//i) # divisors.sort() return divisors ans = 0 divisors = make_divisors(N) for d in divisors: m = (d - 1) if m and (N//m == N % m): ans += m print(ans)
Kaggle Kernel (Jupyter Notebook) でログを別ファイルに出力する
本記事では、Kaggle Kernel (Jupyter Notebook) でログを別ファイルに出力する方法を紹介します。
「Jupyter Notebook形式での出力が大量になると見づらいので、別ファイルに吐き出したい」などの需要を想定しています。
参考実装
Kaggle Kernelを例として作成しました。序盤でloggerを定義して getLogger() でファイルに書き込んでいきます。
書き込んだ情報は、Outputのタブで 001.log として保存されます。内容が短い場合はブラウザ上のプレビューで中身が確認できますし、長い場合はファイルをダウンロードして全文を確認することも可能です。
おわりに
本記事では、Kaggle Kernel (Jupyter Notebook) でログを別ファイルに出力する方法を紹介しました。
なお、本内容は「kaggler-ja slack」での発言内容を転記する形で作成しました。
コロケーションの指標「C-value」のPython実装
概要
論文
Katerina T. Franzi and Sophia Ananiadou: Extracting Nested Collocations, In Proceedings of the 16th International Conference on Computational Linguistics (COLING ‘96), pp. 41-46, 1996.
https://www.aclweb.org/anthology/C96-1009
要旨
- 「コロケーション度合い」の計算は、単純に単語列の出現頻度だけを見ても上手くいかない
- 「C-value」という「コロケーション度合い」を尤もらしく計算する指標を提案
- 具体例含めて、上述のブログで日本語で解説されている
- ※ 1996年の論文
計算の具体例
与えられた文章群から、以下のような「コロケーションの候補」が得られたとします。コロケーションの候補は、単純にn-gramでの出現頻度の高いものを抽出します。次の表はたとえば、"Staff Reporter of The Wall Street Journal"という文字列が19回、"Wall Street Journal"が26回登場したことを意味します。
ここで論文内のアルゴリズムに沿ってC-valueを算出すると、以下のようになりました。これは論文内で登場した結果とも一致しています。
上位には、"Wall Street Journal", "The Wall Street Journal"など感覚的にコロケーションと判定できそうな文字列が来ています。一方で "of The Wall Street" など中途半端な単語で始まる文字列がC-valueは0(コロケーションではない)と判定されています。
遺伝的アルゴリズムで平成から令和に変えてみる
遺伝的アルゴリズムを用いて 'HEISEI' という文字列を 'REIWA' に変えてみました。
平成(HEISEI)から令和(REIWA)に遺伝的アルゴリズムで変換するプログラム書いた pic.twitter.com/LefqiaPYBM
— u++ (@upura0) April 30, 2019
開始時
終了時
ルール
- 'HEISEI' という文字列から開始
- 置き換えられる文字は、英大文字と半角スペースの27種類
- 'REIWA '(末尾は半角スペース)になったら終了
結果
今回の実験の場合、35世代目で 'REIWA ' を出力できました。1世代当たりのエージェント数を1000に設定しているので、合計で35000回の施行をしたことになります。
>>> 27*27*27*27*27*27 387420489
ナイーブに27通りの6文字を試すと4億通り弱のパターンがあるので、遺伝的アルゴリズムを用いることである程度効率よく探索できていると分かります。