Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

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の態度変容の可視化とマーケティングシナリオの自動化など運用者負荷を減らす施策が行われてくると予想される。

AdExchangeとSupply Side Platform(SSP)との違いって何よ?

www.slideshare.net

What is the difference between ad exchanges and supply-side platforms? - Quora はてなブックマーク - What is the difference between ad exchanges and supply-side platforms? - Quora

説明に困るAdExchangeとSSPの違い。ポジションレイヤー的な話だとAdExchangeもSSPともにDSPやADNetworkを束ねてPublisher側に広告を流す仕組みであり、この点だけを述べてしまうとほとんど差異が無いように思われる。また現在に至っては使われ方もほとんど同じと言える。(細かい話だとAdExchangeはDSPを束ねてSSPと接続をする場合もあるがここはあまり意識されない。) Quoraを調べていたら2つの違いについて適切な解答があり、最もupvoteが付いているものを読んでみた。結論としては作られた目的が異なる。AdExchangeは薄利なレムナント在庫を自動管理するもの、SSPは単価の高い広告を適切な在庫に流してPublisherの収益最大化を行う。以下は大体の翻訳。

AdExchangeはStock Exchangeを例としたトランザクションを促進する自動化プラットフォームである。用途としては主にレムナント在庫に使われる。レムナント在庫は余剰在庫なので価値がとても低いから人的なリソースを使わずに売りたい。AdExchangeは薄利なので配信量を多くすること頼っている。SSPは供給サイドのサービスでTechnology Platform/Service/Sales(人)のコンポーネントの組み合わせである。彼らは複雑かつExchangeとは取引をしないような大規模なPublisher,DSP,広告主と関係を保っている。Publisherとしては自身のビジネスに専念できるし、扱いたい広告vendorの数を制限できる。(しかし注意しなければいけないこととしてはPublisherはスーパープレミアムな在庫はSSPに開放せず別途持っていてインハウスのSalesチームにBig Brandとして売らせている。) SSPは広告主の沢山の広告をRealTimeBiddingによって提供するようなInterfaceを持ち、Publisher側の個々のadspotの価値を戦略的に最大化させる。SSPはDMPなどのlayerと接続可能なのでAdExchangeより多くのGross Marginを得ている。(注意しなければいけないことはSSPはAdExchangeより様々な面での高いコストを支払っている。)

Defining SSPs, Ad Exchanges And Rubicon Project | AdExchanger はてなブックマーク - Defining SSPs, Ad Exchanges And Rubicon Project | AdExchanger

上のリンクはAdExchangeとSSPとRubicon Projectの定義。以下は大体の翻訳

AdExchangeとSSPはかつては異なるものであったが段々と区別が困難になりつつあり、補完的な技術は統合されている。SSPが登場した頃、AdExchangeとSSPの違いはAdtech vendorの間ではとても重要な内容だった。デジタル市場の動きがとても速いという理由もあって特徴的な名前付けをする必要があった。SSPとAdExchangeの統合は新しいことではなく、GoogleSSPのAdmeldとDoubleClick AdExchangeを統合している。歴史的な違いとしてはAdExchangeはトランザクションを有効にする一方で、SSPはPublisher側に価格調整機能などの多くのToolを提供してAdExchangeと同じことを行う。長い間様々なPlayerを見ていると、特定の市場空間にいる大体の会社がより優れた顧客サービスをできるようにツールの開発や機能提供を行う。Rubiconは収益最大化を目的としたSSPとしてスタートしたはずが、彼らが十分な在庫を持っていたならば、自然とAdExchangeの機能を統合している。この産業の誰もがmedia platformerであって、全てのPublisherが喜んでいない状況である。SSP,AdExchange,DSPやAdnetworkの統合は周囲(広告主やPublisher)を混乱させる。

Recsys2015で発表されたCriteo社の最新レコメンド情報を読む

www.slideshare.net

criteo社のRecommendation Logic

Criteo社の広告枠への配信に対するCTR/CVR予測モデルの話以外にもRecommendLogicに関する発表がRecsys2015であったので見てみました。一般的なRecommed Systemでは良く見受けられる構成や手法なのでインパクトがある内容ではありませんが共有します。Keywords : Logistic Regression, Hadoop, Memcached, collaboration filterling, Recsys2015,
Criteo社のCTR/CVR予測モデルは下記論文などを参照 Simple and scalable response prediction for display advertising はてなブックマーク -

Criteo社の説明とインフラ
  • 2005年に設立、フランスに本社を置き世界に社員1700人(そのうちEnginnerが300人)、100億のUniqUserを持つ。
  • 秒間80万のHTTPリクエスト、29000インプレッション、RTBの処理を10ms、Recommendの処理を100msでこなす。
  • 3つの大陸にインハウスのデータセンターが7つ。サーバー15000台、ヨーロッパに巨大なHadoop Clusterがある。35PBのBig Dataがある。
Criteo社のデータソース
  • 商品カタログデータが広告主ごとに100万ほど。その広告主を10000社持つ。
  • インターネットユーザーの行動履歴のイベント数が毎日2B。
  • 広告表示やクリックなどのイベントデータが毎日20B。
Recommend Logic
  • やりたいこととしてはRecommendの関数にインターネットユーザーを入れた時に一番のオススメ商品が出るようにしたいが、実際のところ複数の商品が出るし、新鮮さも保たなければならない。
  • できることとしてはOfflineで事前に商品の推薦を選んでおき、OnlineでRecommendationを決定する。
  • Offlineで広告主からインターネットユーザーの行動ログを送ってもらい、商品ランキング/カテゴリ商品ランキングを定め、商品閲覧の共起から類似商品を導き出し、商品購買の共起から補足商品を推薦する。
  • インターネットユーザーが商品Xを閲覧した時の推薦する候補は以下のもの
    • 閲覧した商品Xそのもの。(直接商品)
    • 他のインターネットユーザーが商品Xと閲覧共起しているもの。(類似商品)
    • 他のインターネットユーザーが商品Xを閲覧した上で購入したもの。(補足商品)
    • 広告主のサイトで最も見られて/買われているもの。(売れ筋商品)
System Overview
  • 4時間おきに広告主から商品カタログデータを貰い、Memcachedに入れる。
  • 広告主サイト側でのインターネットユーザーのイベントログを送ってもらい、商品アイテム推薦を導き出すためにHadop MapReduceにかける。MapReduceされた推薦データは12時間おきにMemcachedに入れられる。
  • 広告表示/クリック/コンバージョンデータを6時間おきに取得し、それを基に予測モデルをHadoop上で更新する。
  • Recommendのリクエストが来るたびに、インターネットユーザーのデータを用いて推薦アイテムを商品カタログから参照する。
  • 機械学習の予測モデル(おそらくクリックやコンバージョン予測)はLogistic Regressionを利用している。なぜならばLRはスケールするし、速いし、たくさんの特徴を扱うことができる。(bitのhash magicを使うなどして)
  • Memcachedに入れられた類似商品、最も見られている商品、最も買われている商品をスコアリングして高いものから推薦する。
Recommend Logicの評価
  • オンラインABテストを行う際はインターネットユーザーの50%ずつにそれぞれのモデルを適用するが、これらは以下の理由により煩わしい。
    • すぐに多くのお金を失う。
    • テストの期間が長くなってしまう。信頼がおける期間は2週間ぐらい必要。
    • ソースコードを本番同様にしなければならない。
    • インフラ的に高負荷になってしまう。
    • 広告主のアカウントがそこまで十分な時間をくれない。
  • その代わりとしてOnlineのログを使ったテストフレームワークがある。
  • しかし自分たちで管理するデータしかもっていない。(外部データは非常に高価なため)
  • それでも私達は完全な間違いをしないことの確信がある。
  • Onlineのパフォーマンスを上げるためにOfflineテストの最善策を見つけなければならない。以下は参考論文 Counterfactual Reasoning and Learning Systems はてなブックマーク -
今後のUpdate
  • より長期的なUserのProfileデータを活用する。
  • より多く/より良い商品情報を利用する。(画像、文脈、NLP)
  • 類似商品計算のUpdate。
  • 商品スコアリングの結合。
  • 私たちはClick予測のデータを公開している。
    • 4GB display-click data : Kaggle challenge in 2014 http://bit.ly/1vgw2XC
    • 1TB Display-Click data (industry’s largest dataset) : http://bit.ly/1PyH4Vq
      • 4 billion of observations
      • 156 billion feature-value
      • available on Microsoft Azure
      • used by edX (UC Berkeley)

アジャイル開発の導入に向けた備忘録

SCRUM BOOT CAMP THE BOOK

SCRUM BOOT CAMP THE BOOK

アジャイルサムライ――達人開発者への道

アジャイルサムライ――達人開発者への道

SCRUM BOOT CAMPアジャイルサムライ

このブログも勉強したことの纏めサイト的なものになってしまってきているので、体験談や自分の考えも纏められるようにしていきたいですね、、、。今回はアジャイル開発手法の1つであるSCRUMについて計画,実施,振り返りを行う機会があったので、新しいインプットとしてSCRUM BOOT CAMPアジャイルサムライを読んでみました。過去に独自色の強いアジャイルを試したことはありましたが、コミュニケーション時間の増加および課題の明確化ができるたものの、アジャイルの学習や進行に費やした時間に対するプロダクト成果まで結びつかず途中で挫折しました。その経験からチームビルドを半ば諦めて個人の力で打開する雰囲気作りをしていた節があったので、これを機にもう一度教科書を読んでから考え直してから実践したいと思います。掲載している内容は自分の言葉で置き換えておりますのでご注意ください。

SCRUM BOOT CAMP
  • 事前に全てを予測するのは不可能。そこから計画することはできない。 という事が前提。
  • 要求の分析や設計には時間をかけず、重要なものやリスクが高いものから先に作る。
  • 要求の実現順、問題点を明確化、もっと良いやり方の適応などを意識する事。
  • 開発チームの規模は3〜9人ぐらいがベスト。
  • スプリントは短くて1週間、長ければ4週間。週単位で区切る場合が多い。
  • スプリントにおいて開発する量は過去の実績値(velocity)を元に予測。
  • スプリント計画で合意した内容に全力を尽くすが、完了を約束するわけではない。
  • スプリント単位でリリース判断可能なプロダクトが求められる。完了の定義を事前に明確化し、途中での削除は避ける。
  • スプリント内では毎日の状況確認。
  • スプリント内で出来上がった動作するプロダクトを確認する。スプリントレビューはプロダクトオーナーに対してデモを披露する。
  • スプリントの最後に振り返り(スプリントレトロスペクティブ)を行い、もっと成果を出すためのプランを出す。
  • プロダクトオーナーとスクラムマスターの兼任は避けたほうが良い。プロダクトオーナーは製品を良くすることを考え、スクラムマスターは開発を円滑に進める。
  • プロダクトバックログのためにインセプションデッキを作成する。インセプションデッキのテンプレートは以下にある。
  • プロダクトバックログは全員が必ず理解する。
  • プロダクトバックログの工数や予算は実際に作業する担当者が見積もる。見積のズレは必ず発生するので、時間をかけずに行う。基準となる作業を見つけて相対的な見積をする。当てずっぽうの見積の中でベストを尽くす。
  • スプリント内で実現しようとするプロダクトバックログの量が多いと大変で良くない傾向なので、確実に終わらせる事ができる項目数を定義する。
  • デイリースクラムが単純な進捗報告会とならないように、問題を見つけるように工夫する。問題が出てきたらデイリースクラムの後に関係者で集まって対応を考える。
  • スプリントレビューではデモを目で見て、本当はどうすべきかを確認する。デモと完了の定義を比較して終わっているかも合わせて確認する。完了の定義はチーム内で合意をしていないといけない。
  • 問題に対しては個人でなんとかしようとしがちなので、チーム全員で対応すべき。
  • タスクボードを使ってTodo,Doing,Doneを分かりやすくする。
  • バーンダウンチャートを使って縦軸に見積もり時間の合計、横軸に営業日を記録し、最終日が0になるような折れ線グラフを作る。これが理想線となり、実際のタスクの実行時間をプロットして理想線と比較する。
  • スプリントを旨く回すために自分たちでルールを決めても良い。
  • velocityに求められのは安定性。安定していないvelocityは予測に使えない。velocityを上げていくことだけを意識していくと悪影響がでる。
  • みんなをサポートしてプロジェクトの目的を達成していくのがスクラムマスターの仕事、サーヴァントリーダシップと呼ばれる。またスクラムマスターはあらゆる妨害を見つけて取り除く。
  • 良いスクラムマスターだと妨害リストに50個以上項目を管理している。妨害リストはチームが見えるところに貼っておくと良い。
  • プロダクトバックログは日々更新されるべきで、いろいろな意見が集まるように誰でも更新できるようにしておくと良い。プロダクトバックログを観て削除できるものは優先度を下げたり諦めるなどをする。
  • 開発メンバーのプロジェクトを進めるスキルがあるかどうかを判断するためにスキルマップを書いてみると良い。開発メンバーの性格や得意/不得意を知った上で各メンバーとこれまでどんなプロジェクトにいたか、仕事で重要視すること、期待されていることは何かを話し合っておくことも重要。
  • 失敗を重ねて学んで行く。成長しないスクラムチームではプロジェクトがうまくいかない。失敗を繰り返さないように学んでいく。
  • 通常のスプリントの後でリリースの前にリリーススプリントをやることも初期のスクラムチームでは採用される。リリースに必要なことを片付けるための期間。
アジャイルサムライ
  • チームの持てる力を最大限に出すことでプロジェクトの成功確率を向上させる。
  • 本当に価値があるものに対して集中し、余分なものは捨てて身軽になる。
  • アジャイル開発は気弱な人には合わず、隠すことが無い、質の高い仕事へ情熱を持つこと、価値を生み出すことを期待するのであるならアジャイルを採用することによって得ることは多い。
  • プロジェクトの3つの真実。1.プロジェクトのスタートでは全ての要求を決めれない、2. 要求はどれも変わる、3. やる内容は時間と資金より常に多い。
  • チームを縦割り組織にしないで、役割分担を区別しない、継続的な開発、チームで責任を果たそうとする態度の3つが大事。
  • ビジネスを理解しているプロダクトオーナーと開発者は日々一緒に働かなければならない。
  • 人に合わせて役割を決めることがチームビルディングのコツ。
  • 自分たちで計画を立てることで当事者意識を持たせる。
  • “最良のアーキテクチャ・要求・設計は,自己組織的なチームから生み出される”
  • 良い組織状態はアジャイルプロジェクトマネージャーが1週間いなくても業務に支障がでないこと。
  • 我々は何故ここにいるのか、司令官は何を考えているのかを把握する。
  • リスクを全て洗い出す。リスクを分類して解決に取り組む価値のあるリスクを取り除く働きをする。
  • 時間と予算は有限、品質は高いものでないといけない、やるべきことが際限ないという4つのフォースがプロジェクトを支配している。
  • 文書に頼らず顔を合わせて話してすこともアジャイル開発の原則。
  • 良いユーザーストーリの6つの要素。1. 独立(Independent)、2.交渉可能(Negotiable)、3.価値ある(Valuable)、4.見積もり可能(Estimatable)、5.小さい(Small)、6.テスト可能(Testable)。これらの頭文字でINVESTと呼ばれる。
  • プロジェクト初期段階での概算見積もりは最大4倍ほどの差があると思っておくこと。
  • 人は相対見積もりだとうまくいく。絶対見積だと難しい。仕事の大きさを相対的な数値として捉えられることが重要。大きさを小、中、大の3つに分類し、それぞれ1pt、3pt、5ptなどのように定義する。基準となるストーリーを1つずつ決め、残りのストーリーはそれと同じ基準で当てはめて考える。
  • 見積もりを行うときにプランニングポーカーを利用しても良い。チームメンバーの意見を聞く事が可能。
  • アジャイルでは計画の見直しとしてリリース期日を延ばすことよりスコープを柔軟に対応することのほうが多い。
  • team velocity = 完了したストーリー数 / イテレーション数が通常の計算だが、実際の現場では以下のようになる。team velocity = 完了させたスローリーポイント数 / イテレーション数。
  • バーンダウンチャートとバーンアップチャートのどちらかを採用して見える形でプロジェクトへの期待をマネジメントする。
  • プロジェクトの途中からアジャイルを導入することも可能。

WORK RULES! はGoogleでの採用やマネジメントが分かる良本

ワーク・ルールズ!―君の生き方とリーダーシップを変える

ワーク・ルールズ!―君の生き方とリーダーシップを変える

内容の覚書

Googleにいらっしゃる人事担当/上級副社長?のラズロボックさんが書いた本。最近の僕のtopicsはチームメンバーと自分が同じ方向性で共に成長できるかどうかということ、それに対する経営者やリーダーやマネージャーとしてのあり方というものであり、この本でもその点に注意して読んでみた。訳者の意訳力もあるのか、かなりスラスラ読める本なのでお薦め。忙しい人は冒頭と14章だけ読んでみると良いかもしれない。最高の人材(人財)を採用しチームとして機能させるための並々ならぬ努力が読み取れる。

  • マネージャーはチームに奉仕し、現場の障害を取り除いてチームが躍動することに集中する。
  • 最高の創業者は他の創業者が自分と並び立つ余地を生み出す。会社員でも自分を創業者とみなし行動する。
  • ミッションが個人の仕事に影響を与えるのは事業目的ではなく、道徳だからである。歴史上大きな力を振る舞った運動は道徳的な動機を持っていた。ミッションへの信頼が共有されているためほとんどのグーグラーは結束している。
  • 社員の発言や意思決定を重要視する。(余談:中国での検索結果検閲の判断についても社員からの意見に耳を傾けた。www.google.cnはサービスを閉じたが、www.google.hkは継続している)
  • 一般的な企業の場合は社員教育資金や時間など力を注ぐが、Googleの場合は上位10%に入る求職者を採用し、その後の手間をかけずに済ませる。採用費用は平均的な企業の2倍ほど。
  • 何らかの点で自分より優れた人だけを雇う。
  • アイビーリーグの平均/平均以上の卒業生より、州立学校をトップで卒業した聡明で勤勉な学生を採用したい。過去にやり遂げたことをに比べてどこの大学を出たかはさほど重要ではない。
  • 単純に賢いからという理由で採用するのではなく、一緒に働く全ての人を成功に導いてくれる人を採用する。
  • 本当に優秀な人は仕事を探していない、在籍している会社に満足しているし十分な報酬を得ている。そこでテクノロジーの力を利用して最高の人材を探し出すヘッドハンティングを行う。(gHire)
  • 面接者は最初の5分間で評価を行い、それ以降の時間は最初の評価を確認するための時間として費やす。
  • 人の職務能力を予測するための最善の指標は日々の業務内容と似た仕事(ワークサンプルテスト)を与えること。
  • 自己複製採用マシーンを作成するための4つの事。1. 採用候補者の人材の質/基準を高く設定する。2. 社員が自分自身で採用候補者を見つける。3. 採用候補者を客観的に評価する。4. 採用候補者に入社すべき理由を伝える。
  • 人材の質を確保するためにはあらゆる圧力には屈せず闘う。
  • 「権力は腐敗する。絶対的な権力は絶対腐敗する。」権力を持つものは持たないものより道徳的規範を持たなければならない。
  • マネージャーの権限が少なければ少ないほどチームが取り入れるべき自由裁量の余地は増えることになる。
  • マイクロマネジメントはミスマネジメント。
  • 常識はずれの野心的目標を設定して失敗したとしても、きっと何か素晴らしいことをやり遂げたことなる。
  • Googleでは各個人のOKRを確認することができる。
  • 人間の本質を変えるためのマネジメントではなく、仕事を変えるためには何が必要かということ。
  • マネージャーの仕事は人々が働く意味を見つけることをサポートすること。
  • スター社員を分析して他の社員より成功している理由を見つける。
  • 業績が低い人への思いやりも忘れてはいけない。採用のプロセスが適切ならその人への役割の与え方が間違っている。学習を支援して新しい役割を見つける。
  • 人生で最低/最高の瞬間に出くわしたとしても自分より寛大な組織が後ろに居てくれると分かるだけで慰めになる。
  • 評価決定前にマネージャー陣が集まって部下の最終評価を検討するキャリブレーションがあるので公平な評価が可能。
  • 社員の評価においてボトムテールの人々の改善に投資をすることはチームの改善に繋がる。それでも業績を上げない場合は退職して別の会社で成功を収める。
  • パフォーマンスの高さは状況に依存するので、他の職場でうまくいっていても新しい環境でうまくいくとは限らない。
  • エンジニアは管理されることを嫌う。彼らはマネージャーの事が嫌いだし、マネージャーになりたくないと思っていことも確か。
  • 優れたマネージャーの8つの属性。1. 良いコーチであること。2. マイクロマネジメントをしないこと。3. メンバーの成功や満足度に関心を示すこと。4. 生産性/成果思考であること。5. 話を聞いて、情報を共有すること。6. チームメンバーのキャリア開発を支援。7. 明確な構成と戦略を持つこと。8. チームに対して助言できる技術スキルを持っていること。この中でも技術的な専門知識は重要度が一番低い。
  • ある分野で専門的な知識を得るためには1万時間が必要。ただし1万時間の長さではなく、どう使うかが重要。少しでも確実にのこるものを学ばせるほうが賢い投資。
  • フィードバックのない反復はモチベーションが向上しないし進歩しない。組織やチームの学習効率をあげる方法の一つとして学習するスキルを細かい要素に分けて具体的なフィードバックに返すこと。更には学習がもたらした結果を測定する。
  • 最善の学習方法は教えること。
  • 外発的動機づけの報酬体系を洗練させ、4つの原則が生まれる。1, 報酬は不公平。2. 報酬ではなく成果を称える。3. 愛を伝え合う環境づくり。4. 思慮深い失敗に報いる。
  • 最も優秀な人でも失敗するので、失敗にどう対応するかが問題になる。またリスクを賞賛しないと誰もリスクを取らなくなる。
  • 社会的構造の隙間にいる人ほど素晴らしいアイディアを持っている可能性が高い。
  • 意思決定のエネルギーはここぞという時に使うべき。自分をパターン化すること。些細な事に気をとられていたら仕事が終わらない。