Reduzindo o efeito da queda dos eleitores com o sistema de classificação


7

Eu tenho um site no qual os usuários classificam coisas em um sistema de 1 a 5 estrelas. Quando um item chega ao topo dos gráficos, alguns usuários tendem a começar a classificá-lo com 1 estrela, mesmo que tenha uma maioria de 4-5 estrelas para chegar onde está. Não é galopante, eu diria que 10 a 20% dos novos votos são 1's. Claramente eles estão tentando manipular o sistema de classificação, e eu quero evitar isso.

A maneira atual de fazer isso é ter uma "janela razoável" do que considero um voto legítimo.

Para itens com menos de 10 votos; Atualmente, não faço nada e tomo a média como sua classificação.

Quando um item começa a receber mais de 10 votos, amarro-os a uma janela da média deles. Esta janela é definida como

Window = 4.5 - Log(TotalVotes, 10);

Portanto, um intervalo de votos razoável é então (Mean - Window) thru (Mean + Window)

Uma vez que o intervalo razoável de votos é encontrado, o "Rating" é apenas a média de todos os votos razoáveis ​​(aqueles que se enquadram no intervalo razoável).

Isso significa que um item com uma média real de 4,2 com 100 votos teria uma janela 4.5-Log(100,10) = 2.5; portanto, se esse item receber um voto de 1 estrela, ele será ignorado na classificação. No entanto, a estrela ainda afetará a média subjacente.

Isso funcionou bem em geral, mas a questão é quando um item Mean - Windowestá à beira de 1,0, assim que cai abaixo de 1,0 a cada 1 estrela agora é incluída na classificação e a classificação cai significativamente até mesmo a diferença antes e depois de maio foram apenas mais uma classificação de 1 estrela.

Preciso de um sistema / forma de realizar melhor para filtrar essas classificações de 1 estrela, e não apenas elas, mas lidar com a situação em que alguém pode fazer com que seus amigos votem com um item em 10 votos e em todas as 5 estrelas, onde sua verdadeira classificação pode ser mais 3 estrelas.

Procurando recomendações de como lidar com sistemas de classificação orientados pelo usuário e normalizar votos fora de série.


Você pode atribuir um peso menor aos votos posteriores (bons ou ruins). Mas, então, alguém que faça com que um amigo vote mais cedo terá um peso maior.
Paparazzo

Existe um bom análogo a isso na análise de séries temporais - a suavização é realizada através de uma janela em movimento. O Windows já foi uma etapa das funções (assim como a sua "janela"), mas tem um desempenho muito melhor quando são gaussianos. Você deve transformar sua janela em gaussiana e ponderar os votos pelo valor da gaussiana. Vou tentar transformar isso em uma resposta, mas estou muito ocupado agora. Confira a média móvel ponderada exponencialmente (EWMA), mas não a mova, por exemplo, EWA. É bom, já que tudo fica tranqüilo e você se afasta dos saltos quânticos de pontuações contribuintes a não-contribuintes.
AN6U5

3
E se houver uma razão para isso? Digamos na Google Play Store, é carregada uma nova versão de um aplicativo. E opa, está quebrado. É claro que muitas pessoas atribuirão uma classificação de 1 estrela, sem serem razoáveis. Eu procuraria por outros indicadores de manipulação.
QuIT - Anony-Mousse

Respostas:


5

Você deve procurar outros estimadores de localização.

O que você deseja é um estimador robusto , com um alto ponto de ruptura .

A abordagem extrema seria a mediana.

Mas você pode obter resultados mais numericamente interessantes com uma média aparada .

Você define um limite, digamos 2%. Em seguida, você remove os 2% de votos superiores e os 2% de votos inferiores e calcula a média apenas das entradas restantes. Um aplicativo com 98% de 5 estrelas ainda receberá 5,0

Mas, para impedir a manipulação, eu examinaria outros sinais. Como votos agrupados de uma única região, por exemplo.


Obrigado pela recomendação, prazer em saber os termos técnicos do que eu estou procurando. O problema com uma média aparada é que as roupas que nunca aparecem na primeira página quase não recebem 1 voto, enquanto as da primeira página recebem 10% ou mais. Se eu aparar os 2% superior e inferior, o problema ainda existe para os pagers frontais e dói muito os segundos. Para evitar manipulação, excluo votos que parecem distantes da média quando agrupados por IP e região geográfica. No entanto, esta é uma tarefa a limpeza I partem a cada poucos meses, o que está em questão aqui é como lidar com isso na mosca
Parox

2
Se você fizer isso rapidamente, como discutido acima, ficará muito mais lento. E se há uma razão muitas pessoas começam a dar notas baixas (por exemplo, porque se tornou conhecido o produto tem um problema?)
parou - anony-Mousse

1

Eu gosto da resposta da @ Anony-Mousse. Usar estimadores robustos é bom.

Quero adicionar uma direção diferente para lidar com o problema. Parece que existem alguns usuários "maliciosos" que votam negativamente para que você possa identificá-los.

Crie um conjunto de dados dos usuários e use " voto negativo injustificado no item principal" como etiqueta. Você pode usar "voto rejeitado no item principal" como valor padrão e modificá-lo manualmente e tornar a regra mais delicada, como "voto rejeitado mais do que duas vezes no item principal depois que o item atingir os gráficos mais altos". Acho que recursos como número de votos baixos, número de votos baixos para itens principais etc. será útil.

Agora você está em uma estrutura de aprendizado supervisionado. Depois de identificar usuários mal-intencionados, ignore seus votos e evite as manipulações.


1

Para fortalecer seu estimador, você pode modelar suas classificações como um modelo de mistura gaussiana (GMM) que é uma mistura de dois rvs gaussianos: 1) classificações verdadeiras, 2) classificação indesejável que são iguais a um. O Scikit-learn já possui um classificador GMM enlatado: http://scikit-learn.org/stable/auto_examples/mixture/plot_gmm_classifier.html#example-mixture-plot-gmm-classifier-py

Indo um pouco mais, uma abordagem simples seria permitir que o scikit-learn divida suas classificações em dois gaussianos. Se uma das partições tiver uma média próxima de uma, poderemos eliminar essas classificações. Ou, de maneira mais elegante, podemos considerar a média do outro gaussiano não próximo de um como a média verdadeira da classificação.

Aqui está um pouco de código para um notebook ipython que faz isso:

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)

A saída para uma execução é semelhante a:

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]

Podemos simular como isso funcionará com alguns testes de monte carlo:

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))

A saída é colada abaixo. O vermelho é a classificação média e o azul é a classificação proposta. Você pode ajustar os parâmetros para obter comportamentos ligeiramente diferentes. insira a descrição da imagem aqui


0

Gravar todos os votos

Proporção de 1 votos na primeira página em comparação a não

Aplique apenas uma fração do número 1 de votos enquanto estiver na primeira página
Remova basicamente o viés da página 1 com base no viés da página 1 como um todo

1 voto aplicado = item de 1 voto na primeira página * (1 voto no total da segunda página / 1 voto no total da primeira página)


0

Embora seja tecnicamente provavelmente mais fácil implementar uma das soluções acima, acho que você também deve desincentivar os eleitores a votar. Por exemplo, se os votos negativos vierem de uma minoria de usuários que abusam claramente do sistema, os votos repetidos devem contar (negativamente) para sua reputação - como este site.


A taxa de 1 a 5 não é um voto positivo ou negativo. Você penalizaria uma reputação por uma classificação 1 (superior).
Paparazzo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.