Количество пиков в гистограмме
У меня есть 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). Поэтому я должен иметь информацию о минимально допустимом расстоянии между пиками. Более того, в моих данных есть отдельные выбросы, которые превышают максимумы этих меньших пиков.
Не могли бы вы предложить какой-то другой подход, как определить количество пиков для данных, аналогичных приведенным на рисунке.