как сделать комплексную редукцию кроссфильтра

Я пытаюсь создать переменную для вставки dc.js с использованием настраиваемого сокращения (reduceAdd, reduceRemove и т. Д.), И мне сложно понять, как ее закодировать.

Я написал функцию вне этих функций сокращения и теперь должен воспроизвести те же самые функции сокращения, чтобы использовать то же самое для построенных графиков. Логика и код, написанные для внешних функций сокращения, следующие

Логика: для каждой уникальной доступной contact_week (дат) найдите максимальное значение week_number, затем просуммируйте переменную TOTCOUNT и переменную DECAY_CNT и вычислите процент (DECAY_CNT / TOTCOUNT).

Вот исходный код без использования кроссфильтра:

 //Decay % logic   
  var dates = d3.map(filter1,function(d) { return d.CONTACT_WEEK;}).keys() ;
  console.log(dates);
  var sum1,sum2 = 0;


  for(var i=0; i<dates.length; i++)
    {
      data1 = filter1.filter(function(d) { return d.CONTACT_WEEK == dates[i] ;});
      //console.log(data1);
      var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
      //console.log(max);
      data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});

      var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
      var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});
      console.log(sum1);
      var decay = sum2/sum1 * 100 ;
      console.log(decay); 

    } 

Первым шагом в этом является определение уникальных значений дат (contact_week). Как мне сделать это в функциях сокращения, поскольку это уже цикл for, который просматривает данные?

Я думаю, что для max и т. Д. Мы можем использовать reductio или какую-либо другую логику, как указано в комментариях, но я не совсем понимаю подход / дизайн, которому здесь нужно следовать

Любая помощь в подходе / решениях будет принята с благодарностью.

ОБНОВЛЕНИЕ 2:

Пробуем новый подход с помощью reductio js

Пояснение к данным:

Несколько столбцов в моих данных - contact_week (даты); номер_недели (числа - от -4 до 6); decay_cnt (целые числа); totcount (целые числа); продолжительность (порядковые значения - до, во время и после);

Теперь мне нужно рассчитать процент распада, который рассчитывается следующим образом: Для каждой уникальной contact_week найдите максимальное значение week_number, теперь для этого отфильтрованного набора данных вычислите сумму (decay_cnt) / sum (totcount)

Это должно быть нанесено на гистограмму, где по оси X отложена длительность, а по оси Y - показатель распада%.

Пытаясь вычислить максимальное количество номеров недель для отдельных дат, я на данный момент построил гистограмму с contact_week в качестве оси X и max of week_number в качестве оси Y. Как мне получить нужную мне диаграмму?

Код:

dateDimension2  = ndx.dimension(function(d) {return d.CONTACT_WEEK ;});
decayGroup = reductio().max(function (d) { return d.WEEK_NUMBER; })(dateDimension2.group());


chart2
    .width(500)
    .height(200)
    .x(d3.scale.ordinal())
    //.x(d3.scale.ordinal().domain(["DURING","POST1"]))
    .xUnits(dc.units.ordinal)
    //.xUnits(function(){return 10;})
    //.brushOn(false)
    .yAxisLabel("Decay (in %)")
    .dimension(dateDimension)
    .group(decayGroup)
    .gap(10)
    .elasticY(true)
    //.yAxis().tickValues([0, 5, 10, 15])
    //.title(function(d) { return d.key + ": " + d3.round(d.value.new_count,2); })
    /*.valueAccessor(function (p) {
    //return p.value.count > 0 ? (p.value.dec_total / p.value.new_count) * 100  : 0;
    return p.value.decay ;
    })*/
    .valueAccessor(function(d) { return d.value.max; })
    .on('renderlet', function(chart) {
        chart.selectAll('rect').on("click", function(d) {
            console.log("click!", d);
        });
    })
    .yAxis().ticks(5);

Любой подход / предложения будут высоко оценены

Я думаю, что решение в основном заключается в комбинированном подходе поддельных групп / размеров и сокращения js. Любые альтернативы приветствуются!


person Pravin Singh    schedule 28.12.2015    source источник
comment
Пожалуйста, покажите код reduceAdd / reduceRemove, вызывающий ошибку. Лучше всего создать рабочий пример проблемы на jsfiddle или подобном сайте.   -  person Ethan Jewett    schedule 28.12.2015
comment
Хорошая новость заключается в том, что основной цикл и первый фильтр должны обрабатываться группами кросс-фильтров автоматически. Плохая новость заключается в том, что кроссфильтр не имеет встроенных элементов типа min / max, и их сложно сделать эффективно. В конечном итоге вы сохраняете ссылку на строки в каждой ячейке. Если вы будете поискать, вы найдете для этого различные коды, например stackoverflow.com/a/32925852/676195 - IIUC ваша проблема - это просто более сложное сокращение для того же типа данных.   -  person Gordon    schedule 28.12.2015
comment
reductio также имеет минимальные и максимальные значения, но я не знаю, поддерживает ли он фильтрацию строк в корзине. и сокращение на них. Интересный дизайнерский вызов, @Ethan!   -  person Gordon    schedule 28.12.2015
comment
@Gordon С Reductio это можно сделать почти, но я думаю, что не совсем. Он поддерживает предикаты фильтра и вычисление минимума / максимума, но фильтрация по минимальному / максимальному значению является проблемой. Мне просто непонятно, что именно семантически означает фильтрация по минимальному / максимальному значению. Рабочий пример, вероятно, прояснил бы.   -  person Ethan Jewett    schedule 29.12.2015
comment
@EthanJewett: Сейчас использовал reductio js и обновил вопрос. Посмотрите, когда бесплатно   -  person Pravin Singh    schedule 07.01.2016
comment
Я не уверен, почему за это отказывают - возможно, потому, что вы попросили, пожалуйста, закодируйте это для меня каким-то образом. Это законный вопрос, поскольку для такого рода проблем не так много инфраструктуры. Я начал работу над решением, но хочу сделать его общим, чтобы помочь другим. Отправлю позже сегодня.   -  person Gordon    schedule 07.01.2016
comment
Я прошу прощения за то, что reductio может быть ложным. Я в основном пытался указать на то, что это интересная проблема, в которой reductio можно было бы расширить, чтобы помочь. Я не думаю, что здесь нужны поддельные группы, потому что форма бункеров легко обрабатывается кросс-фильтром. Это просто сложная редукция.   -  person Gordon    schedule 07.01.2016


Ответы (1)


Я только что добавил FAQ и пример для такого рода проблем.

Как объясняется там, идея состоит в том, чтобы поддерживать массив строк, которые попадают в каждую корзину, поскольку перекрестный фильтр не выполняет пока не предоставляю к этому доступ. Как только мы получим фактические строки, ваши расчеты будут почти такими же, как и сейчас, за исключением того, что кросс-фильтр отслеживает для вас список недель.

Итак, вы можете использовать эти функции из примера:

  function groupArrayAdd(keyfn) {
      var bisect = d3.bisector(keyfn);
      return function(elements, item) {
          var pos = bisect.right(elements, keyfn(item));
          elements.splice(pos, 0, item);
          return elements;
      };
  }

  function groupArrayRemove(keyfn) {
      var bisect = d3.bisector(keyfn);
      return function(elements, item) {
          var pos = bisect.left(elements, keyfn(item));
          if(keyfn(elements[pos])===keyfn(item))
              elements.splice(pos, 1);
          return elements;
      };
  }

  function groupArrayInit() {
      return [];
  }

Вам необходимо иметь уникальный ключ в ваших записях, чтобы их можно было надежно добавлять и удалять. Я предполагаю, что в ваших записях есть поле ID.

Определите размер недели и группу следующим образом:

var weekDimension = ndx.dimension(function(d) {return d.CONTACT_WEEK ;}),
    id_function = function(r) { return r.ID; },
    weekGroup = weekDimension.group().reduce(groupArrayAdd(id_function), groupArrayRemove(id_function), groupArrayInit);

Тогда наиболее эффективное время для расчета вашей метрики - это когда это необходимо, в методе доступа к значению. Таким образом, вы можете определить свой аксессуар значения с помощью кода, который вы разместили в своем вопросе.

(Конечно, этот код не тестировался, потому что я не знаю ваших данных.)

var calculateDecay = function(kv) {
    // kv.value has the array produced by the reduce functions.
    var data1 = kv.value;
    var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
    data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});

    var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
    var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});

    var decay = sum2/sum1 * 100 ;
    return decay;
}

chart.valueAccessor(calculateDecay);
person Gordon    schedule 07.01.2016
comment
Это здорово, наконец-то работает с правильными значениями! Прежде всего, спасибо за все усилия и огромную помощь! Однако в моем вопросе осталось одно простое (или хитрое) предостережение: я хочу, чтобы размерность была DURATION (а не contact_week). Ось X должна показывать продолжительность в порядковом порядке. (Раньше я просто тестировал с помощью contact_week). Данные описаны выше в однострочном виде, продолжительность - это просто еще один столбец (значения - во время, до, после и т. Д.). Это возможно? Я пробовал изменить имена измерений, но это не помогает, так как они связаны с группой. Пожалуйста, дайте мне знать, как это сделать - person Pravin Singh; 07.01.2016
comment
Я не понимаю, как это влияет на основной вопрос. Разве вы не можете просто соответствующим образом определить размер и использовать те же функции сокращения, которые я описал? - person Gordon; 07.01.2016
comment
Ой, как плохо! Я пробовал что-то другое. Он отлично работает, и вы решили вопрос! Большое спасибо, Гордон! - person Pravin Singh; 07.01.2016
comment
Отлично! Рад помочь и приятно иметь повод разработать канонический ответ на часто задаваемый вопрос. - person Gordon; 07.01.2016
comment
Что ж, фарм голосов в обществе презирают, так что я не буду этого делать. Но, надеюсь, если люди сочтут этот вопрос полезным, он получит положительный результат. Ненавистники должны ненавидеть, и, к сожалению, у нас есть некоторые ненавистники вокруг этого тега. - person Gordon; 08.01.2016
comment
Конечно, Гордон! Еще раз спасибо всем за помощь. Ваше здоровье! - person Pravin Singh; 08.01.2016
comment
Рад, что это сработало :-) И, основываясь на ответе Гордона, я почти уверен, что могу подтвердить, что Reductio не может этого сделать - по крайней мере, на данный момент. У меня такое ощущение, что многие вопросы в этом теге отклоняются, потому что люди приходят из тега javascript и думают, что это тривиальный вопрос относительно Array.map/Array.reduce. К сожалению, я бы рекомендовал не помещать тег javascript в вопросы Crossfilter. : - / - person Ethan Jewett; 09.01.2016
comment
@EthanJewett: Да, я довольно долго пробовал reductio, но не смог получить нужные графики (много циклов, проблем и т. Д.). На данный момент удален тег javascript, надеюсь, этот вопрос поможет другим делать то же самое. Кстати, видел оба ваших обсуждения на github (о сложном сокращении), еще раз спасибо за помощь! - person Pravin Singh; 11.01.2016