Here is a function for finding all of the modes (i.e. peaks), in a set of data. The return object is a list of the found peaks by their position (x value), along with their height relative to the highest peak. Plus a lot of other information. To be clear, in a simple case you can just do something like:
order(table(x), decreasing=TRUE)[1]
But I often come across data that is composed of large sets of (potentially) multi-modal, real value numbers, so that method won’t work. Hence the following code:
#
# Examples:
# x = round(runif(1000, min=1, max=23))
# findMode(x)
# findMode(x, smallest.expected=0.5)
# findMode(x, adjust=0.1)
#
findMode <- function (data, smallest.expected=0, ...) {
d = density(data, ...)
maxLocations = vector()
minLocations = vector()
maxHeights = vector()
minDepths = vector()
maxValue = max(d$y)
exactMax = order(table(data), decreasing=TRUE)[1]
# This will not capture the extreme edges as either a min or a max
wasIncreasing <- TRUE;
for (j in 2:length(d$y)) {
# Hit a peak
if (wasIncreasing & (d$y[j] < d$y[j-1])) {
maxLocations = c(maxLocations, d$x[j])
maxHeights = c(maxHeights, d$y[j]/maxValue)
wasIncreasing = FALSE
# Hit a valley
} else if (! wasIncreasing & (d$y[j] > d$y[j-1])) {
minLocations = c(minLocations, d$x[j]);
minDepths = c(minDepths, d$y[j]/maxValue);
wasIncreasing = TRUE;
# In a flat spot
} else if (d$y[j] == d$y[j-1]) {
next;
}
}
# In addition to changing the density estimation model (see 'density'),
# one may want to sweep away tiny peaks that are just noise.
if (smallest.expected > 0) {
if (length(minDepths) > 0) {
if (max(minDepths) > 0) {
# keeperIndex = ((minDepths / max(minDepths)) > smallest.expected);
keeperIndex = (minDepths > smallest.expected);
minDepths = minDepths[keeperIndex];
minLocations = minLocations[keeperIndex];
}
}
# keeperIndex = ((maxHeights / maxValue) > smallest.expected);
keeperIndex = (maxHeights > smallest.expected);
maxHeights = maxHeights[keeperIndex];
maxLocations = maxLocations[keeperIndex];
}
# Collect these features for this channel of the flowFrame
modeList = list();
modeList$exactMax = exactMax
modeList$maximum = d$x[d$y == max(d$y)][1];
modeList$maxima = maxLocations;
modeList$maxHeights = maxHeights;
modeList$minima = minLocations;
modeList$minDepths = minDepths;
return(modeList);
}
Leave a Reply