Количество пиков в гистограмме

У меня есть 1D данные, которые представляют некоторые значения интенсивности. Я хочу определить количество компонентов в этих данных (кластеры точек с одинаковой интенсивностью или, альтернативно, количество «пиков» в гистограмме, созданной из этих данных).

Этот подход:1D обнаружение множественных пиков? это не очень полезно для меня, потому что один «пик» может содержать больше локальных максимумов (см. изображение ниже).

Конечно, я могу использовать статистический подход, например, я могу попытаться подобрать данные для 1,2,3, .... п пиков, а затем рассчитатьBIC, AIC или что угодно для каждой подгонки. И, наконец, использоватьметод локтя для определения количества кластеров. Тем не менее, я хочу определить приблизительное количество пиков как можно быстрее, и подгонка гауссовой смеси - довольно трудоемкая процедура.

Мой подход

Поэтому я пришел к следующему подходу (в C ++). Он принимает значения высоты гистограмм (y) и ищет индексы, в которых значения y начинают снижаться. Затем значения ниже допуска y (yt) фильтруются. И наконец, индексы, близкие к другим, использующие x допуск (xt), тоже фильтруются:

Indices StatUtils::findLocalMaximas(const Points1D &y, int xt, int yt) {

  // Result indices
  Indices indices;

  // Find all local maximas
  int imax = 0;
  double max = y[0];
  bool inc = true;
  bool dec = false;
  for (int i = 1; i < y.size(); i++) {    

    // Changed from decline to increase, reset maximum
    if (dec && y[i - 1] < y[i]) {
      max = std::numeric_limits<double>::min();
      dec = false;
      inc = true;
    }

    // Changed from increase to decline, save index of maximum
    if (inc && y[i - 1] > y[i]) {
       indices.append(imax);
       dec = true;
       inc = false;
    }

    // Update maximum
    if (y[i] > max) {
       max = y[i];
       imax = i;
    }
  }

  // If peak size is too small, ignore it
  int i = 0;
  while (indices.count() >= 1 && i < indices.count()) {
    if (y[indices.at(i)] < yt) {
      indices.removeAt(i);
    } else {
      i++;
    }
  }

  // If two peaks are near to each other, take only the largest one
  i = 1;
  while (indices.count() >= 2 && i < indices.count()) {
    int index1 = indices.at(i - 1);
    int index2 = indices.at(i);
    if (abs(index1 - index2) < xt) {
      indices.removeAt(y[index1] < y[index2] ? i-1 : i);
    } else {
      i++;
    }
  }
  return indices;
}

Проблема с подходом

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

Не могли бы вы предложить какой-то другой подход, как определить количество пиков для данных, аналогичных приведенным на рисунке.

Ответы на вопрос(1)

Ваш ответ на вопрос