¿Cómo generar dinámicamente bandas/grupos de datos con números similares en cada uno?

StackOverflow https://stackoverflow.com/questions/4520230

  •  12-10-2019
  •  | 
  •  

Pregunta

Quiero generar dinámicamente bandas, que luego se agruparán en informes.

Mi primer pensamiento fue generar las bandas tomando el valor mínimo y el valor máximo y luego dividir la diferencia.

Por ejemplo, suponga que tenía los salarios para un gran grupo de personas:

  • El pago más bajo gana £ 12,000 al año y el más alto gana £ 3,000,000
  • Así que dividí eso en 10 bandas de tamaño similar: (£ 3mill - £ 12k) / 10 = £ 298800
  • Así que mi primera banda cuesta £ 12k a £ 310,800 y consigue a miles de personas en ella
  • Mi segunda banda cuesta £ 310k a £ 610k y tiene unos pocos cientos
  • Cualquier otra banda tiene algunas personas en cada una

Entonces esto no es realmente muy útil. Si tuviera que crear manualmente las bandas, quisiera números aproximadamente similares en cada uno, algo así como: £ 12k- £ 14k, £ 14k- £ 18k, £ 18k- £ 25k, £ 25- £ 35k, ..., £ 1.5- £ 3 millones

Este es solo un ejemplo: podría haber muchas distribuciones diferentes.

Estoy buscando un algoritmo para generar las bandas, por lo que los usuarios ingresarían cuántas bandas desean y los datos se agruparían en tantas bandas con un número similar en cada uno.

La banda debe ser rápida: no puedo simplemente recorrer todo el conjunto de datos.

La aplicación es C# además de SQL, pero las soluciones de otros idiomas son bienvenidos.

¿Fue útil?

Solución

Creo que estás preguntando sobre cómo consultar un conjunto de datos existente en las 'bandas' ...

Si esto es cierto, entonces Oracle admite funciones agregadas ntiles para este propósito. Debe haber equivalentes en otras implementaciones de SQL.

Otros consejos

Has mirado Ntile? SQL Server y la mayoría de los DBM lo admiten.

Por ejemplo:

select b.band, count(*), min(b.valuefield), max(b.valuefield)
from ( 
    select ntile(10) over (order by valuefield) as 'band', valuefield
    from table ) b
group by b.band

Estás mirando el problema desde el punto de vista equivocado. En lugar de mirar el salario, la posición ordenada de la persona en el rango ordenado de salarios. Ponga el algoritmo a un lado por un segundo y piense en ello matemáticamente.

Toma a toda tu gente y ordenarla por salario. Ahora los numeran secuencialmente desde 1 en hasta n, el último con el salario más alto. Si necesita grupos M, cada grupo contiene personas N/M. Entonces, la primera banda salarial va de 0 a persona [n/m] .SALARY, la segunda pasa de allí a persona [2*n/m] .salary y así sucesivamente.

En C# puedes hacer esto de manera bastante eficiente en Linq. Algo como esto. Este es un código no probado, este es un concepto que no es una solución final, probablemente hay algunos problemas de condición de borde en los que no he pensado bien.

List<int> GetBands(int numBands)
{
    using(var db = new MyContext())    
    {
        var list SalaryBands = new List<int>();
        var count = db.People.Count();
        var salaries = db.People.OrderBy(item => item.Salary)
                                .Select(item => item.Salary);
        int skipCount = count / numBands;
        for(int segmentNum = 0; segmentNum < numBands; segmentCount++)
        {
            salaries = salaries.Skip(skipCount);
            salaryBands.Add(salaries.First());
        }
        return salaryBands;
    }
}

Primera observación, desea un gráfico de registro, en lugar de lineal recto.

Segunda observación: Por lo general, construyo grandes conjuntos de datos de muestras (similar a su ejemplo dado) y luego busco mis factores comunes y obtengo un sistema fórmula de los datos reales. ¿Puedes postular más escenarios?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top