একটি সিরিজের ডেটাতে স্থানীয় শিখর / উপত্যকাগুলি কীভাবে সন্ধান করবেন?


17

এখানে আমার পরীক্ষা:

আমি কোয়ান্টমোড প্যাকেজে findPeaksফাংশনটি ব্যবহার করছি :

আমি সহনীয়তার 5 এর মধ্যে "স্থানীয়" শৃঙ্গগুলি সনাক্ত করতে চাই, অর্থাত্ প্রথম সিরিজের স্থানীয় শিখর থেকে 5 দ্বারা নামার পরে:

aa=100:1
bb=sin(aa/3)
cc=aa*bb
plot(cc, type="l")
p=findPeaks(cc, 5)
points(p, cc[p])
p

আউটপুট হয়

[1] 3 22 41

এটি ভুল বলে মনে হচ্ছে, যেহেতু আমি 3 এর চেয়ে বেশি "স্থানীয় শিখর" প্রত্যাশা করছি ...

কোন চিন্তা?


আমার এই প্যাকেজটি নেই। আপনি যে সংখ্যাটি ব্যবহার করছেন তা বর্ণনা করতে পারবেন?
অ্যাডামো

findPeaksআমার উত্তরটিতে পূর্ণ উত্সের কোডটি প্রদর্শিত হবে, @ অ্যাডাম। বিটিডাব্লু , প্যাকেজটি "কোয়ান্টামোড"
whuber

ক্রস আর-সিগ-ফিনান্সে পোস্ট করা হয়েছে ।
জোশুয়া আলরিখ

উত্তর:


8

এই কোডটির উত্সটি আর প্রম্পটে এর নাম টাইপ করে প্রাপ্ত হয়। আউটপুট হয়

function (x, thresh = 0) 
{
    pks <- which(diff(sign(diff(x, na.pad = FALSE)), na.pad = FALSE) < 0) + 2
    if (!missing(thresh)) {
        pks[x[pks - 1] - x[pks] > thresh]
    }
    else pks
}

পরীক্ষাটি তত্ক্ষণাত সিরিজটিতে সফল হওয়ারx[pks - 1] - x[pks] > thresh সাথে প্রতিটি শীর্ষের মানটির সাথে তুলনা করে (সিরিজের পরবর্তী কালের সাথে নয়)। এটি শিখরের পরপরই ফাংশনের opeালের আকারের একটি (অশোধিত) প্রাক্কলন ব্যবহার করে এবং কেবলমাত্র সেই শিখাগুলিই নির্বাচন করে যেখানে slাল আকারে অতিক্রম করে। আপনার ক্ষেত্রে, পরীক্ষায় উত্তীর্ণ হওয়ার জন্য কেবল প্রথম তিনটি পীকই যথেষ্ট তীক্ষ্ণ। আপনি ডিফল্ট ব্যবহার করে সমস্ত শিখর সনাক্ত করতে পারবেন:thresh

> findPeaks(cc)
[1]  3 22 41 59 78 96

30

আমি whuber এর প্রতিক্রিয়ার সাথে একমত কিন্তু কেবল কোডটির "+2" অংশটি যুক্ত করতে চেয়েছিলাম, যা সদ্য পাওয়া চূড়ান্তটিকে আসলে 'ওভারশুট'-এর সাথে মেলে সূচিটি পরিবর্তনের চেষ্টা করে এবং "+1" হওয়া উচিত। উদাহরণস্বরূপ আমরা হাতে পাওয়া উদাহরণটিতে:

> findPeaks(cc)
[1]  3 22 41 59 78 96

যখন আমরা কোনও গ্রাফে এই পাওয়া পর্বতগুলি হাইলাইট করি (গা bold় লাল): এখানে চিত্র বর্ণনা লিখুন

আমরা দেখতে পাচ্ছি যে তারা ক্রমাগত প্রকৃত শীর্ষ থেকে 1 পয়েন্ট দূরে।

consequenty

pks[x[pks - 1] - x[pks] > thresh]

হতে হবে pks[x[pks] - x[pks + 1] > thresh] বাpks[x[pks] - x[pks - 1] > thresh]

বড় আপডেট

পর্যাপ্ত শীর্ষস্থানীয় অনুসন্ধানের ফাংশন সন্ধান করার জন্য আমার নিজের অনুসন্ধান অনুসরণ করে আমি এটি লিখেছি:

find_peaks <- function (x, m = 3){
    shape <- diff(sign(diff(x, na.pad = FALSE)))
    pks <- sapply(which(shape < 0), FUN = function(i){
       z <- i - m + 1
       z <- ifelse(z > 0, z, 1)
       w <- i + m + 1
       w <- ifelse(w < length(x), w, length(x))
       if(all(x[c(z : i, (i + 2) : w)] <= x[i + 1])) return(i + 1) else return(numeric(0))
    })
     pks <- unlist(pks)
     pks
}

একটি 'শিখর' স্থানীয় ম্যাক্সিমা হিসাবে সংজ্ঞায়িত করা mহয় যার উভয় পাশই এর চেয়ে ছোট হয় points অতএব, প্যারামিটারটি যত বড় হবে mতত তাত্ক্ষণিক পিক্স ফান্ডিং পদ্ধতি। তাই:

find_peaks(cc, m = 1)
[1]  2 21 40 58 77 95

ফাংশনটি কোনও অনুক্রমিক ভেক্টরের xমাধ্যমে স্থানীয় মিনিমা সন্ধান করতেও ব্যবহৃত হতে পারেfind_peaks(-x)

দ্রষ্টব্য: কারও যদি এটির প্রয়োজন হয় তবে আমি এখন গিটহাবটিতে ফাংশনটি রেখেছি: https://github.com/stas-g/findPeaks


6

Eek: গৌণ আপডেট। স্টাস_জির ফাংশনের সমতুলতাতে পৌঁছানোর জন্য আমাকে দুটি লাইন কোড, সীমানা (একটি -1 এবং +1 যুক্ত) পরিবর্তন করতে হয়েছিল (এটি সত্যিকারের ডেটা-সেটগুলিতে বেশ কয়েকটি 'অতিরিক্ত পিক' খুঁজে পেয়েছিল)। যে কারও জন্য ক্ষমা প্রার্থনা আমার মূল পোস্টটি দ্বারা খুব সামান্য পথভ্রষ্ট করে।

আমি বেশ কিছুদিন ধরে স্টাস_জির অনুসন্ধান পিকস অ্যালগরিদম ব্যবহার করছি। এর সরলতার কারণে এটি আমার পরবর্তী প্রকল্পগুলির জন্য আমার পক্ষে উপকারী ছিল। তবে, এটি গণনার জন্য কয়েক মিলিয়নবার ব্যবহার করার দরকার ছিল তাই আমি এটি আরসিপিতে পুনরায় লিখেছিলাম (আরসিপি প্যাকেজ দেখুন)। এটি সাধারণ পরীক্ষায় আর সংস্করণ তখন প্রায় 6x দ্রুত faster যদি কেউ আগ্রহী হন তবে আমি নীচের কোডটি যুক্ত করেছি। আশা করি আমি কাউকে সাহায্য করব, চিয়ার্স!

কিছু ছোটখাটো সাবধানতা। এই ফাংশনটি আর কোডের বিপরীত ক্রমে শীর্ষ সূচকগুলি প্রদান করে। এর জন্য একটি ইনহাউস সি ++ সাইন ফাংশন প্রয়োজন, যা আমি অন্তর্ভুক্ত করেছি। এটি সম্পূর্ণরূপে অনুকূলিত করা হয়নি তবে পরবর্তী কোনও পারফরম্যান্স লাভ আশা করা যায় না।

//This function returns the sign of a given real valued double.
// [[Rcpp::export]]
double signDblCPP (double x){
  double ret = 0;
  if(x > 0){ret = 1;}
  if(x < 0){ret = -1;}
  return(ret);
}

//Tested to be 6x faster(37 us vs 207 us). This operation is done from 200x per layer
//Original R function by Stas_G
// [[Rcpp::export]]
NumericVector findPeaksCPP( NumericVector vY, int m = 3) {
  int sze = vY.size();
  int i = 0;//generic iterator
  int q = 0;//second generic iterator

  int lb = 0;//left bound
  int rb = 0;//right bound

  bool isGreatest = true;//flag to state whether current index is greatest known value

  NumericVector ret(1);
  int pksFound = 0;

  for(i = 0; i < (sze-2); ++i){
    //Find all regions with negative laplacian between neighbors
    //following expression is identical to diff(sign(diff(xV, na.pad = FALSE)))
    if(signDblCPP( vY(i + 2)  - vY( i + 1 ) ) - signDblCPP( vY( i + 1 )  - vY( i ) ) < 0){
      //Now assess all regions with negative laplacian between neighbors...
      lb = i - m - 1;// define left bound of vector
      if(lb < 0){lb = 0;}//ensure our neighbor comparison is bounded by vector length
      rb = i + m + 1;// define right bound of vector
      if(rb >= (sze-2)){rb = (sze-3);}//ensure our neighbor comparison is bounded by vector length
      //Scan through loop and ensure that the neighbors are smaller in magnitude
      for(q = lb; q < rb; ++q){
        if(vY(q) > vY(i+1)){ isGreatest = false; }
      }

      //We have found a peak by our criterion
      if(isGreatest){
        if(pksFound > 0){//Check vector size.
         ret.insert( 0, double(i + 2) );
       }else{
         ret(0) = double(i + 2);
        }
        pksFound = pksFound + 1;
      }else{ // we did not find a peak, reset location is peak max flag.
        isGreatest = true;
      }//End if found peak
    }//End if laplace condition
  }//End loop
  return(ret);
}//End Fn

লুপের জন্য এটি ত্রুটিযুক্ত বলে মনে হচ্ছে, @ কেসাইক: for(q = lb; q < rb; ++q){ if(vY(q) > vY(i+1)){ isGreatest = false; } }লুপের মাধ্যমে "রান" জয়ের মাধ্যমে শেষ রান হিসাবে : এর সমতুল্য কাজ করে isGreatest = vY(rb-1) <= vY(rb)। এই লাইনের ঠিক উপরে মন্তব্যটি কী দাবি করেছে তা অর্জন করতে লুপের জন্য এই পরিবর্তনটি করা দরকার:for(q = lb; isGreatest && (q < rb); ++q){ isGreatest = (vY(q) <= vY(i+1)) }
বার্নহার্ড ওয়াগনার

হুম। আমি এই কোডটি লেখার পরে এটি আসল দীর্ঘ সময় হয়েছে। আইআইআরসি এটি সরাসরি স্টাস_জি এর ফাংশন দিয়ে পরীক্ষা করা হয়েছিল এবং ঠিক একই ফলাফল বজায় রেখেছিল। যদিও আপনি যা বলছেন তা আমি দেখতে পাচ্ছি, তবে আউটপুট কী করবে তা আমি নিশ্চিত নই। আমি প্রস্তাবিত / অভিযোজিত বনাম আপনার সমাধানটি অনুসন্ধান করার জন্য এটি আপনার পক্ষে উপযুক্ত একটি পোস্টের উপযুক্ত হবে।
কেসাইক

আমার আরও যোগ করা উচিত যে আমি ব্যক্তিগতভাবে এই স্ক্রিপ্টটি সম্ভবত ১০০x এর আদেশে পরীক্ষা করেছি (এটি আমার প্রকল্পের এক হিসাবে ধরে নেওয়া) এবং এটি এক মিলিয়নেরও বেশি বার ব্যবহৃত হয়েছিল এবং পরোক্ষ ফলাফলের প্রস্তাব দিয়েছিল যা একটি সাহিত্যের ফলাফলের সাথে সম্পূর্ণ চুক্তিতে ছিল একটি নির্দিষ্ট পরীক্ষার কেস সুতরাং, যদি এটি 'ত্রুটিযুক্ত' হয় তবে তা 'ত্রুটিযুক্ত' নয়;)
কেসাইক

1

প্রথমত: অ্যালগরিদম মিথ্যাভাবে একটি সমতল মালভূমির ডানদিকে একটি ড্রপও ডাকায় যেহেতু sign(diff(x, na.pad = FALSE)) 0 হবে -1 হবে যাতে এর ভিন্নতাও -1 হবে। Fixণাত্মক প্রবেশের আগের সাইন-ডিফটি শূন্য নয় তবে ইতিবাচক: তা নিশ্চিত করার জন্য একটি সহজ সমাধান fix

    n <- length(x)
    dx.1 <- sign(diff(x, na.pad = FALSE))
    pks <- which(diff(dx.1, na.pad = FALSE) < 0 & dx.1[-(n-1)] > 0) + 1

দ্বিতীয়: অ্যালগরিদম খুব স্থানীয় ফলাফল দেয় , উদাহরণস্বরূপ একটি 'আপ' এর পরে ক্রম অনুসারে টানা তিনটি পদে যে কোনও রান আসে 'ডাউন'। যদি কেউ কোনও পরিবর্তিত অবিচ্ছিন্ন ক্রিয়াকলাপের স্থানীয় ম্যাক্সিমায় আগ্রহী হয়, তবে - সেখানে আরও ভাল কিছু আছে সম্ভবত, তবে এটি আমার সস্তা এবং তাত্ক্ষণিক সমাধান is


  1. ডেটা এত সামান্য মসৃণ করতে টানা 3 পয়েন্টের গড় রানিং ব্যবহার করে প্রথমে শৃঙ্গগুলি শনাক্ত করুন । ফ্ল্যাট তারপরে ড্রপ-অফের বিরুদ্ধেও উল্লিখিত নিয়ন্ত্রণটি নিয়োগ করুন।
  2. এই প্রার্থীদের তুলনা করে ফিল্টার করুন একটি স্বল্প স্মুটেড সংস্করণের জন্য, প্রতিটি শিখরে কেন্দ্রের বাইরে একটি স্থানীয় উইন্ডোর স্থানীয় গড়ের সাথে একটি উইন্ডোর অভ্যন্তরের গড়।

    "myfindPeaks" <- 
    function (x, thresh=0.05, span=0.25, lspan=0.05, noisey=TRUE)
    {
      n <- length(x)
      y <- x
      mu.y.loc <- y
      if(noisey)
      {
        mu.y.loc <- (x[1:(n-2)] + x[2:(n-1)] + x[3:n])/3
        mu.y.loc <- c(mu.y.loc[1], mu.y.loc, mu.y.loc[n-2])
      }
      y.loess <- loess(x~I(1:n), span=span)
      y <- y.loess[[2]]
      sig.y <- var(y.loess$resid, na.rm=TRUE)^0.5
      DX.1 <- sign(diff(mu.y.loc, na.pad = FALSE))
      pks <- which(diff(DX.1, na.pad = FALSE) < 0 & DX.1[-(n-1)] > 0) + 1
      out <- pks
      if(noisey)
      {
        n.w <- floor(lspan*n/2)
        out <- NULL
        for(pk in pks)
        {
          inner <- (pk-n.w):(pk+n.w)
          outer <- c((pk-2*n.w):(pk-n.w),(pk+2*n.w):(pk+n.w))
          mu.y.outer <- mean(y[outer])
          if(!is.na(mu.y.outer)) 
            if (mean(y[inner])-mu.y.outer > thresh*sig.y) out <- c(out, pk)
        }
      }
      out
    }

0

এটি সত্য যে ফাংশনটি মালভূমিটির সমাপ্তিও চিহ্নিত করে, তবে আমি মনে করি এর থেকে আরও একটি সহজ সমাধান রয়েছে: যেহেতু বাস্তবের শীর্ষের প্রথম পার্থক্যের ফলে '1' তারপরে '-1' আসবে, দ্বিতীয় পার্থক্যটি '-2' হবে, এবং আমরা সরাসরি পরীক্ষা করতে পারি

    pks <- which(diff(sign(diff(x, na.pad = FALSE)), na.pad = FALSE) < 1) + 1

এটি প্রশ্নের উত্তর বলে মনে হচ্ছে না।
মাইকেল আর চেরনিক

0

নম্পি ব্যবহার করে

ser = np.random.randint(-40, 40, 100) # 100 points
peak = np.where(np.diff(ser) < 0)[0]

অথবা

double_difference = np.diff(np.sign(np.diff(ser)))
peak = np.where(double_difference == -2)[0]

পান্ডা ব্যবহার করে

ser = pd.Series(np.random.randint(2, 5, 100))
peak_df = ser[(ser.shift(1) < ser) & (ser.shift(-1) < ser)]
peak = peak_df.index
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.