2014年5月28日水曜日

1000万件の高評価がたった1件だけの評価に負けないスコアランキングアルゴリズム(ライブラリ)

アマゾンで1件だけの評価が5スターだと、商品自体の全体評価が5スターになる。それよりも5スターを集めている別の商品の総合評価は 4.5スター。どちらが本当に評判の良い商品?
5スターが多数付いているであろう総合評価4.5スターの商品が、たった1件の5スターがついた商品に見劣りしてしまう。何か変だ。

このライブラリは "the lower bound of Wilson score confidence interval for a Bernoulli parameter" と呼ばれるアルゴリズムを使って、物や人に対する評価(良い・悪い)をランキングを計算(ソート)する。NSSortDescriptorのカテゴリとして実装されている。



アルゴリズムの名前長過ぎ。それはともかくこんな感じで使う。
@{@"name": @"banana", @"up": @(90), @"down": @(78)},
                    @{@"name": @"cherry", @"up": @(28), @"down": @(6)},
                    @{@"name": @"durian", @"up": @(2), @"down": @(43)},
                    @{@"name": @"elderberry", @"up": @(81), @"down": @(42)},
                    @{@"name": @"fig", @"up": @(70), @"down": @(93)},
                    @{@"name": @"grape", @"up": @(48), @"down": @(89)},
                    @{@"name": @"honeydew", @"up": @(65), @"down": @(26)},
                    ];

NSSortDescriptor *sortDescriptor =
    [NSSortDescriptor wilsonRankSortDescriptorWithPositiveKey:@"up"
                                                  negativeKey:@"down"
                                                    ascending:NO];

for (id fruit in [fruits sortedArrayUsingDescriptors:@[sortDescriptor]]) {
    NSLog(@"%@ (%@↑ / %@↓)", fruit[@"name"], fruit[@"up"], fruit[@"down"]);
}

用意されたカテゴリメソッドから NSSortDescriptorが得られるのでそれを配列に適用するだけで良い。
上記サンプルの結果
apple (77↑ / 14↓)
cherry (28↑ / 6↓)
honeydew (65↑ / 26↓)
elderberry (81↑ / 42↓)
banana (90↑ / 78↓)
fig (70↑ / 93↓)
grape (48↑ / 89↓)
durian (2↑ / 43↓)

the lower bound of Wilson score confidence interval for a Bernoulli parameter の解説はここがわかりやすい(英語)。



例えばある商品や人について、Youtubeにあるようないい・悪いの評価が付けられるシステムがあるとする。
(例)りんご  良い 600  悪い 400 (良い 60%)
   みかん  良い 5500 悪い 4500 (良い 55%)

単純に良い率でランキングすると 60%のりんごが上位に来るが、絶対値としての「良い」はみかんの方がその10倍近くも支持を集めている。それを考慮するとこれらはどちらが高評価なのか?

あるいは平均で判定するのはどうか?それもやはり絶対値としての多数がうまく評価されない。これは冒頭のアマゾンの例で示した。

という風にいくつかの悪い例を並べ、その解決方法として " Lower bound of Wilson score confidence interval for a Bernoulli parameter"を紹介している。

数式

私には全然わかりません o_o;;

説明からすると相対的にサンプル数が少ないケースの影響度を低くする(過度に評価しない)ようだ。このランキングが絶対正しいというわけではもちろん無いが、少なくとも単純な平均ベースの結果よりは人間の感覚に近い結果を提供してくれそう。


Mattさんのサンプルは少々ばらつきが穏やかなので、手を入れてもっと極端なデータでやってみた。
NSArray *fruits = @[@{@"名前": @"りんご", @"良い": @(77), @"悪い": @(14)},
    @{@"名前": @"みかん", @"良い": @(1), @"悪い": @(0)},
    @{@"名前": @"ばなな", @"良い": @(24), @"悪い": @(36)},
    @{@"名前": @"ぶどう", @"良い": @(0), @"悪い": @(1)},
];

さきほどのアマゾンの(1件だけ5スター)のケースおよびその逆(1件だけ悪い)を入れてみた。

結果
りんご (77↑ / 14↓)
みかん (1↑ / 0↓)
ばなな (24↑ / 36↓)
ぶどう (0↑ / 1↓)

おお。サンプルを増やせば妥当性が評価できそう(誰かやって)。

0 件のコメント:

コメントを投稿