使用Javascript查找数组的峰

时间:2019-02-26 13:46:17

标签: javascript graph

我有一个640个值的数组,其中包含画一条线所需的y值。

Line

我需要确定每个三个峰的顶部的阵列位置。

我在这里查看了与局部最大值/局部最小值有关的类似问题,但是运行我发现的代码会遇到一些小的问题。我只需要三个非常不同的峰。

我正在尝试使用Javascript执行此操作。来自数组的数据如下:

126,126,126,126,126,126,126,126,126,126,126,126,126,126,124,123,122,122,120,119,119,118,118,118,119,119,119,120,121,121,122,124,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,124,125,124,125,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,123,124,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,122,123,122,123,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,119,119,119,119,116,115,114,113,113,113,113,113,115,117,118,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,108,107,106,118,108,108,103,103,103,103,103,103,104,105,107,108,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109

我在数组上运行了这段代码:

    function pickPeaks(arr){
  return arr.reduce( (res, val, i, self) => {
    if(
      // a peak when the value is greater than the previous and greater than the next
      val > self[i - 1] && val > self[i + 1] 
      || 
      // a plateau when the value is greater than the previuos and equal to the next and from there the next different value is less
      val > self[i - 1] && val === self[i + 1] && self.slice(i).find( item =>  item !== val ) < val 
    ){
      res.pos.push(i);
      res.peaks.push(val);
    }
    return res;
  }, { pos:[],peaks:[] } );
}

console.log(pickPeaks(first_black_array))

并输出以下内容:

peaks: (9) [362, 356, 356, 357, 358, 358, 367, 374, 377]
pos: (9) [21, 67, 69, 112, 179, 181, 313, 608, 612]

我希望结果是这样的:

pos: [24, 316, 616]

(每个峰的顶部)

非常感谢

3 个答案:

答案 0 :(得分:2)

要扩大我的评论,类似

function detectPeaks(data, windowWidth, threshold) {
  const peaks = [];
  for (let i = 0; i < data.length; i++) {
    const start = Math.max(0, i - windowWidth);
    const end = Math.min(data.length, i + windowWidth);
    let deltaAcc = 0;
    for (let a = start; a < end; a++) {
      deltaAcc += Math.abs(data[a - 1] - data[a]);
    }
    if (deltaAcc > threshold) {
      peaks.push(i);
    }
  }
  return peaks;
}

找到“峰值”(或者说是价值变化比其他地方变化多的区域)很好。

您可以在https://codepen.io/akx/pen/QowEQq上找到一个交互式示例,在这里您还可以调整窗口宽度和阈值。

答案 1 :(得分:0)

与先前的值相比,您可以查找较小的值,并通过更新最后一个最小值的索引来查找,如果值增加,则按新的最小值。

实际上,根据问题,此方法返回的索引最小值为608,否则不应为最小值。也许您需要过滤的最小值最小值太小。

var data = [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 124, 123, 122, 122, 120, 119, 119, 118, 118, 118, 119, 119, 119, 120, 121, 121, 122, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 124, 125, 124, 125, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 123, 124, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 123, 122, 123, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 116, 115, 114, 113, 113, 113, 113, 113, 115, 117, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 108, 107, 106, 118, 108, 108, 103, 103, 103, 103, 103, 103, 104, 105, 107, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109],
    push = true,
    last = 0,
    result = data.reduce((r, v, i, a) => {
        if (a[r[last]] === v) {                  // take latest index of series
            r[last] = i;
            return r;
        }
        if (a[i - 1] < v) {                      // look for new series
            push = true;
            return r;
        }
        if (a[i - 1] > v) {
            if (push && a[i - 1] > a[r[last]]) { // prevent continuing minima
                last = r.push(i) - 1;
                push = false;
            } else {
                r[last] = i;
            }
        }
        return r;
    }, []);


console.log('values ', result.map(i => data[i].toString().padStart(3)).join(' '));
console.log('indices', result.map(v => v.toString().padStart(3)).join(' '));

答案 2 :(得分:0)

此功能将遍历您的数据并确定数据中最大的过渡。然后它将对它们进行协调,以便在获取n条记录时不会向您输出相同的峰。

   function getPeaks(data, n = 3, peakList = []) {
      return data.reduce((a, v, i, _a,
          end_index = _a.length - 1,
          change = v - _a[i - 1] || 0,
          mate = i + Math.sign(change),
          _ = (change) && a.peaks.push({change,i,mate})
        ) => (i === end_index) ?
        (a.peaks.forEach(_ =>
            (!peakList.includes(_.i) && (mate = a.peaks.find(__ =>
              __.i === _.mate))) && (a.samePeak.push({
              highpoint: data[_.i] > data[mate.i] ? _.i : mate.i,
              steepness: mate.change > _.change ? mate.change : _.change
            })),
            peakList.push(_.i, mate.i)),
          a.samePeak.sort((_, __) =>
            __.steepness - _.steepness)
          .map(_ => _.highpoint)
          .slice(0, n)) : a, {
          peaks: [],
          samePeak: []
        })
    }

let data = [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 124, 123, 122, 122, 120, 119, 119, 118, 118, 118, 119, 119, 119, 120, 121, 121, 122, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 124, 125, 124, 125, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 123, 124, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 123, 122, 123, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 116, 115, 114, 113, 113, 113, 113, 113, 115, 117, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 108, 107, 106, 118, 108, 108, 103, 103, 103, 103, 103, 103, 104, 105, 107, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109]


function getPeaks(data, n = 3, peakList = []) {
  return data.reduce((a, v, i, _a,
      end_index = _a.length - 1,
      change = v - _a[i - 1] || 0,
      mate = i + Math.sign(change),
      _ = (change) && a.peaks.push({
        change,
        i,
        mate
      })
    ) => (i === end_index) ?
    (a.peaks.forEach(_ =>
        (!peakList.includes(_.i) && (mate = a.peaks.find(__ =>
          __.i === _.mate))) && (a.samePeak.push({
          highpoint: data[_.i] > data[mate.i] ? _.i : mate.i,
          steepness: mate.change > _.change ? mate.change : _.change
        })),
        peakList.push(_.i, mate.i)),
      a.samePeak.sort((_, __) =>
        __.steepness - _.steepness)
      .map(_ => _.highpoint)
      .slice(0, n)) : a, {
      peaks: [],
      samePeak: []
    })
}

//getpeaks(data, number of peaks to get)

console.log( getPeaks(data, 3) );


诚然,当我经历-时,它变得有些模糊::)这是一个更清晰的版本:

function getPeaks(data, n = 3, peakList = [] ) {
    return data.reduce( ( a, v, i, _a, end_index = _a.length - 1 ) => {
        change = v - _a[ i - 1 ] || 0,
            mate = i + Math.sign( change ),
            payload = {
                change,
                i,
                mate
            };
        if ( change ) a.peaks.push( payload );
        return ( i === end_index ) ? ( a.peaks.forEach( _ => {
            if ( peakList.includes( _.i ) ) return;
            if ( mate = a.peaks.find( __ => __.i === _.mate ) ) {
                a.samePeak.push( {
                        highpoint: data[ _.i ] > data[ mate.i ] ? _.i : mate.i,
                        steepness: mate.change > _.change ? mate.change : _.change
                } )
                peakList.push( _.i, mate.i );
            }
        } ), a ) : a;
    }, {
        peaks: [],
        samePeak: []
    } ).samePeak.sort( ( _, __ ) => __.steepness - _.steepness )
  .map(({highpoint})=>highpoint)
  .slice( 0, n );
}

    function getPeaks(data, n = 3, peakList = [] ) {
    	return data.reduce( ( a, v, i, _a, end_index = _a.length - 1 ) => {
    		change = v - _a[ i - 1 ] || 0,
    			mate = i + Math.sign( change ),
    			payload = {
    				change,
    				i,
    				mate
    			};
    		if ( change ) a.peaks.push( payload );
    		return ( i === end_index ) ? ( a.peaks.forEach( _ => {
    			if ( peakList.includes( _.i ) ) return;
    			if ( mate = a.peaks.find( __ => __.i === _.mate ) ) {
    				a.samePeak.push( {
    						highpoint: data[ _.i ] > data[ mate.i ] ? _.i : mate.i,
    						steepness: mate.change > _.change ? mate.change : _.change
    				} )
    				peakList.push( _.i, mate.i );
    			}
    		} ), a ) : a;
    	}, {
    		peaks: [],
    		samePeak: []
    	} ).samePeak.sort( ( _, __ ) => __.steepness - _.steepness )
      .map(({highpoint})=>highpoint)
      .slice( 0, n );
    }

console.log( getPeaks(data, 3) );