Tengo una gran tabla de datos de medición en MySQL y necesito calcular el rango percentil para todos y cada uno de estos valores. Oracle parece tener una función llamada percent_rank pero no puedo encontrar nada similar para MySQL. Claro que podría simplemente usar fuerza bruta en Python, que utilizo para llenar la tabla, pero sospecho que sería bastante ineficiente porque una muestra podría tener 200,000 observaciones.Cálculo del rango percentil en MySQL
Respuesta
Esta es una respuesta relativamente fea, y me siento culpable de decirlo. Dicho esto, podría ayudarte con tu problema.
Una forma de determinar el porcentaje sería contar todas las filas y contar el número de filas que son mayores que el número que proporcionó. Puede calcular mayor o menor que y tomar el inverso según sea necesario.
Cree un índice de su número. total = select count (); less_equal = select count () donde value> indexed_number;
El porcentaje sería algo así como: less_equal/o total (Total - less_equal)/total de
Asegúrese de que ambos de ellos están utilizando el índice que ha creado. Si no lo son, ajústelos hasta que lo estén. La consulta de explicación debe tener "usar índice" en la columna de la derecha. En el caso del recuento selectivo (*) debería estar usando el índice para InnoDB y algo así como const para MyISAM. MyISAM conocerá este valor en cualquier momento sin tener que calcularlo.
Si necesita tener el porcentaje almacenado en la base de datos, puede utilizar la configuración de arriba para el rendimiento y luego calcular el valor de cada fila utilizando la segunda consulta como una selección interna. El primer valor de la consulta se puede establecer como una constante.
¿Le sirve de ayuda?
Jacob
De hecho, lo intenté hace unas semanas y fue increíblemente lento, así que terminé calculando percentiles en python y poniendo el valor en la base de datos. – lhahne
¿Intentó usar el recuento de selección (*) y seleccionar conteo (*) <= su valor? ¿Confirmaste que ambos estaban siendo manejados por un índice que solo tenía las columnas que necesitabas? Si la solución tuviera que tocar las filas de datos, esperaría que fuera una o dos órdenes de magnitud más lenta. Si los índices incluían más columnas que las necesarias o si la configuración de memoria de MySQL no se configuraba correctamente, era muy lento. Si es así, esto debería haber sido rápido. ¿Aproximadamente cuánto tiempo es "increíblemente lento"? Dependiendo del orden de magnitud de la respuesta esperada, mi respuesta podría ser mansamente lenta. – TheJacobTaylor
@TheJacobTaylor Respuesta correcta pero corta de código. Si pones una consulta de tipo 'seleccionar distinto' funcional, obtienes mi +1. Además, si puedes arreglar esto, obtienes un bonito +1 brillante y ¡mira! ;)) http://stackoverflow.com/questions/13689434/update-all-rows-with-countdistinct-only-updates-first-row-the-rest-0 –
no hay una manera fácil de hacer esto. ver http://rpbouman.blogspot.com/2008/07/calculating-nth-percentile-in-mysql.html
Lo que estoy buscando es De hecho, el inverso de eso, dado un número, debería decirme su rango. Estoy algo seguro de que esto sería más fácil en Oracle, pero desafortunadamente esa no es una posibilidad. – lhahne
Para obtener el rango, yo diría que necesita para exterior (izquierda) se une a la mesa en sí algo como:
select t1.name, t1.value, count(distinct isnull(t2.value,0))
from table t1
left join table t2
on t1.value>t2.value
group by t1.name, t1.value
Para cada fila, se contar cuántas (si los hay) las filas de la misma tabla tienen un valor inferior.
Tenga en cuenta que estoy más familiarizado con sqlserver, por lo que la sintaxis podría no ser correcta. Además, es posible que los distintos no tengan el comportamiento correcto para lo que quieres lograr. Pero esa es la idea general.
Luego, para obtener el rango percentil real, primero tendrá que obtener el número de valores en una variable (o valores distintos según la convención que desea tomar) y calcular el rango percentil utilizando el rango real dado anteriormente.
Si está combinando su SQL con un lenguaje de procedimientos como PHP, puede hacer lo siguiente. Este ejemplo descompone los tiempos de exceso de bloque de vuelo en un aeropuerto, en sus percentiles. Utiliza la cláusula LIMIT x, y en MySQL en combinación con ORDER BY
. No es muy bonito, pero hace el trabajo (lo siento luchado con el formato):
$startDt = "2011-01-01";
$endDt = "2011-02-28";
$arrPort= 'JFK';
$strSQL = "SELECT COUNT(*) as TotFlights FROM FIDS where depdt >= '$startDt' And depdt <= '$endDt' and ArrPort='$arrPort'";
if (!($queryResult = mysql_query($strSQL, $con))) {
echo $strSQL . " FAILED\n"; echo mysql_error();
exit(0);
}
$totFlights=0;
while($fltRow=mysql_fetch_array($queryResult)) {
echo "Total Flights into " . $arrPort . " = " . $fltRow['TotFlights'];
$totFlights = $fltRow['TotFlights'];
/* 1906 flights. Percentile 90 = int(0.9 * 1906). */
for ($x = 1; $x<=10; $x++) {
$pctlPosn = $totFlights - intval(($x/10) * $totFlights);
echo "PCTL POSN for " . $x * 10 . " IS " . $pctlPosn . "\t";
$pctlSQL = "SELECT (ablk-sblk) as ExcessBlk from FIDS where ArrPort='" . $arrPort . "' order by ExcessBlk DESC limit " . $pctlPosn . ",1;";
if (!($query2Result = mysql_query($pctlSQL, $con))) {
echo $pctlSQL . " FAILED\n";
echo mysql_error();
exit(0);
}
while ($pctlRow = mysql_fetch_array($query2Result)) {
echo "Excess Block is :" . $pctlRow['ExcessBlk'] . "\n";
}
}
}
Aquí es un enfoque diferente que no requiere de una combinación. En mi caso (una tabla con más de 15,000 filas), se ejecuta en aproximadamente 3 segundos. (El método JOIN toma un orden de magnitud más largo).
En la muestra, asumen que medida es la columna en la que está calculando el rango ciento, y Identificación es sólo un identificador de fila (no es obligatorio):
SELECT
id,
@prev := @curr as prev,
@curr := measure as curr,
@rank := IF(@prev > @curr, @[email protected], @rank) AS rank,
@ties := IF(@prev = @curr, @ties+1, 1) AS ties,
([email protected]/@total) as percentrank
FROM
mytable,
(SELECT
@curr := null,
@prev := null,
@rank := 0,
@ties := 1,
@total := count(*) from mytable where measure is not null
) b
WHERE
measure is not null
ORDER BY
measure DESC
de crédito para este método va a Shlomi Noach. Él escribe sobre ello en detalle aquí:
http://code.openark.org/blog/mysql/sql-ranking-without-self-join
He probado esto en MySQL y funciona muy bien; ninguna idea acerca de Oracle, SQLServer, etc.
Esto funciona extremadamente bien. Genius SQL. –
Desafortunadamente, esto depende del orden de evaluación de las variables de usuario, que es un comportamiento indefinido. El primer comentario en ese enlace cita el manual de MySQL: "El orden de evaluación de las variables de usuario no está definido y puede cambiar en función de los elementos contenidos en una consulta determinada ... La regla general es nunca asignar un valor a una variable de usuario en una parte de una declaración y use la misma variable en alguna otra parte de la misma declaración. Puede obtener los resultados que espera, pero esto no está garantizado ". Referencia: http://dev.mysql.com/doc/refman/5.1/en/user-variables.html – rep
SELECT
c.id, c.score, ROUND(((@rank - rank)/@rank) * 100, 2) AS percentile_rank
FROM
(SELECT
*,
@prev:[email protected],
@curr:=a.score,
@rank:=IF(@prev = @curr, @rank, @rank + 1) AS rank
FROM
(SELECT id, score FROM mytable) AS a,
(SELECT @curr:= null, @prev:= null, @rank:= 0) AS b
ORDER BY score DESC) AS c;
- 1. Cálculo del rango por percentil
- 2. Cálculo del percentil
- 3. Cálculo del promedio ponderado en MySQL?
- 4. Cálculo del rango móvil en SQL Server (sin matrices)
- 5. MySQL seleccionar EN rango
- 6. Función de rango en MySQL
- 7. MySQL rango límite
- 8. ¿Cálculo de superposición de rango de fechas eficiente en python?
- 9. Clasificación de MySQL en un cálculo
- 10. Cálculo de medias recortadas en MySQL
- 11. Generando un rango de números en MySQL
- 12. MySQL cálculo semana entre dos fechas
- 13. Cálculo del divisor CRC
- 14. MYSQL Resultados de suma de un cálculo
- 15. Mysql int (11) número fuera de rango
- 16. Crear rango de fechas de mysql
- 17. SELECCIONE el rango de enteros en MySQL. P.ej. 1,2,3,4, ..., n;
- 18. MySql: ¿Cuenta las filas en el rango de precio?
- 19. Comprobación de conflictos de rango de fechas en MySQL
- 20. Cálculo del uso de CPU
- 21. Cálculo del ancho de banda
- 22. Cálculo del logaritmo Base-n en Ruby
- 23. Cálculo del tiempo en Python (datetime.timedelta?)
- 24. Cálculo del porcentaje de progreso
- 25. Cálculo del valor máximo del histograma
- 26. En MySQL cálculo de desplazamiento para un huso horario
- 27. Cálculo de la duración de tiempo total en MySQL
- 28. Cálculo del porcentaje del recuento de grupos (*)
- 29. cálculo del último día del mes
- 30. Conversión/cuantificación del rango de flotación al rango entero
¿Puede explicar exactamente qué quiere decir con percentile rank? –
@AssafLavie: http://en.wikipedia.org/wiki/Percentile_rank – eliasah
Hice una función Mysql que funciona para cualquier percentil: http://stackoverflow.com/a/40266115/1662956 – dartaloufe