格付けシステムによる反対投票者の影響の軽減


7

ユーザーが1つ星から5つ星のシステムで評価するサイトを持っています。アイテムがチャートの一番上に達すると、それがどこにあるかを取得するために4〜5つ星の過半数を得たとしても、一部のユーザーは1つ星の評価を開始する傾向があります。それは蔓延しているわけではありません、私は新しい投票の10-20%が1です。明らかに彼らは評価システムを操作しようとしているので、私はそれを防ぎたいのです。

私が現在行っている方法は、正当な投票だと私が考えるものの「妥当なウィンドウ」を持つことです。

投票数が10未満のアイテムの場合。私は現在何もせず、評価なので平均値をとります。

アイテムの投票数が10を超えたら、平均値のウィンドウに結び付けます。このウィンドウは次のように定義されています

Window = 4.5 - Log(TotalVotes, 10);

したがって、妥当な投票範囲は (Mean - Window) thru (Mean + Window)

妥当な投票範囲が見つかると、「レーティング」はすべての妥当な投票(妥当な範囲に該当するもの)の平均にすぎません。

これは、100票で4.2の真の平均値を持つアイテムがのウィンドウを持つことを意味します4.5-Log(100,10) = 2.5。したがって、そのアイテムが1つ星の票を獲得した場合、評価では無視されます。ただし、1つ星は基になる平均に影響します。

これは一般的にはうまくMean - Windowいきましたが、問題は、アイテムが1.0の瀬戸際にあり、1つ星の投票ごとに1.0を下回るとすぐに評価に含まれ、前後の差でさえも大幅に低下することです。 1つ星の評価がもう1つあります。

私はこれらの1つ星の評価をフィルターで除外するためのより良いシステム/方法を必要としていますが、それだけでなく、誰かが友達にアイテムを10票と5つ星すべてに賛成させ、その真の評価がもっと高い状況に対処する必要があります3つ星。

ユーザー主導の評価システムを処理し、外れ値投票を正規化する方法の推奨事項を探します。


後の投票(良いか悪いか)に低い重みを付けることができます。しかし、そうすれば、友人に早く投票してもらう人は、より高い重みを得ます。
パパラッツォ

時系列分析にはこれによく似たものがあり、移動ウィンドウを介して平滑化が行われます。ウィンドウは(「ウィンドウ」と同じように)かつてはステップ関数でしたが、ガウス関数であるとパフォーマンスが大幅に向上します。あなたはあなたの窓をガウスに変えて、ガウスの値によって投票に重みを付けるべきです。これを答えにしようと思いますが、今は本当に忙しいです。指数加重移動平均(EWMA)を確認してください。ただし、EWAは移動しないでください。すべてがスムーズになり、貢献スコアから非貢献スコアへの量子ジャンプから逃れることができるので、すばらしいです。
AN6U5 2015年

3
その理由がある場合はどうなりますか?Google Playストアで、新しいバージョンのアプリがアップロードされたと言います。そして、おっと、それは壊れています。もちろん、多くの人が合理的ではなく、1つ星の評価を与えます。私は操作の他の指標を探します。
QUITあり-Anony-Mousse 2015

回答:


5

場所の他の推定量を調べる必要があります。

必要なのは、高いブレークダウンポイントを持つ堅牢な推定量です。

極端なアプローチは中央値です。

しかし、平均値をトリミングすると、数値的に興味深い結果が得られる場合があります。

しきい値を定義します(たとえば2%)。次に、上位2%の票と下位2%の票を削除し、残りのエントリのみの平均を取ります。5つ星が98%のアプリでも5.0を取得します

しかし、改ざんを防ぐために、他のシグナルを調べます。たとえば、単一の地域からの集まった投票など。


推薦をありがとう、私が求めているものの技術用語を知ってうれしい。トリミングされた平均の問題は、最初のページに表示されない衣装は1票をほとんど獲得しないのに対し、最初のページの衣装は10%以上を獲得することです。上部と下部を2%トリミングしても、フロントページャーには問題が残り、セカンドページャーに大きなダメージを与えます。不正操作を防ぐために、IPと地理的地域でグループ化すると、平均から離れていると思われる投票を削除します。ただし、これは私が数か月ごとに実行するクリーンアップタスクです。ここで問題
なのは

2
上で説明したようにオンザフライでこれを行うと、はるかに遅くなります。多くの人々が低い
点数を出し

1

@ Anony-Mousseの答えが好きです。堅牢な推定量を使用することは良いことです。

問題に対処するために別の方向性を追加したいと思います。これらの反対票を投じる「悪意のある」ユーザーがいるようです。そのため、それらを識別したいと思うかもしれません。

ユーザーのデータセットを作成し、ラベルとして「リーディングアイテムに対する不当な下向き投票」を使用します。デフォルト値として「リーディングアイテムへのダウンキャストキャスト」を使用し、それらを手動で変更して、「アイテムがトップチャートに達した後、リーディングアイテムに2倍以上ダウンキャストする」のようにルールをより繊細にすることができます。低い投票数、主要アイテムへの低い投票数などが役立つでしょう。

これで、教師あり学習フレームワークに入りました。悪意のあるユーザーを特定したら、その投票を無視して操作を避けます。


1

推定量をロバスト化するには、2つのガウスrvの混合である混合ガウスモデル(GMM)として評価をモデル化します。1)真の評価、2)1に等しいジャンク評価。Scikit-learnにはすでにGMM分類器が用意されています:http : //scikit-learn.org/stable/auto_examples/mixture/plot_gmm_classifier.html#example-mixture-plot-gmm-classifier-py

もう少し掘り下げてみると、scikit-learnで評価を2つのガウス分布に分割するという簡単な方法があります。いずれかのパーティションの平均が1に近い場合、それらの評価を破棄できます。または、よりエレガントに、真の評価平均として、他の非1ガウスガウスの平均を取ることができます。

これは、これを行うipythonノートブックのコードのビットです。

from sklearn.mixture import GMM
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import collections

def make_ratings(mean,std,rating_cnt):
    rating_sample = np.random.randn(rating_cnt)*std + mean
    return np.clip(rating_sample,1,5).astype(int)

def make_collection(true_mean,true_std,true_cnt,junk_count):
    true_ratings = make_ratings(true_mean,true_std,true_cnt)
    junk_ratings = make_ratings(1,0,junk_count)
    return np.hstack([true_ratings,junk_ratings])[:,np.newaxis]

def robust_mean(X, th = 2.5, agg_th=2.5, default_agg=np.mean):
    classifier = GMM(n_components=2)
    classifier.fit(X)
    if np.min(classifier.means_) > th or default_agg(X)<agg_th:
        return default_agg(X)
    else:
        return np.max(classifier.means_)

r_mean = 4.2
X = make_collection(r_mean,2,40,10)
plt.hist(X,5)
classifier = GMM(n_components=2)
classifier.fit(X)
plt.show()
print "vars =",classifier.covars_.flatten()
print "means = ",classifier.means_.flatten()
print "mean = ",np.mean(X)
print "median = ",np.median(X)
print "robust mean = ", robust_mean(X)
print "true mean = ", r_mean
print "prob(rating=1|class) = ",classifier.predict_proba(1).flatten()
print "prob(rating=true_mean|class) = ",classifier.predict_proba(r_mean).flatten()
print "prediction: ", classifier.predict(X)

1回の実行の出力は次のようになります。

vars = [ 0.22386589  0.56931527]
means =  [ 1.32310978  4.00603523]
mean =  2.9
median =  3.0
robust mean =  4.00603523034
true mean =  4.2
prob(rating=1|class) =  [  9.99596493e-01   4.03507425e-04]
prob(rating=true_mean|class) =  [  1.08366762e-08   9.99999989e-01]
prediction:  [1 0 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 0 1 0 1 0 1 1 0
 1 1 1 0 0 0 0 0 0 0 0 0 0]

これがいくつかのモンテカルロトライアルでどのように機能するかをシミュレーションできます。

true_means = np.arange(1.5,4.5,.2)
true_ratings = 40
junk_ratings = 10
true_std = 1
m_out = []
m_in = []
m_reg = []
runs = 40
for m in true_means:
    Xs = [make_collection(m,true_std,true_ratings,junk_ratings) for x in range(runs)]
    m_in.append([[m]*runs])
    m_out.append([[robust_mean(X, th = 2.5, agg_th=2,default_agg=np.mean) for X in Xs]])
    m_reg.append([[np.mean(X) for X in Xs]])

m_in = np.array(m_in).T[:,0,:]
m_out = np.array(m_out).T[:,0,:]
m_reg = np.array(m_reg).T[:,0,:]

plt.plot(m_in,m_out,'b.',alpha=.25)
plt.plot(m_in,m_reg,'r.',alpha=.25)
plt.plot(np.arange(0,5,.1),np.arange(0,5,.1),'k.')
plt.xlim([0,5])
plt.ylim([0,5])
plt.xlabel('true mean')
plt.ylabel('predicted mean')
plt.title("true_ratings=" + str(true_ratings)
          + "; junk_ratings=" + str(junk_ratings)
         + "; std="+str(true_std))

出力は以下に貼り付けられます。赤は平均評価で、青は提案された評価です。パラメータを微調整して、わずかに異なる動作を取得できます。 ここに画像の説明を入力してください


0

すべての投票を記録する

トップページにあるときとそうでないときの1票の比率数

最初のページで、1票の端数のみを適用します。
基本的に、ページ1バイアス全体に基づいてページ1バイアスを削除します

1票が適用された場合=最初のページにある場合は1票のアイテム*(1票は2ページ目合計/ 1票は1ページ目合計)


0

技術的には上記のソリューションの1つを実装するのがおそらく最も簡単ですが、反対票を投じるよう有権者の意見を異にすることも検討する必要があると思います。たとえば、明らかにシステムを悪用している少数のユーザーからの反対投票の場合、その反対投票が繰り返されると(このサイトのように)評判が低下します。


レート1-5は賛成でも反対でもありません。1(最高)の評価に対する評判にペナルティを課します。
パパラッツォ2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.