सी में रोलिंग मंझला एल्गोरिदम


114

मैं वर्तमान में C. में रोलिंग माध्य फ़िल्टर (एक रोलिंग माध्य फ़िल्टर के अनुरूप) को लागू करने के लिए एक एल्गोरिथ्म पर काम कर रहा हूं। साहित्य की मेरी खोज से, इसे करने के दो उचित तरीके दिखाई देते हैं। पहले मानों की प्रारंभिक विंडो को सॉर्ट करना है, फिर नए मान सम्मिलित करने और प्रत्येक पुनरावृत्ति पर मौजूदा एक को हटाने के लिए एक द्विआधारी खोज करें।

दूसरा (हार्डल और स्टीगर, 1995, JRSS-C, एलगोरिदम 296) एक डबल-एंड ढेर संरचना का निर्माण करता है, जिसमें एक छोर पर एक अधिकतम, दूसरे पर एक minheap और मध्य में मध्यिका होती है। यह O (n log n) के बजाय एक रैखिक-समय के एल्गोरिथ्म का उत्पादन करता है।

यहां मेरी समस्या है: पूर्व को लागू करना संभव है, लेकिन मुझे इसे लाखों समय की श्रृंखला पर चलाने की आवश्यकता है, इसलिए दक्षता बहुत मायने रखती है। उत्तरार्द्ध को लागू करना बहुत मुश्किल साबित हो रहा है। मुझे R के आँकड़े पैकेज के लिए कोड की Trunmed.c फ़ाइल में कोड मिला, लेकिन यह अशोभनीय है।

क्या किसी को लीनियर टाइम रोलिंग माध्य एल्गोरिथम के लिए एक अच्छी तरह से लिखा सी कार्यान्वयन का पता है?

संपादित करें: Trunmed.c कोड से लिंक http://google.com/codesearch/p?hl=en&sa=N&cd=1&ct=rc#mYw3h_Lb_e0/R-2.2.0/src/library/stats/src/Trunmed.c


बस एक चलता हुआ मतलब लागू किया ... चल मंझला कुछ और मुश्किल है। मूविंग मूविंग मंझला प्रयास करें।
मैट

Google और Google कोड खोज की कोशिश की। इसने Trunmed.c कोड और दूसरी भाषा में Trunmed कोड के SGI पोर्ट (जो मैं बता सकता हूं) के लिए लागू किया। इसके अलावा, मैंने जो JRSS एल्गोरिथ्म का हवाला दिया है, वह जाहिरा तौर पर पत्रिका की श्रृंखला में केवल एक है जिसके लिए मूल कोड संग्रहीत नहीं किया गया था।
AWB

आपके पास प्रत्येक समय श्रृंखला में कितने नंबर हैं? यहां तक ​​कि उनमें से एक लाख के साथ, यदि आपके पास केवल कुछ हजार नंबर हैं, तो इसे चलाने में एक या दो मिनट से अधिक समय नहीं लग सकता है (यदि आपका कोड कुशलता से लिखा गया है)।
दना द साने

16
कैसे दो ढेर समाधान रैखिक है? यह O (n log k) है जहां k खिड़की का आकार है क्योंकि ढेर का हटना O (लॉग k) है।
यारचू

3
कुछ कार्यान्वयन और तुलना: github.com/suomela/median-filter
Jukka Suomela

जवाबों:


28

मैंने आर की src/library/stats/src/Trunmed.cकुछ बार देखा है क्योंकि मैं एक स्टैंडअलोन सी ++ क्लास / सी सबरूटीन में भी कुछ ऐसा ही चाहता था। ध्यान दें कि यह वास्तव में एक में दो कार्यान्वयन हैं, देखें src/library/stats/man/runmed.Rd(सहायता फ़ाइल का स्रोत) जो कहता है

\details{
  Apart from the end values, the result \code{y = runmed(x, k)} simply has
  \code{y[j] = median(x[(j-k2):(j+k2)])} (k = 2*k2+1), computed very
  efficiently.

  The two algorithms are internally entirely different:
  \describe{
    \item{"Turlach"}{is the Härdle-Steiger
      algorithm (see Ref.) as implemented by Berwin Turlach.
      A tree algorithm is used, ensuring performance \eqn{O(n \log
        k)}{O(n * log(k))} where \code{n <- length(x)} which is
      asymptotically optimal.}
    \item{"Stuetzle"}{is the (older) Stuetzle-Friedman implementation
      which makes use of median \emph{updating} when one observation
      enters and one leaves the smoothing window.  While this performs as
      \eqn{O(n \times k)}{O(n * k)} which is slower asymptotically, it is
      considerably faster for small \eqn{k} or \eqn{n}.}
  }
}

इस स्टैंड को एक अधिक स्टैंडअलोन फैशन में देखने के लिए अच्छा होगा। क्या आप स्वयं सेवा कर रहे हैं? मैं कुछ आर बिट्स के साथ मदद कर सकता हूं।

संपादित 1 : ऊपर Trunmed.c के पुराने संस्करण के लिंक के अलावा, यहाँ वर्तमान SVN प्रतियां हैं

  • Srunmed.c (स्टुट्ज़ल संस्करण के लिए)
  • Trunmed.c (Turlach संस्करण के लिए)
  • runmed.R आर समारोह के लिए इन बुला

संपादन 2 : रयान टिबशिरानी के पास कुछ सी और फोरट्रान कोड हैं जो तेजी से मंझने वाले बाइनिंग पर हैं जो एक खिड़की के दृष्टिकोण के लिए एक उपयुक्त प्रारंभिक बिंदु हो सकता है।


धन्यवाद डिर्क। एक बार जब मुझे एक स्वच्छ समाधान मिल जाता है, तो मैं इसे जीपीएल के तहत जारी करने की योजना बना रहा हूं। मैं एक आर और पायथन इंटरफेस स्थापित करने में रुचि रखता हूं।
AWB

9
@AWB इस विचार के साथ क्या हो रहा है? क्या आपने अपने समाधान को पैकेज में शामिल किया?
जू वांग

20

मैं ऑर्डर-स्टैटिस्टिक्स के साथ सी ++ डेटा संरचना का एक आधुनिक कार्यान्वयन नहीं पा सका, इसलिए मेक द्वारा सुझाए गए शीर्ष कोडर लिंक में दोनों विचारों को लागू करना समाप्त हो गया ( मिलान संपादकीय : फ्लोटिंगमेडियन तक स्क्रॉल करें)।

दो मल्टीसेट

पहला विचार O (ln N) प्रति इंसर्ट / डिलीट के साथ डेटा को दो डेटा स्ट्रक्चर्स (ढेर, मल्टीसेट्स आदि) में विभाजित करता है, बड़ी मात्रा के बिना क्वांटाइल को गतिशील रूप से बदलने की अनुमति नहीं देता है। यानी हमारे पास एक रोलिंग मंझला या एक रोलिंग 75% हो सकता है लेकिन एक ही समय में दोनों नहीं।

खंड वृक्ष

दूसरा विचार एक सेगमेंट ट्री का उपयोग करता है जो डालने / हटाने / प्रश्नों के लिए O (ln N) है लेकिन अधिक लचीला है। सभी "एन" के सर्वश्रेष्ठ आपके डेटा रेंज का आकार है। इसलिए यदि आपके रोलिंग माध्यिका में एक लाख आइटम की विंडो है, लेकिन आपका डेटा 1..65536 से भिन्न होता है, तो 1 मिलियन की रोलिंग विंडो के प्रति आंदोलन के लिए केवल 16 ऑपरेशन आवश्यक हैं !!

सी ++ कोड जैसा कि डेनिस ने ऊपर पोस्ट किया है ("यहां निर्धारित मात्रा के लिए एक सरल एल्गोरिथ्म है")

जीएनयू ऑर्डर स्टेटिस्टिक पेड़

देने से ठीक पहले, मैंने पाया कि stdlibc ++ में ऑर्डर स्टेटिस्टिक ट्री हैं !!!

ये दो महत्वपूर्ण ऑपरेशन हैं:

iter = tree.find_by_order(value)
order = tree.order_of_key(value)

देखें libstdc ++ मैनुअल policy_based_data_structures_test (के लिए खोज "विभाजन और शामिल होने के")।

मैंने c ++ 0x / c ++ 11 शैली वाले आंशिक टाइपराइफ़ का समर्थन करने वाले कंपाइलरों के लिए एक सुविधा हेडर में उपयोग के लिए पेड़ को लपेटा है:

#if !defined(GNU_ORDER_STATISTIC_SET_H)
#define GNU_ORDER_STATISTIC_SET_H
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

// A red-black tree table storing ints and their order
// statistics. Note that since the tree uses
// tree_order_statistics_node_update as its update policy, then it
// includes its methods by_order and order_of_key.
template <typename T>
using t_order_statistic_set = __gnu_pbds::tree<
                                  T,
                                  __gnu_pbds::null_type,
                                  std::less<T>,
                                  __gnu_pbds::rb_tree_tag,
                                  // This policy updates nodes'  metadata for order statistics.
                                  __gnu_pbds::tree_order_statistics_node_update>;

#endif //GNU_ORDER_STATISTIC_SET_H

वास्तव में, libstdc ++ एक्सटेंशन कंटेनरों को कई मूल्यों के लिए अनुमति नहीं है ! डिजाइन द्वारा! जैसा कि ऊपर मेरे नाम (t_order_statistic_set) द्वारा सुझाया गया है, कई मान विलय किए गए हैं। इसलिए, उन्हें हमारे उद्देश्यों के लिए थोड़ा और काम करने की आवश्यकता है :-(
लियो गुडस्टाट

हमें 1 की जरूरत है (मानों के बजाय (सेट के बजाय) 2 का एक नक्शा बनाने के लिए) शाखा आकारों को कुंजी की गिनती को दर्शाया जाना चाहिए (libstdc ++ - v3 / शामिल / ext / pb_ds / detail / tree_policy / order_statistics_imp.hpp) से विरासत में मिली पेड़, और 3) अधिभार डालने () के लिए गिनती / कॉल update_to_top () बढ़ाने के लिए अगर मूल्य पहले से ही मौजूद है 4) अधिभार मिटा () के लिए गिनती / कॉल update_to_top () कम करने के लिए यदि मूल्य अद्वितीय नहीं है (देखें libstdc ++ - v3 / शामिल / ext / pb_ds / detail / rb_tree_map_ / rb_tree_.hpp) कोई स्वयंसेवक ??
लियो गुडस्टैंड

15

मैंने यहाँ C कार्यान्वयन किया है । कुछ और विवरण इस प्रश्न में हैं: रोलिंग मेडियन इन सी - टर्लाक कार्यान्वयन

नमूना उपयोग:

int main(int argc, char* argv[])
{
   int i,v;
   Mediator* m = MediatorNew(15);

   for (i=0;i<30;i++)
   {
      v = rand()&127;
      printf("Inserting %3d \n",v);
      MediatorInsert(m,v);
      v=MediatorMedian(m);
      printf("Median = %3d.\n\n",v);
      ShowTree(m);
   }
}

6
मिन-माध्य-अधिकतम ढेर के आधार पर महान, तेज और स्पष्ट कार्यान्वयन। बहुत अच्छा काम।
जोहान्स रूडोल्फ

मैं इस समाधान का जावा संस्करण कैसे खोज सकता हूं?
हेंगामेह

10

मैं इस वृद्धिशील मध्यस्थ आकलनकर्ता का उपयोग करता हूं:

median += eta * sgn(sample - median)

जिसका समान रूप से अधिक सामान्य माध्य अनुमानक है:

mean += eta * (sample - mean)

यहाँ एटा एक छोटा सा सीखने की दर पैरामीटर (जैसे 0.001) है, और sgn()साइनम फ़ंक्शन है जो एक रिटर्न देता है {-1, 0, 1}। ( etaयदि डेटा गैर-स्थिर है और आप समय के साथ परिवर्तनों को ट्रैक करना चाहते हैं, तो इस तरह एक स्थिरांक का उपयोग करें ; अन्यथा, स्थिर स्रोतों के eta = 1 / nलिए अभिसरण की तरह कुछ का उपयोग करें , जहां nअब तक देखे गए नमूनों की संख्या है।)

इसके अलावा, मैंने मध्यस्थ अनुमानक को संशोधित करके इसे मनमाना मात्रा के लिए काम किया। सामान्य तौर पर, एक मात्रात्मक फ़ंक्शन आपको वह मान बताता है जो डेटा को दो भागों में विभाजित करता है: pऔर 1 - p। निम्न मान इस मान को बढ़ाता है:

quantile += eta * (sgn(sample - quantile) + 2.0 * p - 1.0)

मान pभीतर होना चाहिए [0, 1]। यह अनिवार्य रूप से sgn()फ़ंक्शन के सममितीय आउटपुट {-1, 0, 1}को एक तरफ झुकाने के लिए स्थानांतरित करता है, डेटा के नमूनों को दो असमान आकार के डिब्बे (अंशों में pऔर 1 - pडेटा के क्रमशः मात्रात्मक अनुमान से कम / अधिक होता है) में विभाजित करता है । ध्यान दें p = 0.5, इसके लिए मंझला अनुमानक को कम करता है।


2
कूल, यहां एक संशोधन है जो चल रहे मतलब के आधार पर 'एटा' को समायोजित करता है ... (इसका उपयोग मंझले के किसी मोटे अनुमान के रूप में किया जाता है, इसलिए यह बड़े मूल्यों पर उसी दर पर धर्मान्तरित होता है जो छोटे मूल्यों पर परिवर्तित होता है)। यानी एटा अपने आप ट्यून हो जाता है। stackoverflow.com/questions/11482529/…
जेफ़ मैकक्लिंटॉक

3
इसी तरह की तकनीक के लिए, इस पेपर को मितव्ययी स्ट्रीमिंग पर देखें: arxiv.org/pdf/1407.1121v1.pdf यह किसी भी चतुर्थांश का अनुमान लगा सकता है और अर्थ में परिवर्तन के लिए adapts कर सकता है। इसके लिए आवश्यक है कि आप केवल दो मूल्यों को संग्रहीत करें: अंतिम अनुमान और अंतिम समायोजन की दिशा (+1 या -1)। एल्गोरिथ्म लागू करने के लिए सरल है। मुझे लगता है कि त्रुटि 97% समय के बारे में 5% के भीतर है।
16:18 बजे पॉल चेरोच

9

यहां मात्रात्मक डेटा के लिए एक सरल एल्गोरिथ्म है (महीने बाद):

""" median1.py: moving median 1d for quantized, e.g. 8-bit data

Method: cache the median, so that wider windows are faster.
    The code is simple -- no heaps, no trees.

Keywords: median filter, moving median, running median, numpy, scipy

See Perreault + Hebert, Median Filtering in Constant Time, 2007,
    http://nomis80.org/ctmf.html: nice 6-page paper and C code,
    mainly for 2d images

Example:
    y = medians( x, window=window, nlevel=nlevel )
    uses:
    med = Median1( nlevel, window, counts=np.bincount( x[0:window] ))
    med.addsub( +, - )  -- see the picture in Perreault
    m = med.median()  -- using cached m, summ

How it works:
    picture nlevel=8, window=3 -- 3 1s in an array of 8 counters:
        counts: . 1 . . 1 . 1 .
        sums:   0 1 1 1 2 2 3 3
                        ^ sums[3] < 2 <= sums[4] <=> median 4
        addsub( 0, 1 )  m, summ stay the same
        addsub( 5, 1 )  slide right
        addsub( 5, 6 )  slide left

Updating `counts` in an `addsub` is trivial, updating `sums` is not.
But we can cache the previous median `m` and the sum to m `summ`.
The less often the median changes, the faster;
so fewer levels or *wider* windows are faster.
(Like any cache, run time varies a lot, depending on the input.)

See also:
    scipy.signal.medfilt -- runtime roughly ~ window size
    http://stackoverflow.com/questions/1309263/rolling-median-algorithm-in-c

"""

from __future__ import division
import numpy as np  # bincount, pad0

__date__ = "2009-10-27 oct"
__author_email__ = "denis-bz-py at t-online dot de"


#...............................................................................
class Median1:
    """ moving median 1d for quantized, e.g. 8-bit data """

    def __init__( s, nlevel, window, counts ):
        s.nlevel = nlevel  # >= len(counts)
        s.window = window  # == sum(counts)
        s.half = (window // 2) + 1  # odd or even
        s.setcounts( counts )

    def median( s ):
        """ step up or down until sum cnt to m-1 < half <= sum to m """
        if s.summ - s.cnt[s.m] < s.half <= s.summ:
            return s.m
        j, sumj = s.m, s.summ
        if sumj <= s.half:
            while j < s.nlevel - 1:
                j += 1
                sumj += s.cnt[j]
                # print "j sumj:", j, sumj
                if sumj - s.cnt[j] < s.half <= sumj:  break
        else:
            while j > 0:
                sumj -= s.cnt[j]
                j -= 1
                # print "j sumj:", j, sumj
                if sumj - s.cnt[j] < s.half <= sumj:  break
        s.m, s.summ = j, sumj
        return s.m

    def addsub( s, add, sub ):
        s.cnt[add] += 1
        s.cnt[sub] -= 1
        assert s.cnt[sub] >= 0, (add, sub)
        if add <= s.m:
            s.summ += 1
        if sub <= s.m:
            s.summ -= 1

    def setcounts( s, counts ):
        assert len(counts) <= s.nlevel, (len(counts), s.nlevel)
        if len(counts) < s.nlevel:
            counts = pad0__( counts, s.nlevel )  # numpy array / list
        sumcounts = sum(counts)
        assert sumcounts == s.window, (sumcounts, s.window)
        s.cnt = counts
        s.slowmedian()

    def slowmedian( s ):
        j, sumj = -1, 0
        while sumj < s.half:
            j += 1
            sumj += s.cnt[j]
        s.m, s.summ = j, sumj

    def __str__( s ):
        return ("median %d: " % s.m) + \
            "".join([ (" ." if c == 0 else "%2d" % c) for c in s.cnt ])

#...............................................................................
def medianfilter( x, window, nlevel=256 ):
    """ moving medians, y[j] = median( x[j:j+window] )
        -> a shorter list, len(y) = len(x) - window + 1
    """
    assert len(x) >= window, (len(x), window)
    # np.clip( x, 0, nlevel-1, out=x )
        # cf http://scipy.org/Cookbook/Rebinning
    cnt = np.bincount( x[0:window] )
    med = Median1( nlevel=nlevel, window=window, counts=cnt )
    y = (len(x) - window + 1) * [0]
    y[0] = med.median()
    for j in xrange( len(x) - window ):
        med.addsub( x[j+window], x[j] )
        y[j+1] = med.median()
    return y  # list
    # return np.array( y )

def pad0__( x, tolen ):
    """ pad x with 0 s, numpy array or list """
    n = tolen - len(x)
    if n > 0:
        try:
            x = np.r_[ x, np.zeros( n, dtype=x[0].dtype )]
        except NameError:
            x += n * [0]
    return x

#...............................................................................
if __name__ == "__main__":
    Len = 10000
    window = 3
    nlevel = 256
    period = 100

    np.set_printoptions( 2, threshold=100, edgeitems=10 )
    # print medians( np.arange(3), 3 )

    sinwave = (np.sin( 2 * np.pi * np.arange(Len) / period )
        + 1) * (nlevel-1) / 2
    x = np.asarray( sinwave, int )
    print "x:", x
    for window in ( 3, 31, 63, 127, 255 ):
        if window > Len:  continue
        print "medianfilter: Len=%d window=%d nlevel=%d:" % (Len, window, nlevel)
            y = medianfilter( x, window=window, nlevel=nlevel )
        print np.array( y )

# end median1.py

4

संख्याओं के दो विभाजन को बनाए रखकर रोलिंग माध्य पाया जा सकता है।

विभाजन को बनाए रखने के लिए न्यूनतम ढेर और अधिकतम ढेर का उपयोग करें।

मैक्स हीप में माध्यिका के बराबर की संख्या छोटी होगी।

मिन हीप में माध्यिका के बराबर संख्याएँ होंगी।

बाधा संतुलन: यदि तत्वों की कुल संख्या सम है तो दोनों ही ढेर में समान तत्व होने चाहिए।

यदि तत्वों की कुल संख्या विषम है तो मैक्स हीप में मिन हीप की तुलना में एक अधिक तत्व होगा।

मेडियन एलिमेंट: यदि दोनों विभाजनों में समान संख्या में तत्व हैं तो प्रथम विभाजन से मध्य तत्व का आधा भाग और द्वितीय विभाजन से न्यूनतम तत्व होगा।

अन्यथा प्रथम विभाजन से मध्य तत्व अधिकतम होगा।

कलन विधि-
1- दो ढेर (1 न्यूनतम ढेर और 1 अधिकतम ढेर) लें
   मैक्स हीप में पहले आधे तत्व होंगे
   न्यूनतम हीप में तत्वों की दूसरी आधी संख्या होगी

2- मैक्स हीप के ऊपर से स्ट्रीम से नए नंबर की तुलना करें, 
   यदि यह छोटा है या बराबर है तो उस संख्या को अधिकतम ढेर में जोड़ें। 
   अन्यथा मिन हीप में नंबर जोड़ें।

3- अगर मिन हीप में मैक्स हीप से ज्यादा एलिमेंट्स हैं 
   फिर मिन हीप के शीर्ष तत्व को हटा दें और मैक्स हीप में जोड़ें।
   यदि मिन हीप की तुलना में अधिकतम हीप में एक से अधिक तत्व हैं 
   फिर मैक्स हीप के शीर्ष तत्व को हटा दें और मिन हीप में जोड़ें।

४- यदि दोनों ढेर में समान तत्वों की संख्या हो तो
   माध्य मैक्स हीप से अधिकतम तत्व का आधा और मिन हीप से न्यूनतम तत्व होगा।
   अन्यथा मेडियन पहले विभाजन से अधिकतम तत्व होगा।
public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        RunningMedianHeaps s = new RunningMedianHeaps();
        int n = in.nextInt();
        for(int a_i=0; a_i < n; a_i++){
            printMedian(s,in.nextInt());
        }
        in.close();       
    }

    public static void printMedian(RunningMedianHeaps s, int nextNum){
            s.addNumberInHeap(nextNum);
            System.out.printf("%.1f\n",s.getMedian());
    }
}

class RunningMedianHeaps{
    PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
    PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(Comparator.reverseOrder());

    public double getMedian() {

        int size = minHeap.size() + maxHeap.size();     
        if(size % 2 == 0)
            return (maxHeap.peek()+minHeap.peek())/2.0;
        return maxHeap.peek()*1.0;
    }

    private void balanceHeaps() {
        if(maxHeap.size() < minHeap.size())
        {
            maxHeap.add(minHeap.poll());
        }   
        else if(maxHeap.size() > 1+minHeap.size())
        {
            minHeap.add(maxHeap.poll());
        }
    }

    public void addNumberInHeap(int num) {
        if(maxHeap.size()==0 || num <= maxHeap.peek())
        {
            maxHeap.add(num);
        }
        else
        {
            minHeap.add(num);
        }
        balanceHeaps();
    }
}

यह मेरे लिए स्पष्ट नहीं है कि C प्रश्न के लिए तीसरा जावा उत्तर कितना लाभ प्रदान करता है। आपको एक नया प्रश्न पूछना चाहिए, और फिर उस प्रश्न में अपने जावा उत्तर की आपूर्ति करनी चाहिए।
jww

तर्क यह पढ़ने के बाद मर गया 'फिर मिन हीप के शीर्ष तत्व को हटा दें और मिन हीप में जोड़ें।' कम से कम पोस्टिंग से पहले अहंकार को पढ़ने के लिए शिष्टाचार है
Cyclotron3x3

4
यह एल्गोरिथ्म एक रोलिंग मंझले के लिए नहीं है, बल्कि तत्वों की बढ़ती संख्या के मध्य के लिए है। रोलिंग मंझला के लिए, किसी को ढेर से एक तत्व भी निकालना होगा, जिसे पहले खोजने की आवश्यकता है।
वाल्टर

2

शायद यह इंगित करने के लायक है कि एक विशेष मामला है जिसका एक सरल सटीक समाधान है: जब धारा के सभी मान एक (अपेक्षाकृत) छोटे परिभाषित सीमा के भीतर पूर्णांक होते हैं। उदाहरण के लिए, मान लें कि सभी को 0 और 1023 के बीच झूठ बोलना चाहिए। इस मामले में केवल 1024 तत्वों और एक गिनती की एक सरणी को परिभाषित करें, और इन सभी मूल्यों को साफ करें। स्ट्रीम में प्रत्येक मान के लिए संबंधित बिन और गिनती बढ़ाएँ। धारा समाप्त होने के बाद बिन को गिनते हैं जिसमें गिनती / 2 उच्चतम मूल्य होता है - 0. से शुरू होने वाले क्रमिक डिब्बे को जोड़कर आसानी से पूरा किया जाता है उसी विधि का उपयोग करके एक मनमाना रैंक क्रम का मूल्य मिल सकता है। (बिन संतृप्ति का पता लगाने और एक रन के दौरान एक बड़े प्रकार के भंडारण डिब्बे के आकार को "अपग्रेड" करने की आवश्यकता होगी तो एक मामूली जटिलता है।)

यह विशेष मामला कृत्रिम लग सकता है, लेकिन व्यवहार में यह बहुत आम है। यह वास्तविक संख्याओं के लिए एक सन्निकटन के रूप में भी लागू किया जा सकता है यदि वे एक सीमा के भीतर झूठ बोलते हैं और परिशुद्धता का "अच्छा पर्याप्त" स्तर ज्ञात होता है। यह "वास्तविक दुनिया" वस्तुओं के एक समूह पर माप के किसी भी सेट के लिए बहुत अधिक होगा। उदाहरण के लिए, लोगों के समूह की ऊँचाई या तौल। बहुत बड़ा सेट नहीं है? यह ग्रह पर सभी (व्यक्तिगत) बैक्टीरिया की लंबाई या वजन के लिए भी काम करेगा - यह मानकर कि कोई व्यक्ति डेटा की आपूर्ति कर सकता है!

ऐसा लगता है कि मैंने मूल को गलत फैला दिया है - जो ऐसा लगता है कि यह बहुत लंबी धारा के मध्य के बजाय एक स्लाइडिंग विंडो मंझला चाहता है। यह दृष्टिकोण अभी भी उसी के लिए काम करता है। प्रारंभिक विंडो के लिए पहले N स्ट्रीम मान लोड करें, फिर N + 1th स्ट्रीम मान के लिए उसी बिन को बढ़ाएं, जबकि 0 वें स्ट्रीम मान के अनुरूप बिन को घटाएं। इस मामले में अंतिम एन मूल्यों को बनाए रखने की अनुमति देना आवश्यक है, जो कुशलता से आकार एन की एक सरणी को संबोधित करके किया जा सकता है। चूंकि मध्यिका की स्थिति केवल -2 से बदल सकती है, -1,0,1 , स्लाइडिंग विंडो के प्रत्येक चरण पर, प्रत्येक चरण पर माध्यिका तक सभी डिब्बे को योग करना आवश्यक नहीं है, बस "माध्यक सूचक" को समायोजित करें, जिसके आधार पर पक्ष संशोधित किए गए थे। उदाहरण के लिए, यदि नया मूल्य और हटाया जा रहा है दोनों वर्तमान मंझधार से नीचे आते हैं तो यह नहीं बदलता है (ऑफसेट = 0)। जब स्मृति में आसानी से पकड़ बनाने के लिए N बहुत बड़ा हो जाता है तो विधि टूट जाती है।


1

आप समय में अंक की एक समारोह के रूप में संदर्भ मूल्यों करने की क्षमता है, तो आप प्रतिस्थापन के साथ मूल्यों नमूना सकता है, को लागू करने bootstrapping विश्वास के अंतराल के भीतर एक बूटस्ट्रैप माध्यिका मान उत्पन्न करने के लिए। यह आपको एक अनुमानित संरचना को एक डेटा संरचना में आने वाले मूल्यों को लगातार छाँटने की तुलना में अधिक दक्षता के साथ अनुमानित कर सकता है।


1

उन लोगों के लिए जिन्हें जावा में एक रनिंग माध्यिका की आवश्यकता है ... प्राथमिकता आपका मित्र है। O (लॉग एन) डालें, O (1) वर्तमान माध्यिका, और O (N) निकालें। यदि आप अपने डेटा के वितरण को जानते हैं तो आप इससे बहुत बेहतर कर सकते हैं।

public class RunningMedian {
  // Two priority queues, one of reversed order.
  PriorityQueue<Integer> lower = new PriorityQueue<Integer>(10,
          new Comparator<Integer>() {
              public int compare(Integer arg0, Integer arg1) {
                  return (arg0 < arg1) ? 1 : arg0 == arg1 ? 0 : -1;
              }
          }), higher = new PriorityQueue<Integer>();

  public void insert(Integer n) {
      if (lower.isEmpty() && higher.isEmpty())
          lower.add(n);
      else {
          if (n <= lower.peek())
              lower.add(n);
          else
              higher.add(n);
          rebalance();
      }
  }

  void rebalance() {
      if (lower.size() < higher.size() - 1)
          lower.add(higher.remove());
      else if (higher.size() < lower.size() - 1)
          higher.add(lower.remove());
  }

  public Integer getMedian() {
      if (lower.isEmpty() && higher.isEmpty())
          return null;
      else if (lower.size() == higher.size())
          return (lower.peek() + higher.peek()) / 2;
      else
          return (lower.size() < higher.size()) ? higher.peek() : lower
                  .peek();
  }

  public void remove(Integer n) {
      if (lower.remove(n) || higher.remove(n))
          rebalance();
  }
}

c ++ में मानक पुस्तकालय के विस्तार में ग्नू से सांख्यिकीय पेड़ हैं। मेरी पोस्ट नीचे देखें।
लियो गुडस्टैंड

मुझे लगता है कि आपका कोड यहां सही तरीके से नहीं डाला गया है। वहाँ कुछ अधूरे हिस्से हैं जैसे: }), higher = new PriorityQueue<Integer>();या new PriorityQueue<Integer>(10,। मैं कोड नहीं चला सकता।
हेंगमेह

@Hengameh जावा अर्धविराम के साथ बयान समाप्त करता है - पंक्ति विराम बिल्कुल भी मायने नहीं रखता है। आपने इसे गलत तरीके से कॉपी किया होगा।
मैथ्यू पढ़ें

आपको एक नया प्रश्न पूछना चाहिए, और फिर उस प्रश्न में अपने जावा उत्तर की आपूर्ति करनी चाहिए।
jww

0

यहाँ एक है जिसका उपयोग तब किया जा सकता है जब सटीक आउटपुट महत्वपूर्ण नहीं होता है (प्रदर्शन उद्देश्यों के लिए) आपको कुल एवमाउंट और लास्टेडियन की आवश्यकता होती है, साथ ही साथ न्यूवल्यू भी।

{
totalcount++;
newmedian=lastmedian+(newvalue>lastmedian?1:-1)*(lastmedian==0?newvalue: lastmedian/totalcount*2);
}

Page_display_time जैसी चीजों के लिए काफी सटीक परिणाम प्रस्तुत करता है।

नियम: इनपुट स्ट्रीम को पृष्ठ प्रदर्शन समय, गिनती में बड़ा (> 30 आदि) के क्रम में सुचारू होने की आवश्यकता है, और एक शून्य शून्य अभिभावक है।

उदाहरण: पृष्ठ लोड समय, 800 आइटम, 10ms ... 3000ms, औसत 90ms, वास्तविक मध्यमान: 11ms

30 इनपुट के बाद, औसतन त्रुटि आमतौर पर <= 20% (9ms..12ms) होती है, और कम और कम हो जाती है। 800 इनपुट के बाद, त्रुटि + -2% है।

इसी तरह के समाधान के साथ एक और विचारक यहां है: मेडियन फ़िल्टर सुपर कुशल कार्यान्वयन


-1

यहाँ जावा कार्यान्वयन है

package MedianOfIntegerStream;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;


public class MedianOfIntegerStream {

    public Set<Integer> rightMinSet;
    public Set<Integer> leftMaxSet;
    public int numOfElements;

    public MedianOfIntegerStream() {
        rightMinSet = new TreeSet<Integer>();
        leftMaxSet = new TreeSet<Integer>(new DescendingComparator());
        numOfElements = 0;
    }

    public void addNumberToStream(Integer num) {
        leftMaxSet.add(num);

        Iterator<Integer> iterMax = leftMaxSet.iterator();
        Iterator<Integer> iterMin = rightMinSet.iterator();
        int maxEl = iterMax.next();
        int minEl = 0;
        if (iterMin.hasNext()) {
            minEl = iterMin.next();
        }

        if (numOfElements % 2 == 0) {
            if (numOfElements == 0) {
                numOfElements++;
                return;
            } else if (maxEl > minEl) {
                iterMax.remove();

                if (minEl != 0) {
                    iterMin.remove();
                }
                leftMaxSet.add(minEl);
                rightMinSet.add(maxEl);
            }
        } else {

            if (maxEl != 0) {
                iterMax.remove();
            }

            rightMinSet.add(maxEl);
        }
        numOfElements++;
    }

    public Double getMedian() {
        if (numOfElements % 2 != 0)
            return new Double(leftMaxSet.iterator().next());
        else
            return (leftMaxSet.iterator().next() + rightMinSet.iterator().next()) / 2.0;
    }

    private class DescendingComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    }

    public static void main(String[] args) {
        MedianOfIntegerStream streamMedian = new MedianOfIntegerStream();

        streamMedian.addNumberToStream(1);
        System.out.println(streamMedian.getMedian()); // should be 1

        streamMedian.addNumberToStream(5);
        streamMedian.addNumberToStream(10);
        streamMedian.addNumberToStream(12);
        streamMedian.addNumberToStream(2);
        System.out.println(streamMedian.getMedian()); // should be 5

        streamMedian.addNumberToStream(3);
        streamMedian.addNumberToStream(8);
        streamMedian.addNumberToStream(9);
        System.out.println(streamMedian.getMedian()); // should be 6.5
    }
}

आपको एक नया प्रश्न पूछना चाहिए, और फिर उस प्रश्न में अपने जावा उत्तर की आपूर्ति करनी चाहिए।
jww

-4

यदि आपको बस एक स्मूथेड एवरेज की आवश्यकता है तो एक्स द्वारा लेटेस्ट वैल्यू को नवीनतम तरीके से गुणा करना है और एवरेज वैल्यू को (१-एक्स) से जोड़ना है। यह फिर नया औसत बन जाता है।

संपादित करें: ऐसा नहीं है जो उपयोगकर्ता ने सांख्यिकीय रूप से मान्य के रूप में मांगा है और बहुत सारे उपयोगों के लिए पर्याप्त नहीं है।
मैं इसे यहाँ (नीचे के बावजूद) खोज के लिए छोड़ दूँगा!


2
यह माध्य की गणना करता है। वह मंझला चाहता है। इसके अलावा, वह मानों की स्लाइडिंग विंडो के माध्यिका की गणना कर रहा है, पूरे सेट की नहीं।
ए। लेवी

1
यह एक्स के आधार पर एक क्षय स्थिरांक के साथ मूल्यों की एक खिड़की के एक औसत चलने की गणना करता है - यह बहुत उपयोगी है जहां प्रदर्शन मायने रखता है और आपको कलमन फ़िल्टर करने से परेशान नहीं किया जा सकता है। मैं इसे खोज में लगाता हूं तो इसे पा सकता हूं।
मार्टिन बेकेट

यह वही है जो मैंने तुरंत सोचा था, इस तरह के एक फिल्टर को एक ऑडियो ऐप के लिए एक बहुत ही बुनियादी और सस्ते लोपास-फ़िल्टर के रूप में लागू किया है।
जेम्स मॉरिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.