2

I need to find peaks in a time series data, but the result needs to be equal to the result of the findpeaks function in MATLAB, with the argument 'MinPeakWidth" set to 10. I have already tried a lot of functions in order to achieve this: pracma::findpeaks, fluoR::find_peaks, splus2R::peaks, IDPmisc::peaks (this one has one argument regarding peak width, but the result is not the same). I have already looked in other functions as well, including packages for chromatography and spectoscropy analysis in bioconductor. Beyond that, I have tried the functions (and little alterations) from this other question in stackoverflow: Finding local maxima and minima

The findpeaks function in MATLAB is used for finding local maximas and has the following charcateristics:

Find the local maxima. The peaks are output in order of occurrence. The first sample is not included despite being the maximum. For the flat peak, the function returns only the point with lowest index.

The explanation for the "MinPeakWidth' argument in MATLAB web site is

Minimum peak width, specified as the comma-separated pair consisting of 'MinPeakWidth' and a positive real scalar. Use this argument to select only those peaks that have widths of at least 'MinPeakWidth'. If you specify a location vector, x, then 'MinPeakWidth' must be expressed in terms of x. If x is a datetime array, then specify 'MinPeakWidth' as a duration scalar or as a numeric scalar expressed in days. If you specify a sample rate, Fs, then 'MinPeakWidth' must be expressed in units of time. If you specify neither x nor Fs, then 'MinPeakWidth' must be expressed in units of samples.

Data Types: double | single | duration

This is the data:

valores <- tibble::tibble(V1 = c(
0.04386573, 0.06169861, 0.03743560, 0.04512523, 0.04517977, 0.02927114, 0.04224937, 0.06596527, 2.15621006, 0.02547804, 0.03134409, 0.02867694,
0.08251871, 0.03252856, 0.06901365, 0.03201109, 0.04214851, 0.04679828, 0.04076178, 0.03922274, 1.65163662, 0.03630282, 0.04146608, 0.02618668,
0.04845364, 0.03202031, 0.03699149, 0.02811389, 0.03354410, 0.02975296, 0.03378896, 0.04440788, 0.46503730, 0.06128226, 0.01934736, 0.02055138,
0.04233819, 0.03398005, 0.02528630, 0.03694652, 0.02888223, 0.03463824, 0.04380172, 0.03297124, 0.04850558, 0.04579087, 1.48031231, 0.03735059,
0.04192204, 0.05789367, 0.03819694, 0.03344671, 0.05867103, 0.02590745, 0.05405133, 0.04941912, 0.63658824, 0.03134409, 0.04151859, 0.03502503,
0.02182294, 0.15397702, 0.02455722, 0.02775277, 0.04596132, 0.03900906, 0.03383408, 0.03517160, 0.02927114, 0.03888822, 0.03077891, 0.04236406,
0.05663730, 0.03619537, 0.04294887, 0.03497815, 0.03995837, 0.04374904, 0.03922274, 0.03596561, 0.03157820, 0.26390591, 0.06596527, 0.04050374,
0.02888223, 0.03824380, 0.05459656, 0.02969611, 0.86277224, 0.02385613, 0.03888451, 0.06496997, 0.03930725, 0.02931837, 0.06021005, 0.03330982,
0.02649659, 0.06600261, 0.02854480, 0.03691669, 0.06584168, 0.02076757, 0.02624355, 0.03679596, 0.03377049, 0.03590172, 0.03694652, 0.03575540,
0.02532416, 0.02818711, 0.04565318, 0.03252856, 0.04121822, 0.03147210, 0.05002047, 0.03809792, 0.02802299, 0.03399243, 0.03466543, 0.02829443,
0.03339476, 0.02129232, 0.03103367, 0.05071605, 0.03590172, 0.04386435, 0.03297124, 0.04323263, 0.03506247, 0.06225121, 0.02862442, 0.02862442,
0.06032925, 0.04400082, 0.03765090, 0.03477973, 0.02024540, 0.03564245, 0.05199116, 0.03699149, 0.03506247, 0.02129232, 0.02389752, 0.04996414,
0.04281258, 0.02587514, 0.03079668, 0.03895791, 0.02639014, 0.07333564, 0.02639014, 0.04074970, 0.04346211, 0.06032925, 0.03506247, 0.04950545,
0.04133673, 0.03835127, 0.02616212, 0.03399243, 0.02962473, 0.04800780, 0.03517160, 0.04105323, 0.03649472, 0.03000509, 0.05367187, 0.03858981,
0.03684529, 0.02941408, 0.04733265, 0.02590745, 0.02389752, 0.02385495, 0.03649472, 0.02508245, 0.02649659, 0.03152265, 0.02906310, 0.04950545,
0.03497815, 0.04374904, 0.03610649, 0.03799523, 0.02912771, 0.03694652, 0.05105353, 0.03000509, 0.02902378, 0.06425520, 0.05660319, 0.03065341,
0.04449069, 0.03638436, 0.02582273, 0.03753463, 0.02756006, 0.07215131, 0.02418869, 0.03431030, 0.04474425, 0.42589279, 0.02879489, 0.02872819,
0.02512494, 0.02450022, 0.03416346, 0.04560013, 1.40417366, 0.04784363, 0.04950545, 0.04685682, 0.03346052, 0.03255004, 0.07296053, 0.04491526,
0.02910482, 0.05448995, 0.01934736, 0.02195528, 0.03506247, 0.03157064, 0.03504810, 0.03754736, 0.03301058, 0.06886929, 0.03994190, 0.05130644,
0.21007323, 0.05630628, 0.02893721, 0.03683226, 0.03825290, 0.02494987, 0.02633410, 0.02721408, 0.03798986, 0.33473991, 0.04236406, 0.02389752,
0.03562747, 0.04662421, 0.02373767, 0.04918125, 0.04478894, 0.02418869, 0.03511514, 0.02871556, 0.05586166, 0.49014922, 0.03406339, 0.84823093,
0.03416346, 0.08729506, 0.03147210, 0.02889640, 0.06181828, 0.04940672, 0.03666858, 0.03019139, 0.03919279, 0.04864613, 0.03720420, 0.04726722,
0.04141298, 0.02862442, 0.29112744, 0.03964319, 0.05657445, 0.03930888, 0.04400082, 0.02722065, 0.03451685, 0.02911419, 0.02831578, 0.04001334,
0.05130644, 0.03134409, 0.03408579, 0.03232126, 0.03624218, 0.04708792, 0.06291741, 0.05663730, 0.03813209, 0.70582932, 0.04149421, 0.03607614,
0.03201109, 0.02055138, 0.03727305, 0.03182562, 0.02987404, 0.04142461, 0.03433624, 0.04264550, 0.02875086, 0.05797661, 0.04248705, 0.04476514))

From the data above, I obtain 22 peaks using pracma::findpeaks function with the code bellow:

picos_r <- pracma::findpeaks(-valores$V1, minpeakdistance = 10)

Using the MATLAB function

picos_matlab = findpeaks(-dado_r, 'MinPeakWidth', 10);

I obtain 11 peaks, as the following:

picos_matlab <- c(-0.02547804, -0.02618668, -0.01934736, -0.02182294, -0.0245572200000000, -0.0202454, -0.02385495, -0.01934736, -0.02373767, -0.02862442, -0.02722065)

I used pracma::findpeaks because it has already given an equal result in another part of the function that I am writting. I have already tried to change the code of the pracma::findpeaks, but with little success.

Juliana
  • 93
  • 1
  • 10

2 Answers2

1

The package cardidates contains a heuristic peak hunting algorithm that can somewhat be fine-tuned using parameters xmax, minpeak and mincut. It was designed for a special problem, but may also used for other things. Here an example:

library("cardidates")

p <- peakwindow(valores$V1)
plot(p) # detects 14 peaks

p <- peakwindow(valores$V1, minpeak=0.18)
plot(p) # detects 11 peaks

Details are described in the package vignette and in https://doi.org/10.1007/s00442-007-0783-2

Another option is to run a smoother before peak detection.

tpetzoldt
  • 5,338
  • 2
  • 12
  • 29
  • Thank you! I am gonna try this! Also, this values are already smoothed. They come from another function. – Juliana May 26 '21 at 06:00
  • As said, the algorithm is different from your description of the Matlab package and has other tuning heuristics. The cardidates algorithm workes well for me, but besides that, I am also interested in peak detection algorithms you found in other R packages. But, if you need an exact replicate of Matlab algorithm, it may necessary to have a look in its source code, if it is available. – tpetzoldt May 26 '21 at 06:03
  • @tptzoldt, I need an exacly replicate of the MATLAB function. I took a look in the source code of MATLAB to even replicate a function, but I am still understanding it. If you have MATLAB, it is located: MATLAB folder in your computer > the folder for the version > toolbox > signal > signal > findpeaks. – Juliana May 26 '21 at 06:11
  • 1
    @tptzoldt, for me, the function that deals well with replicated values is the pracma::findpeaks. The IDPmisc::peaks is also interesting because it has a stepf argument that can be changed to find peaks. The majority of them use diff() to detect the peaks, but in the thread that i have posted above, there are some that computed in diferent ways. – Juliana May 26 '21 at 06:15
  • OK, thanks for the list of tools. I have no Matlab anymore, but found a free `findpeaks.m` code on the net that looks quite easy. Not sure if it is the original algorithm or something different: http://freesourcecode.net/matlabprojects/66577/find-peaks-in-vector--in-matlab The recursive elimiation part is similar to the cardidates algorithm (that itself is based on package **pastecs**), but the elimination criteria are different. – tpetzoldt May 26 '21 at 06:23
  • I found that MATLAB has many functions to findpeaks. The one that I am using is a longer one from signal package (no worries, it has a lot of commentaries and it is weel divided). https://gitlab.esat.kuleuven.be/JohnFredy.MoralesTellez/projectworkdesign/-/blob/3049183a98410f57119a767563f6c06dc0ff1748/gastric_motility/findpeaks.m Please, note that the findpeaks itself is only the first part. The other codes are the definition of the other functions that findpeaks use. – Juliana May 26 '21 at 06:38
  • 2
    There is also the 'gsignal' package which is a reimplementation in R of the 'signal' Octave package and looks quite promising. It contains a `findpeaks()` function. I did not try it out as it was not clear to me what your main test case is. – Hans W. May 27 '21 at 07:04
0

I'm not sure what your test case is: -valores$V1, valores$V1, or -dado_r (what is that)?
I think pracma::findpeaks() does quite well if you do:

x <- valores$V1
P <- pracma::findpeaks(x,
        minpeakdistance = 10, minpeakheight = sd(x))

plot(x, type = 'l', col = 4)
grid()
points(P[,2], P[, 1], pch=20, col = 2)

It finds 11 peaks that stick out while four or five others are too near to be counted. All the smaller ones (standard deviation) are being ignored.

Hans W.
  • 1,799
  • 9
  • 16
  • My test case is ```-valores$V1```. ```-dado_r``` is the name of the variable in MATLAB just to cite. I will test this and give the feedback. Thank you for the help! – Juliana May 28 '21 at 04:33