Как сделать логарифмический биннинг на гистограмме?

Я ищу метод логарифмического бинирования некоторых наборов данных. У нас есть данные со значениями в диапазоне от _min до _max (число с плавающей запятой >= 0), и пользователь должен иметь возможность указать различное количество ячеек _num_bins. (некоторые целые n).

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

class Histogram {
double _min, _max;
int _num_bins;
......
};

double Histogram::logarithmicValueOfBin(double in) const {
    if (in == 0.0)
        return _min;

    double b = std::log(_max / _min) / (_max - _min);
    double a = _max / std::exp(b * _max);

    double in_unscaled = in * (_max - _min) / _num_bins + _min;
    return a * std::exp(b * in_unscaled) ;
}

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


person Boumbles    schedule 23.09.2015    source источник
comment
Не используйте [float/double] == [value]. Потому что компьютеры не могут представлять точные значения. Вместо этого используйте эпсилон: if(std::abs(in - x) < 0.00001) (или другое приемлемое маленькое значение).   -  person Casey    schedule 23.09.2015
comment
coliru.stacked-crooked.com/a/2bf7eaa25bcf1b9b ?   -  person Mooing Duck    schedule 20.11.2020
comment
Если вы готовы пожертвовать значительной точностью, frexp и ldexp могут сделать это действительно быстрым. coliru.stacked-crooked.com/a/5f7477995f36930f   -  person Mooing Duck    schedule 20.11.2020


Ответы (2)


Я нашел решение, повторно реализовав версию функции logspace Matlab с открытым исходным кодом .

Учитывая диапазон и количество ячеек, вам нужно создать равномерно распределенную числовую последовательность

module.exports = function linspace(a,b,n) {
  var every = (b-a)/(n-1),
      ranged = integers(a,b,every);

  return ranged.length == n ? ranged : ranged.concat(b);
}

После этого вам нужно перебрать каждое значение и с вашей базой (скорее всего, e, 2 или 10) сохранить мощность, и вы получите свои диапазоны ячеек.

module.exports.logspace = function logspace(a,b,n) {
  return linspace(a,b,n).map(function(x) { return Math.pow(10,x); });
}

Я переписал это на С++, и он поддерживает диапазоны > 0.

person Boumbles    schedule 06.10.2015

Вы можете сделать что-то вроде следующего

// Create isolethargic binning
    int     T_MIN   = 0;                    //The lower limit i.e. 1.e0
    int     T_MAX   = 8;                    //The uper limit   i.e. 1.e8
    int     ndec    = T_MAX - T_MIN;        //Number of decades
    int     N_BPDEC = 1000;                 //Number of bins per decade
    int     nbins   = (int) ndec*N_BPDEC;   //Total number of bins
    double  step    = (double) ndec / nbins;//The increment 
    double  tbins[nbins+1];                 //The array to store the bins

    for(int i=0; i <= nbins; ++i)
        tbins[i] = (float) pow(10., step * (double) i + T_MIN);
person Thanos    schedule 20.11.2020