Выполнение поиска в разреженных массивах Javascript

У меня есть интересная задача Javascript (выполненная в Node.js, FWIW): мне нужно взять «взвешенную медиану» набора данных, для которого у меня есть значения (в данном случае доход) и вес для каждого из них. Например:

income  #people
0   5
16000   3
20000   8
32000   4
40000   3
41000   1
50000   2
90000   1

Другими словами, 8 человек зарабатывают 20 тысяч долларов, 2 — 50 тысяч долларов и т. д. Мне нужна «взвешенная медиана» — медиана всех 27 человек.

Наивным способом сделать это было бы создать массив и заполнить его каждым значением, например так:

var incomes = [0, 0, 0, 0, 0, 16000, 16000, 16000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 32000, 32000, 32000, 32000, 40000, 40000, 40000, 41000, 50000, 50000, 90000];

Затем можно легко взять медиану этого массива (что составляет 20 000 долларов). На самом деле у меня есть данные от 7 000 до 14 000 человек на выборку. Хотя я уверен, что Node справится с таким большим массивом, он кажется невероятно неаккуратным.

Мое текущее решение состоит в том, чтобы вычислить индекс медианного значения в гипотетическом подробном массиве — 13, в данном случае — и пройтись по массиву доходов и весов, складывая совокупный вес до тех пор, пока он не достигнет или не превысит точку на полпути. . Вот упрощенный пример. (Очевидно, что медианы требуют несколько иных правил для списков с четными номерами. Это просто POC.)

var halfway = 13,
    progress = 0;

var vals = [[0,5], [16000,3], [20000,8], [32000,4], [40000,3], [41000,1], [50000,2], [90000,1]];

for (var v = 0; v < vals.length; v += 1) {
    progress += vals[v][1];

    if (progress >= halfway) {
        var median = vals[v][0];
        break;
    }
}

Это работает нормально, но становится грязным, когда вы хотите начать вычислять квартили и так далее. Что было бы проще для меня, так это иметь возможность создать разреженный массив значений в соответствующем месте в подробном массиве, не заполняя все промежуточные значения, а затем выполнять поиск в этом массиве для любого индекса до максимума. Но мне нужен эффективный механизм для поиска предыдущего известного индекса в разреженном массиве, если (что вполне вероятно) индекс, который я ищу в запасном массиве, не заполнен.

Кажется, это должна быть довольно распространенная проблема.


person Chris Wilson    schedule 24.09.2014    source источник
comment
Глупый вопрос, но: вы пробовали с vals.forEach(function (element, i, array){});   -  person DrakaSAN    schedule 24.09.2014
comment
Не уверен, что это будет отличаться от зацикливания по старинке, как я сделал выше. (Я сделал это так, потому что легче вырваться.)   -  person Chris Wilson    schedule 24.09.2014
comment
Сколько различных доходов вам нужно обрабатывать? Будут ли у многих из тысяч людей разные доходы?   -  person parchment    schedule 24.09.2014
comment
Потенциально тысячи, да - это данные переписи населения. Я понимаю, что это не самая естественная задача для Node, но это то, что я знаю.   -  person Chris Wilson    schedule 24.09.2014
comment
Почему бы вам не использовать объект, где ключом была сумма дохода, а значением было количество людей, которые имели именно этот доход. Вы можете перебирать все доходы, просто перебирая свойства объекта, и у вас есть мгновенный доступ к любому значению дохода и количеству людей с этим доходом. Также более компактно хранить дублирующиеся значения дохода для каждого человека.   -  person jfriend00    schedule 24.09.2014
comment
Как мне перейти от этого решения к среднему значению?   -  person Chris Wilson    schedule 24.09.2014


Ответы (1)


Что касается вычислительной эффективности, я думаю, что то, что у вас есть, примерно так же хорошо, как вы собираетесь получить, хотя я не уверен, с какими трудностями вы сталкиваетесь с квартилями (извините, слишком низкая репутация, чтобы попросить разъяснений по этому поводу).

Давайте начнем с оценки эффективности того, что у вас есть. У вас есть массив длины n, и вы проходите через него, добавляя к счетчику и прерывая его на полпути (я предполагаю, что информация о полпути была дана, опять же, извините, слишком мало, чтобы спросить). Так что неплохо было посмотреть на простой O(n).

Теперь то, что вы предлагаете, представляет собой некоторую форму поиска, которая по заданному индексу знает ближайший заполненный индекс, O (1). Что ж, так будет лучше, так что давайте посмотрим, что нам для этого понадобится. Что ж, нам нужно будет переместить данные данные в какую-то новую структуру данных, прокручивая их в цикле..... О, упс, это означает, что мы вернулись к O (n).

Мораль истории то, что у вас есть хорошая, хорошая работа.

person neverlucky13    schedule 24.09.2014