Как динамически генерировать полосы/группы данных с одинаковыми числами в каждом?
-
12-10-2019 - |
Вопрос
Я хочу динамически генерировать полосы, которые затем будут сгруппированы в отчетах.
Моей первой мыслью было генерировать полосы, взяв минимальное значение и максимальное значение, а затем разделение разницы.
Например, предположим, что у вас была зарплата для большой группы людей:
- Самая низкая оплаченная зарабатывает 12 000 фунтов стерлингов в год, а самый высокий зарабатывает 3 000 000 фунтов стерлингов
- Поэтому я разделил это на 10 полос аналогичного размера: (3 миллиона фунтов стерлингов - 12 тыс. Фунтов стерлингов) / 10 = £ 298800
- Итак, моя первая группа стоит от 12 до 310 800 фунтов стерлингов и получает тысячи людей
- Моя вторая группа стоит от 310 тысяч фунтов стерлингов и имеет несколько сотен
- У любой другой группы есть несколько человек в каждой
Так что это на самом деле не очень полезно. Если бы я был вручную создать группы, которые я бы хотел примерно аналогичных цифр в каждом, что-то вроде: 12 тыс. Фунтов стерлингов, 14 тыс. Фунтов стерлингов, 18 тысяч фунтов стерлингов, 25 тыс. Фунтов стерлингов, 25-35 тыс. Фунтов стерлингов, ..., £ 1,5- 3 миллиона фунтов стерлингов
Это только один пример - может быть много разных распределений.
Я ищу алгоритм для генерации полос, поэтому пользователи вводят, сколько групп они хотят, и данные будут сгруппированы в столько полос с одинаковым числом в каждой.
Беспочка должна быть быстрой - я не могу просто пройти через весь набор данных.
Приложение C# в верхней части SQL, но решения от других языков приветствуются.
Решение
Я думаю, вы спрашиваете о том, как запросить существующий набор данных в «группах» ...
Если это правда, то Oracle поддерживает функции NTILE Agagerate для этого. Должны быть эквиваленты в других реализациях SQL.
Другие советы
Вы смотрели на Ntile? SQL Server и большинство СУБД поддерживают его.
Например:
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
Вы смотрите на проблему с неправильной точки зрения. Вместо того, чтобы смотреть на зарплату, посмотрите на упорядоченное положение человека в сортированном диапазоне зарплат. Отложите алгоритм на секунду и подумайте об этом математически.
Возьмите всех своих людей и сортируйте их по зарплате. Теперь последовательно насчиская их с 1 на n до N, последний с самой высокой зарплатой. Если вам нужны M группы, то каждая группа содержит N/M. Таким образом, первая полоса зарплаты переходит от 0 до человека [N/M] .salary, вторая идет оттуда к человеку [2*n/M] .salary и т. Д.
В C# вы можете сделать это довольно эффективно в LINQ. Что-то вроде этого. Это непроверенный код, это концепция, а не окончательное решение, вероятно, есть некоторые проблемы с условием края, о которых я не думал правильно.
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;
}
}
Первое наблюдение, вам нужен логический график, в отличие от прямой линейной.
Второе наблюдение: я обычно строю большие наборы данных выборки (сродни вашим примеру), а затем ищу свои общие факторы и получаю формальную систему из фактических данных. Можете ли вы создать еще несколько сценариев?