読者です 読者をやめる 読者になる 読者になる

Web就活日記

愛と夢と人生について書きます

Team Geekを読んだ

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

GWを利用して積読の消化をを実践中。Googleギークたちはいかにしてチームを作るのかというサブタイトルが印象的な一冊。主にチームの文化形成やリーダー(マネージャー)としての在り方の部分を重点に自分なりに感じた言葉として纏める。

2章 素晴らしいチーム文化を作る

  • チーム文化 = エンジニアリングチームが共有する経験、価値、目標。
  • 優秀なエンジニアに働いてもらうためには優秀なエンジニアを採用しなければならない。優秀なエンジニアトップダウンのマネジメントではなく合意ベースのマネジメントを好み、意思決定に参加したいと思う。
  • 建設的な批判はチームの発展や成長には欠かせない。
  • MTGの数を減らして非同期コミュニケーションを増やすべき。
  • ミッションステートメントを作成し、注力すること、やらないことを明確化し、プロダクトの方向性の合意を得る。ただしプロダクトのピボットに合わせて修正可能なものとする。
  • MTGを行う際のルールを作る。
    • 絶対に必要な人だけを呼ぶ。新しいものを設計するMTGには5人以上呼んではいけない。
    • アジェンダMTG前に配布。
    • ゴールを達成したらそこで終了。
    • MTGを順調に進める。
    • お昼、終業の前に開始時間を設定する。
  • Face to FaceのMTGを過小評価してはいけない。
  • 全てのコードはコードレビューされるべき。品質を保つと同時に品質への誇りを持たせる。

3章 船にはキャプテンが必要

  • Googleではチームリーダーは二つの役割に分かれている。
    • TL(チームリード) : プロダクトの技術的なものに責任を持つ。
    • TLM(テクニカルリードマネージャ) : エンジニアのキャリアに責任を持つ。
  • 多くのエンジニアはマネージャーになりたくないと思う。
  • マネージャーになることは、自身をスケールさせたり、より多くのエンジニアと協力してより多くのコードを書くことができるし、もしくは自分がマネージャーに向いているかもしれない。
  • 必要以上のマネージは行わないこと。例:マイクロマネジメントなど
  • サーヴァントリーダーシップのようにエンジニアが働きやすい環境を整えるために、あらゆる障害を排除することも必要。
  • 採用においては自分の言いなりになる人ではなく、自分より優秀な人を採用すべき。自分より優秀な人は自分の変わりになってくれるだろうし、新しい刺激を与えてくれるかもしれない。
  • 1〜2人ほどのパフォーマンスが低い人がいるだけでチームはうまく回らなくなってしまう。そういった人をチームに残すことはその人のためにもならない。今の場所で成長させるか退席させるかを判断する。
  • パフォーマンスが低い人へのコーチングは2-3ヶ月で達成する目標を定めてあげる。小さい目標から入って小さい成功体験を何個か積み重ね、次第に目標を大きくしていく。
  • 採用を妥協してはいけない。イマイチな人を採用した結果、採用を妥協したことのコストより大きくなってしまう恐れがある。
  • チームメンバーの幸せを追い求める。また面談では必要なものを聞く。
  • チームメンバーにタスクを委譲するものと、自分で手を汚して対応する必要がある。リーダーになって間もない頃であればタスクをメンバーに渡してチームが学習する機会とする。しばらくリードした後であれば他の人がやらないような領域で自ら手を動かし尊敬を集める。
  • 事を荒立たせる必要がある時もあり、その場合は直ぐに着手する。自然解決を待ってはいけない。
  • 人を幸せで生産的にするのは外発的動機づけではなく、内発的動機づけであり、内発的動機づけには自律/熟達/目的の3つが必要。

The Data Management Platform: Foundation for Right-Time Customer Engagement [DMPに関する欧米の調査内容(2012.12)]

DMP

The Data Management Platform: Foundation for Right-Time Customer Engagement

調査資料
http://www.iab.net/media/file/Winterberry_Group_White_Paper-Data_Management_Platforms-November_2012.pdf
2012年12月にIABから出されたDMPに関する実態調査的な資料を見つけたので目を通してみた。※尚下記で引用される英文説明や図は全て上のリンクからの出典となる。

DMPの概要
f:id:yutakikuchi:20160306130538p:plain
出典元の表現としては以下のように書かれている。

  • the data management platform (DMP), an emerging technology solution that supports “Big Data” implementation for advertisers, marketers, publishers and others looking to aggregate, integrate, manage and deploy disparate sources of data.

data management platform(DMP)は分断されたデータソースを集約/結合/管理/配布したい広告主、マーケータ、パブリッシャー、その他...の人たちのための"Big Data"の実装をサポートするテクノロジーソリューションとして用いられる。DMPとしては上図にあるように

  • AGGREGATE(DATA SOURCES)、INTEGRATE AND MANAGE(DMP APPLICATIONS)、DEPLOY(USE CASES)

の3パートに分かれており、データの収集、解析、利用という流れがある。AGGREGATEのフェーズにおいてデータソースとして中核となるのはFirst-Party(クライアントだけが持つデータ)、Thrid-Party(データ公開をしている外部クライアントが持つデータ)としてのデジタル化された行動履歴のデータであり、その他よく使われるものとしてはOfflineのデータ、商品の購買データ、新しいデータソースなどがある。収集したデータソースに対してデータの記録と保管/バラバラのフォーマットにならないようデータの正規化/必要なデータを選択、セグメント化/分析した結果を見て意思を決定する。その先に、デジタルデータの独立したフィードを集約or管理し、インターネットユーザーのより深い興味解析やOnline広告のターゲティングを強化し、mediaのセールス拡大のために行動するであろうインターネットユーザーのセグメントをリッチ化する。更にインターネットユーザーのデジタル体験を最適化するためにデジタルとデジタル以外のデータを集約してあらゆるチャネルをとおしてユーザーとコミュニケーションをする。

DMPはどんな活用に期待されているのか
f:id:yutakikuchi:20160306194726p:plain
ビジネス的には期待されている内容としては上図の通りで

  • Improve Ad Targeting Effectiveness、Embrance Shift to Media Audience Buying、Aggregate Connected Customer Insights、Automate Digital Media Buying、Optimize Media Buying Efficiencies、Realize Potential of Cross-Channel Marketing... Connect Traditional and Digital Data in a Compliant Way

広告ターゲティング精度改善、メディアのAudienceDataの購入、接続された顧客の興味の集約、デジタルメディアの自動購入、メディアの効率な買い方の最適化、(CrossChannelMarketingの実現、デジタルと非デジタルデータの結合などがある。 一つの媒体に接触するAudienceの行動履歴は断片でしか無いので横断したCrossChanelMarketingの重要性、更にはAudienceの消費行動はリアルな世界がまだ中心なのでオンラインデータとオフラインデータの結合(020)への期待が伺える。

  • ADVERTISING、MARKETING、MEDIA SALES、COMMERCE

実際のところビジネスの領域としては広告、マーケティング、媒体収益、流通の4つで主に利用されている。DMPを活用すると手動でデータを管理するのと何が異なるのか?という内容に対しては

  • INTEGRATION、SCALE、SPEED、FLEXIBILITY、INSIGHT、ASSURANCE

結合、スケール、スピード、柔軟性、知見、保証とシステムとしてはやや当たり前の内容が書かれている。更にコアコンピタンスとしては以下の通り。

  • Integration of First-and-ThirdParty Data、 Segmentation、 Digital Data Aggregation、 Audience Analytics、 Digital Data Warehousing、 Data Transfer/ Export to Channels、 Modeling、Integration of Digital and Traditional Data

First,ThirdPartyのデータを結合、 セグメント化、 デジタルデータの集約、 オーディエンスの分析、 デジタルデータの保管、 データ変換やチャネルへの出力、 モデリング、デジタルと非デジタルのデータの結合。

DMPって簡単に言うと
以下の4つの項目として挙げられている。

  • A CENTRAL HUB FOR DATA COLLECTION, INTEGRATION AND MANAGEMENT:
  • A HYBRID OF PLATFORM TECHNOLOGY AND MANAGED-SERVICE SOLUTIONS—PROVIDING A RICH VIEW OF A GIVEN CUSTOMER AUDIENCE:
  • AN APPROACH TO “ACTIVATING” DATA RESOURCES THAT MIGHT OTHERWISE BE UNDERUTILIZED:
  • A TOOL FOR ENABLING RICHER ONLINE VISITOR EXPERIENCES—AND MORE TARGETABLE CUSTOMER SEGMENTS:

データ収集の中央ハブであり、結合と管理を行う。技術と管理されたサービスソリューションのハイブリッドプラットフォームである。オーディエンスの豊富なViewを提供。十分に活用されていないかもしれないデータリソースを活用するアプローチである。オンラインの訪問者の体験をより豊富にすることを可能にしたツールであり、顧客セグメントをよりターゲティング可能にする。

DMP構築の障害
f:id:yutakikuchi:20160306225947p:plain

  • Internal Process & Marketing Ops Challenges、No Clear Internal Owner for DMP Solution、No Clarity Into Role of DMPs in the C-Suite、Lack of Established Performance Metrics、Lack of Clear Business Case/ROI Expectations、Privacy, Security & Data Governance Concerns、Cost Concerns、Lack of Addressable Data to Fuel DMP Use、Prefer to Wait for NextGeneration Technology

内部的な承認プロセスとマーケティング運用の意欲の問題、DMPソリューションの内部的な責任者が不明確、経営者の中にDMPの役割を担う人がいない、効果指標が不明確、ビジネスケースと費用対効果の欠如、プライバシーやセキュリティとデータの契約について心配、コストが心配、十分にDMPを活用するだけの割当可能なデータの欠如、次世代技術を待つことを好む。

所感
3年前の資料を振り返ったことになるが、現在もDMPの役割としての変化はほとんど無い。ただしPrivateDMPで始まった業界もPublicDMPとなるPlayerが登場してビジネスをスケールさせると同時にデータの集め方としてアンケートモニター会社との連携、使い方としてはLPOやCRMなどの領域にも力を発揮し始めている。テクノロジー的にはDMPに蓄積されたKEY(ID)の統合によるデバイスをまたいだ人物の特定、オーディエンスの興味関心解析、リアルタイム位置情報の分析とその先のレコメンド等の分野に期待があり、それらの技術を使って付加価値の有るデータを作り出せる事がPlayerとしての差別化で重要と認識している。

機械学習の種類と特徴

人間ではなく機械が自動的に意思決定することのメリットとして、大量のデータをInputとした予測、推定、分類などの処理をAlgorithmの構築によって瞬時に行える事である。 1枚の画像だけを見て何が写っているかのような判断においては人間の脳が優れているものの、大量のデータInputを基にした組み合わせの選択や最適解に瞬時に辿り着くという目的においては機械に任せてしまったほうが効率的とも言える。昔から機械学習による予測、推定、分類などの処理は様々な手法として提案されており、どういった問題を機械に判断させるかという切り口で最適なものを人が選択する。下記表に機械学習の種類と特徴を纏めてみた。※ただし必ずしも6種類のいずれかに分類される訳ではない。例としてニューラルネットワークがあり教師あり学習であり深層学習にも位置する。

機械学習の種類 特徴 代表的なAlgorithm 備考
教師あり学習 正解を持つデータを入力とし、特定の法則に従って予測データの出力を行うこと。
(例) 男女などの正解ラベルがあるデータを入力とし、ラベルが未知のデータに対して法則を適用し予測ラベル出力する。
SVM
NaiveBayes
回帰分析
教師あり学習 - Wikipedia
教師なし学習 正解ラベルなどが無く、データそのものを解析して特徴などを出す手法。
(例) データとして距離的に近いものを同一のクラスタとして定義する。
LDA
LSI
主成分分析
K-Means
教師なし学習 - Wikipedia
半教師あり学習 正解を持つデータの数は少ない場合、正解と未知のデータを合わせて学習することで効果を高める事ができる。
(例) 教師あり学習であるSVMを拡張して既知/未知データを合わせて学習する。
S3VMs(Semi-Supervised Support Vector Machines) 半教師あり学習 - 機械学習の「朱鷺の杜Wiki」
構造学習 個々のデータに対して推定を行わずに全体のデータ構造に最適な形として個々の推定を行う。
(例) 文書のカテゴリを判断する際に形態素に分解して品詞レベルで推定するのではなく全体で推定する。
CRF 双対分解による構造学習 | Preferred Research
強化学習 学習した結果に対して得た報酬によって更に学習を強くすることが出来る。
(例) A/Bテストを行って実績が高いものに自動的に最適化を寄せる
マルコフ決定過程
BanditAlgorithm
UCB
強化学習 - Wikipedia
深層学習 ニューラルネットワークを多層化した、様々なレベルのデータを学習することが出来る
(例) 画像の特徴量を自動抽出し、画像に描かれているものを自動判する
畳み込みニューラルネット
ディープボルツマンマシン
ディープラーニング - Wikipedia

Good Product Manager/Bad Product Manager

Product Manager

Good Product Manager/Bad Product Manager はてなブックマーク -
↑は良いProductManagerとそうでないも内容のまとめ。タイトルについつい釣られて読んでしまったので日本語で起こしてみる。良い/悪いの判断なんて周りが決めることで、もし貴方がProductManagerであるならば例え途中で失敗したとしても自身のProductを成長させたいという信念を曲げずにTryしまくればいいと思いますね。

Good
市場,Product, Productの方向性と競合がどのようにうまくやっているかを知り,精通した基礎知識からの判断と信頼が必要。ProdctのCEOである。製品に対する全責任を取り,Productの成功によって自身を評価する。Productと時間と必要なすべてのものに対して責任を持つ。Contextの方向性も知っている,例えば会社,資金調達,競争等。言い訳をせずにこれらの責任を持ち勝ちプランを実行する。良いProductを良いタイミングで届けるために一緒に協力しなければならない様々な組織に対して時間の時間を全部取り上げるようなことはしない。またチームの時間をとるようなことや様々な機能のProject Manageもしない。自身はProduct TeamではなくTeamを管理する。Engineer Managerとのmarketingの窓口担当になる。ターゲットを定義して「何」(方法とは対照的な)を届けるかという管理を行う。Engineerの人たちと口頭と同じように書き込みでもコミュニケーションをする。非定型的な方向性を与えない。情報を非公式に収集する。FAQやプレゼン,説明資料などを作成する。Productの深刻な問題を発見し現実的なsolutionとして構築する。重要な問題から取り掛かる(差別化の銀の弾丸,頑丈な設計選択,厳しいPorductの決断,攻めや収益のための市場)。チームを収益と顧客に集中させる。多大な力と実行力で良いProductを定義する。インバウンド計画と到達する市場シェアと収益の目標の間に優れた価値を提供することを考える。問題の分解に優れている。プレスに扱われたいstoryを考える。プレスに対して質問をする。プレスとアナリストは賢いことを前提としている。自分の仕事と成功を定義する。訓練されているので毎週ステータスレポートを送信する。

Bad
言い訳を沢山持っている。資金調達が充分でない, Engineering Managerが優秀ではない, Microsoftは10倍のEngineering人材がいる, 自分はハードワークしている,方向性を得ていない。方法論について理解することが最善だと思う。Sales強化のために質問が殺到しそれに答えることに対して不満を言う。一日中問題の火消しになる。口頭で自身の意見を述べ、権限が無く何もできないことを嘆く。失敗を想像する。Microsoftがどのような多くの特徴を持っているかに集中させる。実現できないProductを定義したり必要なものを何でもEngineeringさせる。(それは最も困難な問題を解くこと) 価値の提供と競争力のある機能,価格,普遍性の間の差異について混乱する。全ての問題を一つに結びつけてしまう。多くの特徴をカバーと正確な技術をプレスしたいと考える。プレスのどんな質問にも答えてしまう。プレスとアナリストを区別していないく混ざっている。明白な説明を決してしない。常に誰かから何をすべきかを説明されたいと思う。ステータスレポートの送信を忘れてしまう。

scalaのimmutable

immutable or mutable, val or var

scalaでcollection(List,Seq,Set,Map,Tupple...)を扱う場合はimmutable(不変) or mutable(可変)を使うかで言語内部でのデータの持ち方が異る。また変数の宣言をval(再割当て禁止) or var(再割当て可能)を使うかで実行可否や挙動が変わる。よって2つの観点(immutable or mutable / val or var)の組み合わせで調査をする必要がある。関数型言語ではvalを利用する事が推奨され、scalaのcollectionはdefaultでimmutableが選択されている。よって自然な組み合わせはval × immutableとなり、変数を定義した後に変数に対しては再割当てが行えないので副作用無く安全な方法とされている。これにより通常valで宣言した変数に対して操作を加えた結果を格納する場合はまた別のvalで宣言する必要があるが、collectionにてmutableを用いてvalにて宣言した場合、模倣的な操作が可能なので挙動を追ってみる。

まずはcollection以外の場合、例えばStringなどはval or varのどちらで宣言しても扱うデータとしてはimmutableなので、元のデータに操作を加えた場合後は新しいデータよる再割当てを行おうとする。以下は再割当て挙動、同一性(ポインタが指し示すものが同じ)、等価性(値が同じ)、についての確認。

最初の例ではvalを使用し再割当てできないもの。immutableなのでデータ更新処理で再割当を行おうとしているが変数側のvalでエラーが表示される。

// valで文字列 scalaを代入。
scala> val a = "scala"
a: String = scala

// valで別の変数にコピー。
scala> val b = a
b: String = scala

// valなので再割当てができない。
scala> a = a + " java"
<console>:8: error: reassignment to val
       a = a + " java"
         ^

// 同一性を確認。2つの変数が同じポインタを指している。
scala> b eq a
res4: Boolean = true

// 同一が確認されているので、等価でもある。
scala> b == a
res5: Boolean = true

// valで宣言した変数に対して操作する場合は新しいvalに代入可能
scala> val c = a + " java"
c: String = scala java

次の例はvarで宣言し、再割当て可能としている。最初に定義した変数に対して更新を加えて再割当てした結果、元のデータとポインタの指し示しが異なってしまう。これこそimmutableな扱いで元のデータに対して更新は行わずに新しいデータを作成し新しいポインタで管理している。コピーした先のデータはコピー元の更新の影響を受けないので安全な管理が可能となっている。

// varで文字列scalaを代入。
scala> var a = "scala"
a: String = scala

// varでコピーを作成。
scala> var b = a
b: String = scala

// varなので再割当て可能。
scala> a = a + " java"
a: String = scala java

// コピー元とコピー先はそれぞれ違うポインタになっている。
scala> b eq a
res6: Boolean = false

// 等価でもない。aのみ更新されている。
scala> b == a
res7: Boolean = false

// aは更新済み。
scala> a
res8: String = scala java

// bは更新されていない。
scala> b
res9: String = scala

次にcollection.Setの例。まずはvalで宣言した変数に対してimmutableなSetを操作する。valで宣言された変数に対しては再割当てできない、かつimmutableなSetは自身を更新する追加メソッドが無いというエラーが出てしまう。(immutableでもvalで変数宣言するとこのメソッドは問題なく動作するという面白い挙動は以下で説明する。) Setの更新ができていないのでコピー元、コピー先は同一で等価という判定になる。この例がval × immutableなので一番制限が強いものだが、scalaではこの形式が推奨されている。

// scala, javaのSetを定義。
scala> val a = Set("scala", "java")
a: scala.collection.immutable.Set[String] = Set(scala, java)

// コピーを作成する。
scala> val b = a
b: scala.collection.immutable.Set[String] = Set(scala, java)

// pythonをsetに加えようとするがerrorになる。immutableのSetには追加メソッドが用意されていないというエラー。
scala> a += "python"
<console>:9: error: value += is not a member of scala.collection.immutable.Set[String]
              a += "python"
                ^

// 同一性を確認。2つの変数が同じポインタを指している。
scala> b eq a
res7: Boolean = true

// 同一が確認されているので、等価でもある。
scala> b == a
res8: Boolean = true

次に上のことを変数宣言varで行う。valの場合にはSetがimmutableでも自身を更新して要素を追加するメソッドが有効になる。本来これはコンパイルエラーになる問題だが、scalaがsyntax sugarを用いているためコンパイル時にa += "python"を a = a + "python"として解釈して実行している。これはaのポインタを新しいデータとして再割当てしてしているので、Stringの場合と同様にコピー先との同一性は無い。

// scala, javaのSetを定義
scala> var a = Set("scala", "java")
a: scala.collection.immutable.Set[String] = Set(scala, java)

// コピーを作成する。
scala> var b = a
b: scala.collection.immutable.Set[String] = Set(scala, java)

// pythonをsetに加えようとするが処理が行われる。valの際はエラーとなったがscalaが文法を解釈。また元のデータに対して更新を行うのではなく、新しく割当を行っている。
scala> a += "python"

// コピー元とコピー先はそれぞれ違うポインタになっている。
scala> b eq a
res10: Boolean = false

// 等価でもない。aのみ更新されている。
scala> b == a
res11: Boolean = false

// aは更新済み。
scala> a
res12: scala.collection.immutable.Set[String] = Set(scala, java, python)

// bは更新されていない。
scala> b
res13: scala.collection.immutable.Set[String] = Set(scala, java)

次に変数の宣言をvalで行いSetをmutableとして指定する。mutableの場合は自身のデータ更新が可能なのでポインタの指し示す先が変わることが無い。よって変数がvalであっても再割当てを行わないので、自身のデータがそのまま更新され、更にはコピー先のデータにも依存して内容が反映される。

// scala, javaのSetを定義。
scala> val a = scala.collection.mutable.Set("scala", "java")
a: scala.collection.mutable.Set[String] = Set(java, scala)

// コピーを作成する。
scala> val b = a
b: scala.collection.mutable.Set[String] = Set(java, scala)

// pythonをsetに加えようとするが処理が行われる。変数に対しては再割当ては行われず、自身のデータを更新している。
scala> a += "python"
res14: a.type = Set(python, java, scala)

// 同一性を確認。2つの変数が同じポインタを指している。
scala> b eq a
res15: Boolean = true

// 同一が確認されているので、等価でもある。
scala> b == a
res16: Boolean = true

// aとbの両方が更新されている。
scala> a
res17: scala.collection.mutable.Set[String] = Set(python, java, scala)

// aとbの両方が更新されている。
scala> b
res18: scala.collection.mutable.Set[String] = Set(python, java, scala)

最後に変数をvarで宣言してもvalと同じ結果が得られるが、意味が少し異なる。varの場合は自身のデータも更新と再割当ての両方を行っている。ただしmutableで割当てとしての変更が無いため同一のものを再割当している。

// scala, javaのSetを定義。
scala> var a = scala.collection.mutable.Set("scala", "java")
a: scala.collection.mutable.Set[String] = Set(java, scala)

// コピーを作成する。
scala> var b = a
b: scala.collection.mutable.Set[String] = Set(java, scala)

// pythonをsetに加えようとするが処理が行われる。自身のデータを更新しつつ、再割当てを行っている。
scala> a += "python"
res19: scala.collection.mutable.Set[String] = Set(python, java, scala)

// 同一性を確認。2つの変数が同じポインタを指している。
scala> b eq a
res20: Boolean = true

// 同一が確認されているので、等価でもある。
scala> b == a
res21: Boolean = true

// aとbの両方が更新されている。
scala> a
res22: scala.collection.mutable.Set[String] = Set(python, java, scala)

// aとbの両方が更新されている。
scala> b
res23: scala.collection.mutable.Set[String] = Set(python, java, scala)
まとめ
  • varで変数宣言した場合には同一の変数に対し再割当て可能。
  • valで変数宣言した場合には同一の変数に対し再割当てはできない。
  • collection.immutableを使用するとデータの更新を行う際は新しいcollectionデータを作成し割当を行おうとする。
  • collection.mutableを使用するとデータの更新を行う際は自身を更新して新しいcollectionデータの作成は行わない。
  • varで宣言した変数に対してcollection.immutableの追加更新メソッド(+=)をコンパイラが良しなに解釈して実行する。ただしvalで宣言するとコンパイルエラーが出力される。理由はcollection.immutableにて新しいデータの作成し再割当てを行おうとしているから。
  • 制限の強い順に組み合わせを上げるとすると val × immutable, var × immutable, val × mutable, var × mutableとなり、イメージとしてはimmutable or mutableの使い分けの判断が重要となる。
  • scalaドキュメントにもcollectionのimmutable/mutableの違いが分かりやすい説明として載っている。(下記引用)Collections - 可変コレクションおよび不変コレクション - Scala Documentation はてなブックマーク - Collections - 可変コレクションおよび不変コレクション - Scala Documentation
    • Scala のコレクションは、体系的に可変および不変コレクションを区別している。可変 (mutable) コレクションは上書きしたり拡張することができる。これは副作用としてコレクションの要素を変更、追加、または削除することができることを意味する。一方、不変 (immutable) コレクションは変わることが無い。追加、削除、または更新を模倣した演算は提供されるが、全ての場合において演算は新しいコレクションを返し、古いコレクションは変わることがない。

mysqlでgroup毎のTop-K行を取得する方法

How to select the first/least/max row per group in SQL · Baron Schwartz's Blog はてなブックマーク - How to select the first/least/max row per group in SQL · Baron Schwartz's Blog
mysqlを用いた特定のgroupに所属する行を一定数ずつ(もしくは何かしらでsortされたTop-K行)取り出したいという問題がある。これしきの事、単純なgroup byを使って簡単に解きたい内容であるがちょっとしたテクニックを必要とする。調べたところ以下の解決方法がある。
1. union allを使ってgroup毎に抽出した結果を結合。
2. tableをgroupで自己結合し特定行数取得。
3. session固有のユーザ定義変数を使って特定group内の行をcountしていく。

因みにposgre/sql serverはrow_number()というgroup毎に数を採番してくれる便利関数が存在してこれを利用するらしいが、mysqlにはまだ無い様子。

解決方法1の場合は各group毎に特定行抽出した結果をunionするのでgroupが増えるとQueryが冗長でダサい。2の場合はgroupのcross結合を行うのでgroupに紐づくデータが膨大だとつらい。よってここでは 3.session固有のユーザー定義変数を使って...について簡単に紹介する。

下はidの昇順にてTop-10を出している。最初の行でsession固有の変数を定義している。SQL中の@group = media_idがGroupの指定。group変数が未定義の場合は1を同一の場合にはnumをincrementしている。subquery内のrow_numberがincrement数なので最後のwhereにてrow_numberが10以下を指定するとTop-10を抽出できる。rand()にてgroup内からrandomで特定行数抽出したい場合はsubquery内のsubqueryで最初にrand()しておくと良い。

set @K := 10, @num := 0, @group := '';
select
  id,
  media_id
from (
  select
    id,
    media_id,
    @num := if(@group = media_id, @num + 1, 1) as row_number,
    @group := media_id as mid
  from
    contents
  -- randomに切り替えたい場合はfromとして下記を利用
  -- from (select id, media_id from contents order by rand()) as c
  order by
     media_id
) as t
where 
   t.row_number <= @K;

ただし上の例だとsubqueryを使っていてtemporary tableになってしまうのと、whereによる絞り込みなのでデータ数に依存して計算コストが掛かってしまうことが懸念される。これらの問題解決とSQLをすっきりさせるためにもgroup byとhavingを使った例が以下のもの。しかし実行速度パフォーマンスは手元の環境では10000件程のテストデータだとどちらもほとんど差は無かった。

set @K := 10, @num := 0, @group := '';
select
  id,
  media_id,
  @num := if(@group = media_id, @num + 1, 1) as row_number,
  @group := media_id as mid
from
  contents
-- from (select id, media_id from contents order by rand()) as c
group by
  id, 
  media_id
having 
  row_number <= @K;

オンライン広告におけるアトリビューション分析の必要性

f:id:yutakikuchi:20151224011111p:plain

オンライン広告の評価

ダイレクトレスポンスといったオンライン広告配信を行い広告Clickからの次のActionを求めるような商材の場合、CPA(Cost Per Action/Acquisition)、ROAS(Return On Adevertising Spend)というCOST指標を用いて広告Vendorやキャンペーン評価を行うのが一般的である。この指標を出すためにConversion数(Action数/Acquistion数)を計測が必須で、InternetUserがClickした広告と紐づく直接Conversion、広告はClickせず表示のみを行ったアシスト数の間接Conversionに分けられ、現状ほとんどの広告主が前者の直接Conversionのみを見てCOST指標を評価している。直接Conversion数を出す際によく問題として発生するのが、広告主側でのConversion計測と各広告配信Vendorのレポート数に乖離が発生してしまう点である。乖離の発生原因は直接Conversion計測のやり方と定義の違いである。

まずはConvesion計測のやり方の違いについて言及する。広告主側では広告効果測定ツールというものを導入しており、広告のクリックURLやパラメータに配信Vendorを識別するものを含めInternetUserの広告Click後Conversion完了するまでその識別子を引き回して計測する。こうすることによってどの配信Vendor経由で直接Conversionに寄与したか判別可能となる。その一方で各広告配信Vendorが計測できることは自身が配信した広告のLast Clickと直接Conversionが発生した事実のみで、InternetUserにおける本当のLast Clickというものを各配信Vendorの計測はできていない状況にある。

次に直接Conversionの定義である。各配信Vendorは自身が配信した広告のLast Clickから規定日数以内に直接Conversionが発生したかを計測している。この規定日数が配信Vendorと広告主で異なり、更にはConversionとして認めるInternetUserの属性(新規Userのみ認め、リピーターは除外する)も影響する。この定義差を埋めるために配信VendorのAccount Executiveが配信レポートを提出する際に極力広告主側の定義に合わせているが、それでも上記の計測方法が異なるので完全な一致にはならない。

ダイレクトレスポンスにおける広告配信Vendor間の競合

広告主は複数の広告配信Vendorを利用している事が多く、ダイレクトレスポンスによるリターゲティングを行っている場合は、1requestにおける配信獲得を目指してVendor間で最悪の場合同じ広告主のほぼ同じクリエイティブでImpressionの奪い合いが発生している。差別化のポイントは確実にConversionするInternetUserに対して無駄な予算を使うことなく適切なタイミングで適切な配信面に届けられているかという点になる。この背景に配信在庫に対してImpressionを幾らで入札するかというBidding Priceの精度が大きく関わっており、多くのVendorがMachineLearningを利用したBidding Priceの最適化を行っている。このVendor間の成績をCOST指標で評価してしまうと、Bidding力で勝るVendorに予算がアロケーションされて局所的な最適化が起こってしまう。局所的な最適化の一番の問題はCPAを合わせるために配信Vendor、運用者(代理店も含む)が動いてしまうので、最終的なConversion数を延ばすという点においてこれらの広告では貢献できなくなってしまう。更にこの状況が続くとオンライン広告市場全体としても喜ばしく無いはずである。どの配信Vendorも確実にConversionするInternetUserに対してはHigh Priceの最適化(局所的な高単価CPM)が行われているが、広告主として全体COSTを下げる必要があるので収益観点においては逆の立場である配信Vendor,Publisherは高単価が扱いづらいことになる。

日本のRTB広告在庫の使われ方

日本のPublisherが純広告を抱え込み広告在庫をRTB Player等に積極的にならない原因としては日本のRTB在庫利用がダイレクトレスポンスに偏ってしまっている事が考えられる。上で説明したようにダイレクトレスポンスを在庫に入れると高収益性への期待が薄くなる。各RTB Playerも広告主による焼き畑作業が続くと苦しい一方なので、今後ブランド広告を収益の軸とすることも考えなければならない。RTBの仕組みとしてブランド広告を特定のPublisherに高単価で提供するPMP(Private Market Place)等の仕組みも登場してきているので今後の注目株である。PMPを普及させるためにもRTB Player ≠ リターゲティングのようなイメージをDemand側に啓蒙しなければならない。USの方ではブランド広告をRTB在庫として扱い、収益化に成功している様子。

カスタマージャー二データを用いたアトリビューション分析

Conversionに至るまでの自然検索流入、純広告Impression、アフィリエイト広告Impression、広告Click等の複数チャネルに接触した履歴全てをまとめたカスタマージャーニーデータをアトリビューション分析では利用する。目的としては単純なCPA,ROASのラストクリックを獲得した広告Vendorの評価だけではなく、InternetUserの態度変容に対して各施策がどれだけ寄与したのかを中間指標としてスコアリングし、今後のマーケティング施策全体をどのように設計するかを考えることである。ただしアトリビューション分析がCPA,ROAS評価と比べると一気に難易度が高くなる。なぜならばオンライン施策がオフラインへ購買へどれほど起因したかのシチューエーション問題だけでなく、InternetUserを分析するのかPublisherを分析するのか、それらを対象とする分析のフレームワークやMdelingなど数理統計学の知識を必要とする。アクセス解析ツール側で分析Modeling手法を含んで可視化Solutionとして提供するものも存在するが、複雑すぎて運用者側が使いこなせていない印象がある。今後は広告Vendor側でも分析ツールフレームワークを提供し、InternetUserの態度変容の可視化とマーケティングシナリオの自動化など運用者負荷を減らす施策が行われてくると予想される。