Проблема вычисления n-го процентиля с уменьшением - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть данные перекрестного фильтра с датами (d) и значениями (v):

[
 {d: "2013-07-26T00:00:00.000Z", v: 2.5}
 {d: "2013-07-25T00:00:00.000Z", v: 2.64}
 // ...and many more
[

Я создал группу по месяцам в Crossfilter (crossfilter2@1.4.5):

months = cf.dimension((d) => {
    const dateObj = new Date(d.d);
    // use 1-12 instead of 0-11
    return dateObj.getMonth() + 1;
});

monthsGroup = months.group();

Итак, monthsGroup.all() возвращает массив из 12 объектов, агрегированных по месяцам.Я хочу, чтобы эти объекты включали мин, макс и медиану, а также 25-й и 75-й процентили.Reductio (reductio@0.6.3) помогает с минимальными, максимальными и медианными значениями «из коробки», поэтому я добавил собственный агрегатор для добавления 75-го и 25-го процентилей.

Следующий код работает , но очень медленно:

const monthReducer = reductio()
.valueList(d => d.v)
.min(true)
.max(true)
.median(true)
.count(true)
.custom({
    add(p) {
        const valueList = p.valueList;
        p.p75 = getPercentile(valueList, 75);
        p.p25 = getPercentile(valueList, 25);
        return p;
    },
    remove(p) {
        const valueList = p.valueList;
        p.p75 = getPercentile(valueList, 75);
        p.p25 = getPercentile(valueList, 25);
        return p;
    },
    initial(p) {
        p.p75 = undefined;
        p.p25 = undefined;
        return p;
    },
});

Если я уберу блок .custom, это будет намного быстрее.Это запускает код для каждого элемента в data, что не является необходимым, поскольку нужно только посмотреть на окончательный valueList.Reductio имеет едва документированный хук .post(), который, я думаю, сработает, но я не могу заставить его работать.

ОБНОВЛЕНИЕ: Я получил обратный вызов хука пост-обработкичтобы запустить, но это не работает так, как я ожидал.

Я попытался зарегистрировать новый постпроцессор недокументированным методом, который я видел в источнике:

// register post-processing function to add percentiles
reductio.registerPostProcessor('addPercentiles', (prior) => {
    const all = prior();
    return () => {
        const updated = all.map((e) => {
            const valueList = e.value.valueList;
            e.value.p75 = getPercentile(valueList, 75);
            e.value.p25 = getPercentile(valueList, 25);
            return e;
        });
        return updated;
    };
});

и добавить его вхук post():

// run post-processing to add the 25th & 75th %iles
this.monthsGroup.post().addPercentiles()();

Это похоже на то, что я хочу, но только один раз.Он не перезапускает почтовые хуки, когда фильтр применяется к другому измерению.

Если медиана - это только 50-й процентиль, то также должно быть тривиально, чтобы получить 25-е и 75-е.Я чувствую, что я близко, но я явно делаю что-то не так.Как я могу добавить эти агрегаты к редуктору?

1 Ответ

0 голосов
/ 29 мая 2018

Одним из решений является добавление квантилей вручную, непосредственно перед рендерингом диаграммы.У меня есть функция formatData, которая выполняет форматирование даты / времени и реструктурирует данные, чтобы сделать их более удобными для d3.Поскольку valueList по-прежнему доступен в каждом элементе массива, я просто добавил пару строк, чтобы вычислить там 25-й и 27-й процентили.

Не идеально, но очень просто!

...