2009-12-06 17 views
13

Tenemos una tabla relativamente pequeña que nos gustaría ordenar en función de la calificación, utilizando el Wilson interval o un equivalente razonable. Soy un tipo bastante inteligente, pero mi matemáticas Fu es en absoluto suficiente fuerte como para entender esto:Implementando Wilson Score en SQL

Wilson Score http://www.evanmiller.org/images/rating-equation.png

La fórmula anterior, según me han dicho, calcula una puntuación para una positiva/negativa (pulgar hacia arriba/pulgares hacia abajo) sistema de votación. Nunca tomé un curso de estadística, y han pasado 15 años desde que hice algún tipo de matemática avanzada. No tengo ni idea de qué es lo que usa el pequeño sombrero que usa p, o lo que indica el pescado hacia atrás de Jesús debajo de z.

me gustaría saber dos cosas:

  1. ¿Puede esta fórmula ser alterado para dar cabida a un sistema de clasificación de 5 estrellas? Encontré this, pero el autor expresa sus dudas sobre la precisión de su fórmula.

  2. ¿Cómo se puede expresar esta fórmula en una función de SQL? Tenga en cuenta que no necesito calcular y ordenar en tiempo real. El puntaje se puede calcular y almacenar en caché diariamente.

  3. ¿Estoy pasando por alto algo incorporado en Microsoft SQL Server?

+0

sombrero p = la estimación de la variable aleatoria p. \ N hacia atrás los pescados de Jesús = alfa, que es su importancia de corte – twolfe18

+3

1 de "al revés Jesús pesca", como si los peces tuvieran orientaciones – ash

Respuesta

7

En lugar de tratar de manipular el algoritmo de Wilson para hacer un sistema de clasificación de 5 estrellas. ¿Por qué no miras un algoritmo diferente? Esto es lo que imdb usa para sus 250 principales: Bayesian Estimate

En cuanto a la explicación de las matemáticas en el algoritmo de Wilson, a continuación se publicó en el enlace en su primera publicación. Está escrito en Ruby.

require 'statistics2' 

def ci_lower_bound(pos, n, power) 
    if n == 0 
     return 0 
    end 
    z = Statistics2.pnormaldist(1-power/2) 
    phat = 1.0*pos/n 
    (phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n) 
end 

Si desea otro ejemplo, aquí es uno en PHP: http://www.derivante.com/2009/09/01/php-content-rating-confidence/

Editar: Parece que derivante.com ya no es alrededor. Puede ver el artículo original en archive.org - https://web.archive.org/web/20121018032822/http://derivante.com/2009/09/01/php-content-rating-confidence/ y agregué el código del artículo a continuación.

class Rating 
{ 
    public static function ratingAverage($positive, $total, $power = '0.05') 
    { 
    if ($total == 0) 
     return 0; 
    $z = Rating::pnormaldist(1-$power/2,0,1); 
    $p = 1.0 * $positive/$total; 
    $s = ($p + $z*$z/(2*$total) - $z * sqrt(($p*(1-$p)+$z*$z/(4*$total))/$total))/(1+$z*$z/$total); 
    return $s; 
    } 
    public static function pnormaldist($qn) 
    { 
    $b = array(
     1.570796288, 0.03706987906, -0.8364353589e-3, 
     -0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5, 
     -0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8, 
     0.3657763036e-10, 0.6936233982e-12); 
    if ($qn < 0.0 || 1.0 < $qn) 
     return 0.0; 
    if ($qn == 0.5) 
     return 0.0; 
    $w1 = $qn; 
    if ($qn > 0.5) 
     $w1 = 1.0 - $w1; 
    $w3 = - log(4.0 * $w1 * (1.0 - $w1)); 
    $w1 = $b[0]; 
    for ($i = 1;$i <= 10; $i++) 
     $w1 += $b[$i] * pow($w3,$i); 
    if ($qn > 0.5) 
     return sqrt($w1 * $w3); 
    return - sqrt($w1 * $w3); 
    } 
} 

En cuanto a hacer esto en SQL, SQL tiene todas estas funciones matemáticas ya en su biblioteca. Sin embargo, si fuera usted, lo haría en su aplicación. Haga que su aplicación actualice su base de datos de vez en cuando (¿horas o días?) En lugar de hacerlo sobre la marcha o su aplicación será muy lenta.

+0

¿No es 'phat = 1.0 * pos/n' ===' phat = pos/n'? –

+2

No, al multiplicar 'pos' por' 1.0', lo convierte en un flotador, lo que hace que la división sea una división flotante. – cbrauchli

+0

El enlace al ejemplo PHP ya no funciona –

2

Tomando el enlace de Williams a la solución php http://www.derivante.com/2009/09/01/php-content-rating-confidence/ y haciendo que su sistema sea simplemente positivo y negativo (5 estrellas podrían ser 2 pos, 1 inicio podría ser 2 neg quizás) entonces sería bastante fácil convertirlo a T -SQL, pero sería mucho mejor hacerlo en la lógica del servidor.

+3

Para agregar a lo que dijo Paul, crearía un campo de "puntuación" en sus tablas, y luego tendría una tarea cron para actualizar el puntaje en la base de datos una vez cada X horas (o días). Hacer este tipo de cálculos sobre la marcha sería muy malo para el rendimiento de cualquier aplicación. – William

+0

De acuerdo. Planeo calcular el valor una vez al día, y luego ordenar en función del valor en caché. – dansays

4

Respecto a su primera pregunta (ajustando la fórmula al sistema de 5 estrellas), estoy de acuerdo con Paul Creasey.

fórmula de conversión: [3 +/- i estrellas -> i arriba/abajo califican] (3 estrellas -> 0)

ejemplo: 4 estrellas -> +1 up-voto, 5 estrellas -> +2, 1 -> -2 y así sucesivamente.

Me gustaría en cuenta sin embargo que en lugar del límite inferior del intervalo de que ambas funciones de rubí y PHP computan, me gustaría simplemente calcular la mucho más sencillo punto medio Wilson:

(x + (z^2)/2)/(n + z^2)

donde:
n = Sum (up_votes) + suma (| down_votes |)
x = (positivas)/n = suma (up_votes)/n
z = 1.96 (valor fijo)

0

El autor del first link recientemente agregó una implementación SQL a su publicación.

aquí está:

SELECT widget_id, ((positive + 1.9208)/(positive + negative) - 
       1.96 * SQRT((positive * negative)/(positive + negative) + 0.9604)/
         (positive + negative))/(1 + 3.8416/(positive + negative)) 
    AS ci_lower_bound FROM widgets WHERE positive + negative > 0 
    ORDER BY ci_lower_bound DESC; 

Si esto se puede acomodar a un sistema de calificación de 5 estrellas, está más allá de mí también.

0

He subido una aplicación Oracle PL/SQL a https://github.com/mattgrogan/stats_wilson_score

create or replace function stats_wilson_score(

/***************************************************************************************************************** 

Author  : Matthew Grogan 
Website  : https://github.com/mattgrogan 
Name  : stats_wilson_score.sql 
Description : Oracle PL/SQL function to return the Wilson Score Interval for the given proportion. 
Citation : Wilson E.B. J Am Stat Assoc 1927, 22, 209-212 

Example: 
    select 
    round(29/250, 4) point_estimate, 
    stats_wilson_score(29, 250, 0.10, 'LCL') lcl, 
    stats_wilson_score(29, 250, 0.10, 'UCL') ucl 
    from dual; 

******************************************************************************************************************/ 

    x integer, -- Number of successes 
    m integer, -- Number of trials 
    alpha number default 0.95, -- Probability of a Type I error 
    return_value varchar2 default 'LCL' -- LCL = Lower control limit, UCL = upper control limit 
) 

return number is 

    z float(10); 
    phat float(10) := 0.0; 
    lcl float(10) := 0.0; 
    ucl float(10) := 0.0; 

begin 

    if m = 0 then 
    return(0); 
    end if; 

    case alpha 
    when 0.10 then z := 1.644854; 
    when 0.05 then z := 1.959964; 
    when 0.01 then z := 2.575829; 
    else return(null); -- No Z value for this alpha 
    end case; 

    phat := x/m; 

    lcl := (phat + z*z/(2*m) - z * sqrt((phat * (1-phat))/m + z * z/(4 * (m * m))))/(1 + z * z/m); 
    ucl := (phat + z*z/(2*m) + z * sqrt((phat*(1-phat)+z*z/(4*m))/m))/(1+z*z/m); 

    case return_value 
    when 'LCL' then return(lcl); 
    when 'UCL' then return(ucl); 
    else return(null); 
    end case; 

end; 
/
grant execute on stats_wilson_score to public; 
+1

¿Es demasiado grande para publicar aquí? El enlace podría romperse ... – vonbrand