¿Cuál es la forma más simple (y con suerte no demasiado lenta) de calcular la mediana con MySQL? Lo he usado AVG(x)
para encontrar la media, pero me cuesta encontrar una manera simple de calcular la mediana. Por ahora, estoy devolviendo todas las filas a PHP, haciendo una ordenación y luego seleccionando la fila central, pero seguramente debe haber alguna forma simple de hacerlo en una sola consulta MySQL.
Datos de ejemplo:
id | val
--------
1 4
2 7
3 2
4 2
5 9
6 8
7 3
Al ordenar val
da 2 2 3 4 7 8 9
, entonces la mediana debería ser 4
, versus SELECT AVG(val)
cuál == 5
.
sql
mysql
statistics
median
davr
fuente
fuente
Respuestas:
En MariaDB / MySQL:
Steve Cohen señala que después del primer pase, @rownum contendrá el número total de filas. Esto se puede usar para determinar la mediana, por lo que no se necesita un segundo pase o unión.
También
AVG(dd.val)
ydd.row_number IN(...)
se utiliza para producir correctamente una mediana cuando hay un número par de registros. Razonamiento:Finalmente, MariaDB 10.3.3+ contiene una función MEDIANA
fuente
WHERE 1
paraWHERE d.val IS NOT NULL
que excluyaNULL
filas para mantener este método alineado con el nativoAVG
select avg(value) from (select value, row_number from (select a - b as value from a_table join b_table order by value))
Acabo de encontrar otra respuesta en línea en los comentarios :
Asegúrese de que sus columnas estén bien indexadas y que el índice se utilice para filtrar y ordenar. Verifique con los planes de explicación.
Calcule el número de fila "mediana". Tal vez use:
median_row = floor(count / 2)
.Luego selecciónelo de la lista:
Esto debería devolverle una fila con solo el valor que desea.
Jacob
fuente
Descubrí que la solución aceptada no funcionaba en mi instalación de MySQL, devolviendo un conjunto vacío, pero esta consulta funcionó para mí en todas las situaciones en las que la probé:
fuente
data
y se está utilizando con dos nombres,x
yy
.Desafortunadamente, ni las respuestas de TheJacobTaylor ni Velcrow devuelven resultados precisos para las versiones actuales de MySQL.
La respuesta de Velcro desde arriba es cercana, pero no se calcula correctamente para conjuntos de resultados con un número par de filas. Las medianas se definen como 1) el número del medio en conjuntos con números impares, o 2) el promedio de los dos números del medio en conjuntos de números pares.
Entonces, aquí está la solución de velcro parcheada para manejar conjuntos de números pares e impares:
Para usar esto, siga estos 3 sencillos pasos:
fuente
Propongo una forma más rápida.
Obtenga el recuento de filas:
SELECT CEIL(COUNT(*)/2) FROM data;
Luego tome el valor medio en una subconsulta ordenada:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
Probé esto con un conjunto de datos de 5x10e6 de números aleatorios y encontrará la mediana en menos de 10 segundos.
fuente
Un comentario en esta página en la documentación de MySQL tiene la siguiente sugerencia:
fuente
Instale y use estas funciones estadísticas de mysql: http://www.xarg.org/2012/07/statistical-functions-in-mysql/
Después de eso, calcular la mediana es fácil:
fuente
La mayoría de las soluciones anteriores funcionan solo para un campo de la tabla, es posible que deba obtener la mediana (percentil 50) para muchos campos de la consulta.
Yo uso esto:
Puede reemplazar el "50" en el ejemplo anterior a cualquier percentil, es muy eficiente.
Solo asegúrese de tener suficiente memoria para GROUP_CONCAT, puede cambiarlo con:
Más detalles: http://web.performancerasta.com/metrics-tips-calculating-95th-99th-or-any-percentile-with-single-mysql-query/
fuente
Tengo el siguiente código que encontré en HackerRank y es bastante simple y funciona en todos y cada uno de los casos.
fuente
Partiendo de la respuesta de velcro, para aquellos de ustedes que tienen que hacer una mediana de algo que está agrupado por otro parámetro:
fuente
Puede usar la función definida por el usuario que se encuentra aquí .
fuente
Se preocupa por un recuento de valores impares; en ese caso, da el promedio de los dos valores en el medio.
fuente
Mi código, eficiente sin tablas o variables adicionales:
fuente
GROUP_CONCAT
está limitado a 1023 caracteres, incluso cuando se usa dentro de otra función como esta.Opcionalmente, también puede hacer esto en un procedimiento almacenado:
fuente
x IS NOT NULL
debe agregar?CALL median("table","x","x IS NOT NULL")
.Mi solución presentada a continuación funciona en una sola consulta sin creación de tabla, variable o incluso subconsulta. Además, le permite obtener una mediana para cada grupo en consultas grupales (¡esto es lo que necesitaba!):
Funciona debido al uso inteligente de group_concat y substring_index.
Pero, para permitir big group_concat, debe establecer group_concat_max_len en un valor más alto (1024 caracteres por defecto). Puede configurarlo así (para la sesión SQL actual):
Más información para group_concat_max_len: https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
fuente
Otro riff en la respuesta de Velcrow, pero usa una sola tabla intermedia y aprovecha la variable utilizada para la numeración de filas para obtener el recuento, en lugar de realizar una consulta adicional para calcularlo. También comienza el recuento para que la primera fila sea la fila 0 para permitir simplemente usar Floor y Ceil para seleccionar la (s) fila (s) mediana (s).
fuente
Lo anterior parece funcionar para mí.
fuente
{98,102,102,98}
es100
pero su código da102
. Funcionó bien para números impares.Usé un enfoque de dos consultas:
Estos se envuelven en una función defn, por lo que todos los valores se pueden devolver de una llamada.
Si sus rangos son estáticos y sus datos no cambian con frecuencia, podría ser más eficiente calcular previamente / almacenar estos valores y utilizar los valores almacenados en lugar de consultar desde cero cada vez.
fuente
Como solo necesitaba una solución mediana Y percentil, hice una función simple y bastante flexible basada en los hallazgos de este hilo. Sé que estoy feliz si encuentro funciones "listas para usar" que son fáciles de incluir en mis proyectos, así que decidí compartir rápidamente:
El uso es muy fácil, ejemplo de mi proyecto actual:
fuente
Aquí está mi camino. Por supuesto, podría ponerlo en un procedimiento :-)
Puede evitar la variable
@median_counter
, si la sustituye:fuente
Esta manera parece incluir recuento par e impar sin subconsulta.
fuente
Basado en la respuesta de @ bob, esto generaliza la consulta para tener la capacidad de devolver múltiples medianas, agrupadas según algunos criterios.
Piense, por ejemplo, el precio medio de venta de automóviles usados en un lote de automóviles, agrupados por año-mes.
fuente
A menudo, es posible que necesitemos calcular la mediana no solo para toda la tabla, sino también para los agregados con respecto a nuestra identificación. En otras palabras, calcule la mediana de cada ID en nuestra tabla, donde cada ID tiene muchos registros. (buen rendimiento y funciona en muchos SQL + corrige el problema de pares e impares, más sobre el rendimiento de diferentes métodos Medianos https://sqlperformance.com/2012/08/t-sql-queries/median )
Espero eso ayude
fuente
MySQL ha admitido funciones de ventana desde la versión 8.0, puede usar
ROW_NUMBER
oDENSE_RANK
( NO use,RANK
ya que asigna el mismo rango a los mismos valores, como en el ranking deportivo):fuente
Si MySQL tiene ROW_NUMBER, entonces MEDIAN es (inspírese en esta consulta de SQL Server):
El IN se usa en caso de que tenga un número par de entradas.
Si desea encontrar la mediana por grupo, simplemente PARTICIÓN POR grupo en sus cláusulas OVER.
Robar
fuente
ROW_NUMBER OVER
, no PARTICIÓN POR, nada de eso; esto es MySql, no un motor de base de datos real como PostgreSQL, IBM DB2, MS SQL Server, etc. ;-).Después de leer todos los anteriores, no coincidían con mi requisito real, por lo que implementé el mío que no necesita ningún procedimiento ni complicar las declaraciones, solo yo
GROUP_CONCAT
todos los valores de la columna que quería obtener la MEDIANA y aplicando un COUNT DIV BY 2 Extraigo el valor desde el medio de la lista como lo hace la siguiente consulta:(POS es el nombre de la columna que quiero obtener su mediana)
Espero que esto pueda ser útil para alguien en la forma en que muchos otros comentarios fueron para mí desde este sitio web.
fuente
Conociendo el recuento exacto de filas, puede usar esta consulta:
Dónde
<half> = ceiling(<size> / 2.0) - 1
fuente
Tengo una base de datos que contiene aproximadamente mil millones de filas que necesitamos para determinar la edad promedio en el conjunto. Ordenar mil millones de filas es difícil, pero si agrega los distintos valores que se pueden encontrar (las edades oscilan entre 0 y 100), puede ordenar ESTA lista y usar algo de magia aritmética para encontrar el percentil que desee de la siguiente manera:
Esta consulta depende de las funciones de la ventana de soporte de db (incluidas las PRECEDENTES SIN LÍMITES DE FILAS), pero si no tiene eso, es simple unir aggData CTE consigo mismo y agregar todos los totales anteriores en la columna 'acumulada' que se utiliza para determinar qué El valor contiene el precentil especificado. La muestra anterior calcula p10, p25, p50 (mediana), p75 y p90.
-Chris
fuente
Tomado de: http://mdb-blog.blogspot.com/2015/06/mysql-find-median-nth-element-without.html
Sugeriría otra forma, sin unirse , pero trabajando con cadenas
No lo verifiqué con tablas con datos grandes, pero las tablas pequeñas / medianas funcionan bien.
Lo bueno aquí, es que también funciona AGRUPANDO para que pueda devolver la mediana de varios elementos.
Aquí está el código de prueba para la tabla de prueba:
y el código para encontrar la mediana para cada grupo:
Salida:
fuente
En algunos casos, la mediana se calcula de la siguiente manera:
La "mediana" es el valor "medio" en la lista de números cuando están ordenados por valor. Para conjuntos de conteo par, la mediana es el promedio de los dos valores medios . He creado un código simple para eso:
La mediana de $ devuelta sería el resultado requerido :-)
fuente