Ahogrammer

Deep Dive Into NLP, ML and Cloud

今日からはじめるレコメンデーション -Hacker Newsに学ぶスコア関数の設計-

レコメンデーションといえば、現在最も多く使われている技術の一つと言えるでしょう。その応用は数多く存在し、身近なところで言えば、Amazonによる関連商品の推薦やNetflixによる映画の推薦などに使われており、私たちの意思決定を支援しています。

一口にレコメンデーションといってもそのやり方は様々です。古くは行列分解を用いた手法から最近では機械学習、特にディープラーニングを用いた手法が多数提案されています。今回はその中でも手動で設計したスコア関数を使った手法についてHacker Newsを例に紹介します。大きくは以下の3つを紹介します。

  • 人気度に基づく手法
  • 新規性に基づく手法
  • ハイブリッドな手法

人気度に基づく手法

人気度(Popularity)に基づく手法というのは「他の人が好きなコンテンツなら、あなたも好きに違いない」という考えに基づいて推薦を行う手法です。たとえば、Netflixのようにユーザに映画を推薦する状況について考えてみましょう。世界的な映画データベースであるIMDbによると、2019年現在、最も評価が高い映画は「ショーシャンクの空に」、「ゴッドファーザー」「ゴッドファーザー2」の順番になっています。したがって、人気度に基づく手法ではこれらの映画をユーザに推薦します。

f:id:Hironsan:20190409083643p:plain
Movie ranking by IMDb

人気度に基づく手法を実装するのは難しくありません。もし、SQLを書いて実現するなら、以下のように書くことでユーザに推薦する候補を得られるでしょう。

SELECT movie_id 
FROM   movies 
ORDER  BY rating DESC;

人気度に基づく手法はシンプルですが問題点もあります。たとえば、私たちがイタリアに旅行した際にレストランを探しているとします。そのとき、人気度に基づく手法ではマクドナルドが推薦される可能性があります。私はマクドナルドのチーズバーガが好きなのですが、イタリアに来ているならピザやパスタを食べたいですし、そもそも誰もが知っているマクドナルドを推薦する必要があるのかは疑問です。

その他にも人気度に基づく手法では自分の好みに合わない候補が推薦されることがあります。たとえば、音楽を推薦する際にオリコンの週間ランキングから推薦した場合、少なくとも私の好みには全くあっていません。

f:id:Hironsan:20190409085208p:plain
オリコン週間シングルランキング 2019年04月08日付

また、Hacker Newsのようにニュースの推薦を行う場合にはコンテンツの新しさを考慮する必要があります。というのも、いくら人気の記事でもユーザは3年前の記事を読みたくはないだろうと考えられるからです。そういうわけで次に紹介するのが新規性に基づく手法です。

新規性に基づく手法

新規性(Recency)に基づく手法では、作成あるいは更新日時が新しいコンテンツをユーザに推薦します。たとえば、ニュースのように時事性の高いコンテンツを推薦したりする際には新規性を考慮します。技術者にとって身近なところでは、Hacker Newsのnewestは新規性に基づく推薦と言えるでしょう。

f:id:Hironsan:20190409090147p:plain
Newest news by Hacker News

新規性に基づく手法を実装するのは難しくありません。もし、SQLを書いて実現するなら、以下のように書くことでユーザに推薦する候補を得られるでしょう。

SELECT news_id 
FROM   news 
ORDER  BY created_at DESC;

新規性に基づく手法はシンプルですが問題点もあります。たとえば、有用でない記事が新しいというだけの理由で推薦されてしまいます。こうなると、スパムによってそのランキングは支配されてしまうでしょう。また、新規性に基づいて記事を推薦する場合、自分の全く興味のない分野の記事が推薦されることがあるでしょう。この問題に対して、プログラミングの知識を共有できるサイトQiitaではユーザが自分の興味のある分野のタグをフォローすることで、推薦される記事を絞り込んでいます。

f:id:Hironsan:20190409090733p:plain
Qiitaのタグフィード

このように、人気度と新規性を単体で使うといくつかの問題が出てきてしまいます。そういうわけで、実際にはこれらの手法をハイブリッドして使うことを考えます。なお、個人化の問題については扱うと長くなるので、次の機会にしておきます。

ハイブリッドな手法

ハイブリッドな手法では、Hacker Newsで使っているアルゴリズムを紹介しましょう。その前に人気度と新規性に基づく手法の問題を整理しておきます。人気度に基づく手法ではコンテンツの新しさは考慮されませんでした。そのため、ニュースの推薦で3年前の記事を紹介してしまう可能性があります。一方、新規性に基づく手法では有用でない記事が新しいというだけの理由で推薦される可能性があります。

ハイブリッドな手法の基本的な考え方としては人気度と新規性をバランスさせるようにスコア関数を設計します。概念的には、\displaystyle{\frac{f(popularity)}{g(recency)}}のような形でスコア関数を設計します。こうすることで、「いいね!」がたくさんついているような人気度が高い記事は分子の値を大きくして全体的なスコアを高く、一方で発信されてから時間が経った記事は分母の値を大きくして全体的なスコアを小さくすることができます。

Hacker Newsを例にスコア関数について見てみましょう。Hacker Newsのアルゴリズムを解説した記事によると、Hacker Newsでは以下の式を使って記事にスコア付を行っています。

\displaystyle{
score = \frac{(ups-downs-1)^{0.8}}{(age+2)^{1.8}} \times penalty
}

分子が人気度、分母が新規性を表しています。upsはupvoteの数、downsはdown voteの数、ageは投稿されてからの時間を表していると考えてください。

まず、注目すべきは分子の指数が分母より小さい点(0.8 < 1.8)です。これはつまり分母は分子より早く大きくなるということを示しています。こうすることで、どれだけupvoteが多くてもageは常にその成長を追い越すので、結果として新しい記事が上に来るような設計になっています。以下に示すように、スコア関数の形としては、最初に急激に上がって、ゆっくりと下がっていく形になっています。分母は最初の方はあまり効いていないのですが、時間が経つにつれ効いてくることを示しています。

f:id:Hironsan:20190410093412p:plain
HN article raw scores. http://www.righto.com/2013/11/how-hacker-news-ranking-really-works.htmlより引用

また、分子の指数が0.8である点にも工夫が見られます。指数を0.8とすることで分子の形は以下の図に示すようにsublinearの形になります。こうすることで、最初に獲得した100のupvoteは1000獲得した後の100upvoteより価値があるという考え方を入れられます。

f:id:Hironsan:20190410095037p:plain
Example of linear and sublinear. https://www.researchgate.net/figure/Examples-of-linear-and-sub-linear-functions-Hick-Hyman-law-follows-the-latter-pattern_fig2_270890224より引用

このように設計している理由としては、少数の記事がupvoteのほとんどを獲得し、大多数の記事はupvote数が少ないことに関係していると思われます。Linearに設計すると、1000vote得た記事に100voteの記事は勝負になりませんが、sublinearなら土俵に乗ることはできます。

最後に、penalty 項ではビジネスロジックを入れる事ができます。たとえば、画像だけの記事やリンク集のような記事はスコアが低くなるようにpenalty項を設計することができます。応用としては、たとえば自社でニュースのレコメンデーションシステムを作る際、penalty項をいじって自社に関係する記事に高いスコアを与えるといったことが考えられます。

おわりに

今回は手動で設計したスコア関数によるレコメンデーションの方法についてHacker Newsを例に紹介しました。これらの手法は学習が必要ないというメリットがありますが、その一方で推薦内容の個人化がされていないという欠点もあります。次回は行列分解による手法を例に個人化の方法について紹介したいと思います。

参考資料

www.righto.com

日本語 Sentiment Analyzer を作ってパッケージ化した話

Sentiment Analysisと言えば自然言語処理ではよく知られたタスクで、典型的にはテキストをポジティブ/ネガティブの2クラスに分類するものだ。 その使い道としては、Twitter等のSNSから自社製品についての投稿を収集して評価や緊急度によって分類し、問題に対応するチームメンバーを決定したり、カスタマーフィードバックを時系列で分析して顧客のsentimentを追跡することで不満が顕在化する前に対処したり、従業員のアンケートを分析して、時系列で変化する従業員感情の変化を追跡して、懸念が表面化する前に解決に導くといったものがある。

そんなSentiment Analysisだが、英語のテキストを分析するためのソフトウェアはこれまで様々な形で提供されてきた。たとえば、PythonパッケージならTextBlobNLTK等があり、クラウドサービスであれば、Google Cloud Natural Language APIAYLIEN等がAPIを提供している。

一方、日本語に対するSentiment Analysis機能の提供はどうなのかというと、Google Cloud Natural Language APIのようなクラウドサービスでは提供されていることが多いが、オープンソースだと充実していないのが現状だと思われる。私の探した限りだと、極性評価辞書を使ったタイプのパッケージがいくつか公開されている程度であった。この手の極性評価辞書を使ったタイプは、単純に極性を足すだけだと上手くいかないので色々とルールを書く必要があり、メンテナンスにコストがかかる。また、クラウドサービスだと課金する必要があるので、ちょっとしたことに使いにくい。






(´・ω・`) しょーがねーなー。作るか。




そういうわけで作ったものをオープンソースで公開した。スターつけてくれると嬉しい。

github.com

デモサイトも用意してあるので、インストールしなくても実際の動作を確認できる。

f:id:Hironsan:20190208120644p:plain

性能的な話

ソースコードを見てもらえればわかるが、asariの中身はとてもシンプルなものになっている。sklearnのTfidfVectorizerLinearSVCしか使っていない。テストセットに対する評価は以下の通り。

              precision    recall  f1-score   support

    negative     0.8484    0.8404    0.8444      2331
    positive     0.9283    0.9322    0.9302      5164

   micro avg     0.9037    0.9037    0.9037      7495
   macro avg     0.8883    0.8863    0.8873      7495
weighted avg     0.9034    0.9037    0.9035      7495

ちなみに、最近流行りのBERTで評価した結果は以下の通り。データセットを分割する際にシードを固定し忘れたので完全に↑と同じテストセットで評価したわけではないことに注意。

             precision    recall  f1-score   support

   negative     0.8735    0.8841    0.8788      2382
   positive     0.9457    0.9403    0.9430      5112

avg / total     0.9228    0.9225    0.9226      7494

BERTと比較してもそれなりの性能を確保できたので、予測速度等を考えて思いっきりシンプルに作っている。こんなモデルで学習して欲しい等あれば、コードを書いてPull Requestを送ってほしい。善処する。

2018年のふりかえりと2019年にしたいこと

あけましておめでとうございます。

今日までお正月休みで明日から会社に復帰します。三週間ほど家にこもってゲームばかりしていて頭もだいぶボケてきているので、出社前のリハビリがてら2018年のふりかえりをしたいと思います。まずは2018年に何をしていたか思い出すために、やったことを時系列で書いてみました。

翻訳した技術書が発売される

f:id:Hironsan:20190109104619p:plain

2018年の8月に翻訳を担当した「直感ディープラーニング」が発売されました。この本の企画自体は一年前の2017年7月辺りに立ち上がったのですが、それから一年経ってようやく発売されました。書店に並んでいる本を見たときは感慨深かったです。本当にいい経験をさせてもらったのでやってよかったです。

アノテーションツールのリリース

https://github.com/chakki-works/doccano/blob/master/docs/named_entity_recognition.png?raw=true

同じく2018年の8月には開発したテキスト用のアノテーションツールであるdoccanoをリリースしました。doccanoは企画から開発、リリースまで一人で行ったプロジェクトなのですが、最近は徐々にユーザたちがIssueやPRを上げてくれるようになってきました。2019年は開発者であると同時にマネージャとして多くのユーザとともにdoccanoを発展させていきます。

資格取得

2018年はIPAデータベーススペシャリストネットワークスペシャリストの資格を取得しました。IPAの試験を受けるのは学生時代以来(3年ぶりくらい?)で午前試験の免除もなく体力が持つか不安だったのですが、どちらも一発で合格することができました。よく「実際には役に立たない」等の批判を受けているのを目にしますが、私としては資格取得を通じて体系的に視野を広げられたり、勉強法について見直したのは今後も活かせると思っています。

AutoMLの講演

speakerdeck.com

2018年の12月にはAutoMLについて90分間の講演を行いました。相手が技術者ではなかったので話す内容について結構悩んだ上でスライドを作成したのですが、あまりウケなかった(一番前のおじさんが寝てた(´;ω;`))ので失敗だったかなと思います。ただ、内容自体は結構良いと思っていますし、今後確実に伸びてくる分野なので以下の記事と合わせて見ていただくと役に立つと思います。

qiita.com

2019年にしたいこと

2018年の失敗は色々なことを同時並行にやろうとしたことだと思っています。よく言われていることではあると思いますが、マルチタスクで進めると切り替えのコストが高いことに加えて、一つ一つの仕事がなかなか進まないのでモチベーションがどんどん落ちていくのを感じました。2019年は一つずつ片付けるような仕事のやり方に変える予定です。

2019年は以下のことに絞って取り組みたいと考えています。

  • doccanoのマネジメントとサービス化
  • 研究成果のソフトウェア化
  • 書籍の出版

doccanoはありがたいことにどんどん成長しています。はじめは一人で開発していたので誰かに何かをして貰う必要はなかったのですが、開発してくれる人が増えてきたので何らかの対策を打たないとまずい状況になっています。なので、今年はOSSのマネージャとしてプロダクトを成長させつつ経験を積んでいきたいと思います。

研究成果のソフトウェア化では、研究結果を誰にでも使える形で公開しようと思っています。2019年はテキストからの知識の獲得と活用について取り組もうと考えているのですが、まずはその要素技術である固有表現認識とエンティティリンキングについてソフトウェアを公開できればと思います。

固有表現認識は以下のような感じ。

f:id:Hironsan:20190109122446p:plain

エンティティリンキングは以下のような感じ。以下は「原辰徳」についてエンティティリンキングをした結果です。固有表現を知識ベースにリンクすることで様々な情報を取得できることを示しています。

f:id:Hironsan:20190109122545p:plain

もう一つ取り組みたいのは書籍の出版です。実は昨年から自然言語処理の入門本を書いているのですが、なかなか筆が進まず昨年中に書き終えることができませんでした。今年の早い段階で書き終えて年内には出版できるようにしたいです。

最後になりますが、今年もよろしくおねがいしますm( )m