आप गोलाकार डेटा के सेट के औसत की गणना कैसे करते हैं?


147

मैं परिपत्र डेटा के एक सेट के औसत की गणना करना चाहता हूं। उदाहरण के लिए, मेरे पास कम्पास के पढ़ने से कई नमूने हो सकते हैं। कोर्स की समस्या है कि रैपराउंड से कैसे निपटा जाए। एक ही एल्गोरिदम एक घड़ी की कल के लिए उपयोगी हो सकता है।

वास्तविक प्रश्न अधिक जटिल है - आँकड़ों का क्या अर्थ है एक गोले पर या एक बीजीय स्थान पर जो "चारों ओर लपेटता है", जैसे कि योजक समूह mod n। उत्तर अद्वितीय नहीं हो सकता है, उदाहरण के लिए 359 डिग्री और 1 डिग्री का औसत 0 डिग्री या 180 हो सकता है, लेकिन सांख्यिकीय 0 बेहतर दिखता है।

यह मेरे लिए एक वास्तविक प्रोग्रामिंग समस्या है और मैं इसे सिर्फ एक मठ समस्या की तरह नहीं बनाने की कोशिश कर रहा हूं।


1
औसत कोण से, मेरा मानना ​​है कि वास्तव में आप चाहते हैं कि असर मतलब है। एक कोण दो लाइनों के बीच मौजूद है, एक असर एक लाइन की दिशा है। इस मामले में, स्टारब्ले का अधिकार है।
SmacL

@Nick Fortescue: क्या आप अपने प्रश्न को अधिक विशिष्ट होने के लिए अपडेट कर सकते हैं: क्या आपका मतलब कोण या एक असर है?
मिच गेहूं

1
मैं वास्तव में कुछ अधिक जटिल चाहता था (लेकिन बीयरिंग के अनुरूप है) और प्रश्न को आसान बनाने के लिए सरल बनाने की कोशिश कर रहा था, और हमेशा की तरह इसे और अधिक जटिल बना दिया। मुझे वह उत्तर मिला जो मुझे catless.ncl.ac.uk/Risks/7.44.html#subj4 पर चाहिए था । मैं पुनः qn संपादित करूँगा।
निक फोर्टेस्क्यू

जोखिम का जवाब मूल रूप से मैं जो प्रस्ताव कर रहा हूं, उसे छोड़कर, जब यह संकट में चल सकता है, तो यह
0.14 है

कोणों के अर्थ पर दिलचस्प लेख: twedoakakstudios.com/blog/?p=938
starblue

जवाबों:


99

कोणों से इकाई वैक्टरों की गणना करें और उनके औसत का कोण लें।


8
यदि वैक्टर एक-दूसरे को रद्द कर देते हैं तो यह काम नहीं करता है। औसत इस मामले में अभी भी सार्थक हो सकता है, इसकी सटीक परिभाषा पर निर्भर करता है।
डेविड हनक

21
@ डेविड, दो बियरिंग 180 डिग्री आउट की औसत दिशा अपरिभाषित है। यह स्टारब्ले के उत्तर को गलत नहीं बनाता है, यह सिर्फ एक असाधारण मामला है, जैसा कि कई भूभौतिकीय समस्याओं में होता है।
SmacL

5
@smacl: मैं सहमत हूं, अगर कोण दिशाओं का प्रतिनिधित्व करते हैं। लेकिन अगर आप जटिल संख्याओं के बारे में सोचते हैं, उदाहरण के लिए, और औसत को "c का तर्क क्या कहते हैं, जैसे कि c c == a b", जहां a और b का मापांक 1 है, तो 0 और 180 का औसत। है 90.
डेविड हैनाक

3
यह भी देखें math.stackexchange.com/questions/14530/…
starblue

5
@PierreBdR: अगर मैं दिशा में 0deg में दो कदम और एक दिशा 90deg में ले जाऊंगा, तो मैं उस दिशा में 26.56 डिग्री नीचे चला गया होगा जहाँ मैंने शुरुआत की थी। इस लिहाज से 26.56 30 डिग्री से कम {0,0,90} औसत की दिशा में ज्यादा मायने रखता है। बीजगणितीय औसत कई संभावित औसत में से एक है (देखें en.wikipedia.org/wiki/Mean ) - और यह औसत दिशाओं के उद्देश्य के लिए काफी अप्रासंगिक लगता है (जैसा कि यह कई अन्य लोगों के लिए करता है)।
जानूस

60

इस प्रश्न की पुस्तक में विस्तार से जांच की गई है: "सांख्यिकी पर क्षेत्रों", जेफ्री एस वॉटसन, यूनिवर्सिटी ऑफ अरकंसास लेक्चर नोट्स इन द मैथमेटिकल साइंसेज, 1983 जॉन विले एंड संस, इंक । http: //atatless.ncl पर उल्लेख किया गया है । ac.uk/Risks/7.44.html#subj4 ब्रूस कर्ष द्वारा।

एक औसत कोण का अनुमान लगाने का एक अच्छा तरीका, ए, कोण माप के एक सेट से [i] 0 <= i

                   sum_i_from_1_to_N sin(a[i])
a = arctangent ---------------------------
                   sum_i_from_1_to_N cos(a[i])

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

विषय अब विकिपीडिया पर और अधिक विस्तार से और अन्य उपयोगों के साथ भिन्नात्मक भागों की तरह खोजा गया है ।


8
जो कि आप के रूप में एक ही समय में पोस्ट किए गए एल्गोरिथ्म के समान ही है। आपको सादा एटैन के बजाय atan2 का उपयोग करने की आवश्यकता होगी, हालांकि, अन्यथा आप यह नहीं बता सकते कि उत्तर में कौन सा चतुर्थांश है।
Alnitak

आप अभी भी कुछ अनिश्चित उत्तरों के साथ समाप्त कर सकते हैं। जैसे 0 में, 180 नमूना। तो आपको अभी भी किनारे के मामलों की जांच करनी होगी। इसके अलावा, आमतौर पर एक atan2 फ़ंक्शन उपलब्ध है जो आपके मामले में तेज हो सकता है।
लोकी

50

मैं समस्या देखता हूं - उदाहरण के लिए, यदि आपके पास 45 'कोण और 315' कोण है, तो "प्राकृतिक" औसत 180 होगा, लेकिन आप जो मूल्य चाहते हैं वह वास्तव में 0 'है।

मुझे लगता है कि Starblue कुछ है। प्रत्येक कोण के लिए बस (x, y) कार्टेशियन निर्देशांक की गणना करें, और उन परिणामस्वरूप वैक्टर को एक साथ जोड़ें। अंतिम वेक्टर की कोणीय ऑफसेट आपका आवश्यक परिणाम होना चाहिए।

x = y = 0
foreach angle {
    x += cos(angle)
    y += sin(angle)
}
average_angle = atan2(y, x)

मैं अब इस बात की अनदेखी कर रहा हूं कि उत्तर में कम्पास हेडिंग शुरू होती है, और दक्षिणावर्त जाती है, जबकि "सामान्य" कार्टिजियन निर्देशांक एक्स अक्ष के साथ शून्य से शुरू होते हैं, और फिर एंटी-क्लॉकवाइज जाते हैं। गणित को भले ही उसी तरह से काम करना चाहिए।


13
आपका गणित पुस्तकालय शायद कोणों के लिए रेडियंस का उपयोग करता है। कन्वर्ट करने के लिए याद रखें।
मार्टिन बेकेट

2
शायद यह रात में बहुत देर हो चुकी है, लेकिन इस तर्क का उपयोग करते हुए, मुझे 341.8947 का औसत कोण मिलता है ... 342 के बजाय [320, 330, 340, 350, 10,] के कोण के लिए। कोई भी मेरा टाइपो देखे?
एलेक्स रॉबिन्सन

1
@ एलेक्स रॉबिन्सन यह एक टाइपो नहीं है, यह इसलिए है क्योंकि अंतिम कोण केवल उन कोणों में से प्रत्येक के चरणों का एक सेट लेने के द्वारा प्राप्त अंतिम कोण है।
अलनीतक

1
@AlexRobinson, अधिक विशिष्ट: cos(), sin()और atan2()अनुमानों देना (अच्छे, लेकिन अभी भी 1 या 2 ulps द्वारा बंद) इसलिए अधिक आप औसत, अधिक त्रुटियों आप शामिल हैं।
Matthieu

23

दो एंगल्स के विशेष मामले के लिए:

इस सवाल का जवाब ((ए + बी) आधुनिक 360) / 2 है गलत । कोण 350 और 2 के लिए, निकटतम बिंदु 356 है, 176 नहीं।

यूनिट वेक्टर और ट्रिग सॉल्यूशंस बहुत महंगे हो सकते हैं।

मैं थोड़ा छेड़छाड़ से क्या मिला है:

diff = ( ( a - b + 180 + 360 ) mod 360 ) - 180
angle = (360 + b + ( diff / 2 ) ) mod 360
  • 0, 180 -> 90 (इसके लिए दो उत्तर: यह समीकरण एक से दक्षिणावर्त उत्तर लेता है)
  • 180, 0 -> 270 (ऊपर देखें)
  • 180, 1 -> 90.5
  • 1, 180 -> 90.5
  • 20, 350 -> 5
  • 350, 20 -> 5 (सभी निम्नलिखित उदाहरण भी ठीक से उल्टे हैं)
  • 10, 20 -> 15
  • 350, 2 -> 356
  • 359, 0 -> 359.5
  • 180, 180 -> 180

इसे आगे BAMS के उपयोग द्वारा अनुकूलित किया जा सकता है: stackoverflow.com/questions/1048945/…
darron

बुरा नहीं। पहली पंक्ति, रेंज [-180, 179] में बी के संबंध में एक सापेक्ष कोण की गणना करती है, दूसरी उसके बाद मध्य कोण की गणना करती है। मैं स्पष्टता के लिए a / diff / 2 के बजाय b + diff / 2 का उपयोग करता हूं।
स्टारबेल

1
क्या मैं कुछ भूल रहा हूँ? मैं क्या मिलता है 295
darron

आह .. मैं समझ गया। मतलब का मॉड ऑपरेटर रैप -10 से 350 है। मैं कोड बदल दूंगा। यह एक साधारण अतिरिक्त 360 है।
डार्रॉन

इस पद्धति की एक और अच्छी विशेषता यह है कि दो कोणों के भारित औसत को लागू करना आसान है। दूसरी पंक्ति में, पहले कोण के वजन से गुणा करें और 2 को हर में भार के योग से प्रतिस्थापित करें। कोण = (360 + b + (WEIGHT [a] * diff / (WEIGHT [a + +
WE

14

अकब सही है कि इन वेक्टर आधारित समाधानों को कोणों का सही औसत नहीं माना जा सकता है, वे केवल यूनिट वेक्टर समकक्षों का एक औसत हैं। हालाँकि, ackb का सुझाया गया समाधान गणितीय रूप से ध्वनि के लिए प्रकट नहीं होता है।

निम्नलिखित एक ऐसा समाधान है जो गणितीय रूप से न्यूनतम (कोण [i] - avgAngle) ^ 2 के लक्ष्य से लिया गया है (2 जहां अंतर आवश्यक होने पर सही किया जाता है), जो इसे कोणों का एक वास्तविक अंकगणितीय माध्य बनाता है।

सबसे पहले, हमें यह देखने की जरूरत है कि कोणों के बीच अंतर उनके सामान्य संख्या समकक्षों के बीच अंतर के लिए अलग है। कोण x और y पर विचार करें, यदि y> = x - 180 और y <= x + 180 है, तो हम अंतर का उपयोग कर सकते हैं (xy)। अन्यथा, यदि पहली शर्त पूरी नहीं होती है, तो हमें y के बजाय गणना में (y + 360) का उपयोग करना चाहिए। इसके विपरीत, यदि दूसरी शर्त पूरी नहीं होती है, तो हमें y के बजाय (y-360) का उपयोग करना चाहिए। वक्र के समीकरण के बाद से हम केवल उन बिंदुओं पर परिवर्तन को कम कर रहे हैं जहां ये असमानताएं सही से गलत या इसके विपरीत बदल जाती हैं, हम पूर्ण [0,360) रेंज को इन बिंदुओं से अलग करके खंडों के एक समूह में बदल सकते हैं। फिर, हमें केवल इनमें से प्रत्येक सेगमेंट का न्यूनतम पता लगाना है, और फिर प्रत्येक सेगमेंट का न्यूनतम, जो कि औसत है।

यहां एक छवि प्रदर्शित की गई है जहां कोण अंतर की गणना में समस्याएं आती हैं। यदि x ग्रे क्षेत्र में स्थित है तो समस्या होगी।

कोण तुलना

एक चर को कम करने के लिए, वक्र के आधार पर, हम व्युत्पन्न कर सकते हैं कि हम क्या कम करना चाहते हैं और फिर हम मोड़ पाते हैं (जो कि व्युत्पन्न = 0 है)।

यहाँ हम सामान्य अंकगणितीय माध्य सूत्र को प्राप्त करने के लिए वर्ग अंतर को कम करने के विचार को लागू करेंगे: योग (a [i] / n। वक्र y = योग (([[i -x) ^ 2) को इस तरह से कम से कम किया जा सकता है:

y = sum((a[i]-x)^2)
= sum(a[i]^2 - 2*a[i]*x + x^2)
= sum(a[i]^2) - 2*x*sum(a[i]) + n*x^2

dy\dx = -2*sum(a[i]) + 2*n*x

for dy/dx = 0:
-2*sum(a[i]) + 2*n*x = 0
-> n*x = sum(a[i])
-> x = sum(a[i])/n

अब इसे हमारे समायोजित अंतरों के साथ घटता पर लागू करना है:

b = जहाँ सही (कोणीय) अंतर का उपसमूह [i] -xc = जहाँ सही (कोणीय) अंतर का उपसमूह ([i] -360) -x cn = cd का आकार = जहाँ एक का सबसेट सही (कोणीय) अंतर ([i] +360) -x dn = d का आकार

y = sum((b[i]-x)^2) + sum(((c[i]-360)-b)^2) + sum(((d[i]+360)-c)^2)
= sum(b[i]^2 - 2*b[i]*x + x^2)
  + sum((c[i]-360)^2 - 2*(c[i]-360)*x + x^2)
  + sum((d[i]+360)^2 - 2*(d[i]+360)*x + x^2)
= sum(b[i]^2) - 2*x*sum(b[i])
  + sum((c[i]-360)^2) - 2*x*(sum(c[i]) - 360*cn)
  + sum((d[i]+360)^2) - 2*x*(sum(d[i]) + 360*dn)
  + n*x^2
= sum(b[i]^2) + sum((c[i]-360)^2) + sum((d[i]+360)^2)
  - 2*x*(sum(b[i]) + sum(c[i]) + sum(d[i]))
  - 2*x*(360*dn - 360*cn)
  + n*x^2
= sum(b[i]^2) + sum((c[i]-360)^2) + sum((d[i]+360)^2)
  - 2*x*sum(x[i])
  - 2*x*360*(dn - cn)
  + n*x^2

dy/dx = 2*n*x - 2*sum(x[i]) - 2*360*(dn - cn)

for dy/dx = 0:
2*n*x - 2*sum(x[i]) - 2*360*(dn - cn) = 0
n*x = sum(x[i]) + 360*(dn - cn)
x = (sum(x[i]) + 360*(dn - cn))/n

यह अकेले न्यूनतम प्राप्त करने के लिए पर्याप्त नहीं है, जबकि यह सामान्य मूल्यों के लिए काम करता है, जिसमें एक बिना सेट है, इसलिए परिणाम निश्चित रूप से सेट की सीमा के भीतर झूठ होगा और इसलिए मान्य है। हमें एक सीमा के भीतर न्यूनतम (सेगमेंट द्वारा परिभाषित) की आवश्यकता है। यदि न्यूनतम हमारे सेगमेंट की निचली सीमा से कम है, तो उस सेगमेंट की न्यूनतम सीमा से कम होना चाहिए (क्योंकि द्विघात वक्रों में केवल 1 मोड़ होता है) और यदि न्यूनतम हमारे सेगमेंट के ऊपरी बाउंड से अधिक है तो सेगमेंट की न्यूनतम सीमा पर है ऊपरी सीमा। हमारे पास प्रत्येक सेगमेंट के लिए न्यूनतम होने के बाद, हम बस वही पाते हैं जिसका न्यूनतम मूल्य है जो हम कम से कम कर रहे हैं (राशि (b [i] -x) ^ 2) + योग ((c [i] -360) ) -b) ^ 2) + योग ((d [i] +360) -c) ^ 2))।

यहां वक्र के लिए एक छवि है, जो दिखाता है कि यह उन बिंदुओं पर कैसे बदलता है जहां x = ([[i] +180)% 360 है। डेटा सेट विचाराधीन है {65,92,230,320,250}।

वक्र

यहां जावा में एल्गोरिथ्म का कार्यान्वयन है, जिसमें कुछ अनुकूलन भी शामिल हैं, इसकी जटिलता हे (nlogn) है। इसे घटाकर O (n) किया जा सकता है यदि आप तुलना आधारित प्रकार को गैर-तुलना आधारित सॉर्ट के साथ प्रतिस्थापित करते हैं, जैसे कि मूलांक सॉर्ट।

static double varnc(double _mean, int _n, double _sumX, double _sumSqrX)
{
    return _mean*(_n*_mean - 2*_sumX) + _sumSqrX;
}
//with lower correction
static double varlc(double _mean, int _n, double _sumX, double _sumSqrX, int _nc, double _sumC)
{
    return _mean*(_n*_mean - 2*_sumX) + _sumSqrX
            + 2*360*_sumC + _nc*(-2*360*_mean + 360*360);
}
//with upper correction
static double varuc(double _mean, int _n, double _sumX, double _sumSqrX, int _nc, double _sumC)
{
    return _mean*(_n*_mean - 2*_sumX) + _sumSqrX
            - 2*360*_sumC + _nc*(2*360*_mean + 360*360);
}

static double[] averageAngles(double[] _angles)
{
    double sumAngles;
    double sumSqrAngles;

    double[] lowerAngles;
    double[] upperAngles;

    {
        List<Double> lowerAngles_ = new LinkedList<Double>();
        List<Double> upperAngles_ = new LinkedList<Double>();

        sumAngles = 0;
        sumSqrAngles = 0;
        for(double angle : _angles)
        {
            sumAngles += angle;
            sumSqrAngles += angle*angle;
            if(angle < 180)
                lowerAngles_.add(angle);
            else if(angle > 180)
                upperAngles_.add(angle);
        }


        Collections.sort(lowerAngles_);
        Collections.sort(upperAngles_,Collections.reverseOrder());


        lowerAngles = new double[lowerAngles_.size()];
        Iterator<Double> lowerAnglesIter = lowerAngles_.iterator();
        for(int i = 0; i < lowerAngles_.size(); i++)
            lowerAngles[i] = lowerAnglesIter.next();

        upperAngles = new double[upperAngles_.size()];
        Iterator<Double> upperAnglesIter = upperAngles_.iterator();
        for(int i = 0; i < upperAngles_.size(); i++)
            upperAngles[i] = upperAnglesIter.next();
    }

    List<Double> averageAngles = new LinkedList<Double>();
    averageAngles.add(180d);
    double variance = varnc(180,_angles.length,sumAngles,sumSqrAngles);

    double lowerBound = 180;
    double sumLC = 0;
    for(int i = 0; i < lowerAngles.length; i++)
    {
        //get average for a segment based on minimum
        double testAverageAngle = (sumAngles + 360*i)/_angles.length;
        //minimum is outside segment range (therefore not directly relevant)
        //since it is greater than lowerAngles[i], the minimum for the segment
        //must lie on the boundary lowerAngles[i]
        if(testAverageAngle > lowerAngles[i]+180)
            testAverageAngle = lowerAngles[i];

        if(testAverageAngle > lowerBound)
        {
            double testVariance = varlc(testAverageAngle,_angles.length,sumAngles,sumSqrAngles,i,sumLC);

            if(testVariance < variance)
            {
                averageAngles.clear();
                averageAngles.add(testAverageAngle);
                variance = testVariance;
            }
            else if(testVariance == variance)
                averageAngles.add(testAverageAngle);
        }

        lowerBound = lowerAngles[i];
        sumLC += lowerAngles[i];
    }
    //Test last segment
    {
        //get average for a segment based on minimum
        double testAverageAngle = (sumAngles + 360*lowerAngles.length)/_angles.length;
        //minimum is inside segment range
        //we will test average 0 (360) later
        if(testAverageAngle < 360 && testAverageAngle > lowerBound)
        {
            double testVariance = varlc(testAverageAngle,_angles.length,sumAngles,sumSqrAngles,lowerAngles.length,sumLC);

            if(testVariance < variance)
            {
                averageAngles.clear();
                averageAngles.add(testAverageAngle);
                variance = testVariance;
            }
            else if(testVariance == variance)
                averageAngles.add(testAverageAngle);
        }
    }


    double upperBound = 180;
    double sumUC = 0;
    for(int i = 0; i < upperAngles.length; i++)
    {
        //get average for a segment based on minimum
        double testAverageAngle = (sumAngles - 360*i)/_angles.length;
        //minimum is outside segment range (therefore not directly relevant)
        //since it is greater than lowerAngles[i], the minimum for the segment
        //must lie on the boundary lowerAngles[i]
        if(testAverageAngle < upperAngles[i]-180)
            testAverageAngle = upperAngles[i];

        if(testAverageAngle < upperBound)
        {
            double testVariance = varuc(testAverageAngle,_angles.length,sumAngles,sumSqrAngles,i,sumUC);

            if(testVariance < variance)
            {
                averageAngles.clear();
                averageAngles.add(testAverageAngle);
                variance = testVariance;
            }
            else if(testVariance == variance)
                averageAngles.add(testAverageAngle);
        }

        upperBound = upperAngles[i];
        sumUC += upperBound;
    }
    //Test last segment
    {
        //get average for a segment based on minimum
        double testAverageAngle = (sumAngles - 360*upperAngles.length)/_angles.length;
        //minimum is inside segment range
        //we test average 0 (360) now           
        if(testAverageAngle < 0)
            testAverageAngle = 0;

        if(testAverageAngle < upperBound)
        {
            double testVariance = varuc(testAverageAngle,_angles.length,sumAngles,sumSqrAngles,upperAngles.length,sumUC);

            if(testVariance < variance)
            {
                averageAngles.clear();
                averageAngles.add(testAverageAngle);
                variance = testVariance;
            }
            else if(testVariance == variance)
                averageAngles.add(testAverageAngle);
        }
    }


    double[] averageAngles_ = new double[averageAngles.size()];
    Iterator<Double> averageAnglesIter = averageAngles.iterator();
    for(int i = 0; i < averageAngles_.length; i++)
        averageAngles_[i] = averageAnglesIter.next();


    return averageAngles_;
}

कोणों के एक सेट का अंकगणितीय माध्य आपके सहज विचार से सहमत नहीं हो सकता है कि औसत क्या होना चाहिए। उदाहरण के लिए, सेट का अंकगणितीय माध्य {179,179,0,181,181} 216 (और 144) है। आपके द्वारा तुरंत सोचा गया उत्तर संभवतः 180 है, हालांकि यह सर्वविदित है कि अंकगणित माध्य धार मूल्यों से अत्यधिक प्रभावित है। आपको यह भी याद रखना चाहिए कि कोण वैक्टर नहीं हैं, जैसा कि अपील करते हैं कि कभी-कभी कोणों के साथ काम करते समय लग सकता है।

यह एल्गोरिथ्म निश्चित रूप से उन सभी मात्राओं पर भी लागू होता है जो मॉड्यूलर अंकगणित (न्यूनतम समायोजन के साथ) का पालन करते हैं, जैसे कि दिन का समय।

मैं यह भी कहना चाहूंगा कि भले ही यह वेक्टर समाधानों के विपरीत कोणों का एक सही औसत है, लेकिन इसका मतलब यह नहीं है कि यह वह समाधान है जिसका आपको उपयोग करना चाहिए, इसी यूनिट वैक्टर का औसत वास्तव में आपके लिए मूल्य हो सकता है का उपयोग करना चाहिए।


मित्सुता विधि वास्तव में शुरुआती कोण + प्रारंभिक कोण से घुमावों का औसत देती है। तो एक समान विधि प्राप्त करने के लिए, माप त्रुटि के लिए लेखांकन तब आपको होने वाले घुमावों को देखना होगा और उन लोगों के लिए त्रुटि का अनुमान लगाना होगा। मुझे लगता है कि उनके लिए एक त्रुटि का अनुमान लगाने के लिए आपको रोटेशन के लिए एक वितरण की आवश्यकता होगी।
फुर्तीला

6

आपको औसत को अधिक सटीक रूप से परिभाषित करना होगा । दो कोणों के विशिष्ट मामले के लिए, मैं दो अलग-अलग परिदृश्यों के बारे में सोच सकता हूं:

  1. "सही" औसत, (a + b) / 2% 360।
  2. एक ही अर्धवृत्त में रहते हुए दो अन्य के बीच "कोण" को इंगित करता है, जैसे 355 और 5 के लिए, यह 0 होगा, 180 नहीं। ऐसा करने के लिए, आपको यह जांचने की आवश्यकता है कि क्या दो कोणों के बीच का अंतर 180 से बड़ा है या नहीं। यदि हां, तो उपरोक्त सूत्र का उपयोग करने से पहले छोटे कोण को 360 से बढ़ाएं।

मैं यह नहीं देखता कि दो कोणों से अधिक के मामले के लिए दूसरा विकल्प कैसे सामान्य किया जा सकता है।


हालांकि यह प्रश्न कोणों को संदर्भित करता है, लेकिन इसका अर्थ दिशा के रूप में बेहतर है, और यह एक सामान्य नेविगेशन मुद्दा है।
SmacL

अच्छे अंक, डेविड। उदाहरण के लिए, 180º कोण और 540? कोण का औसत क्या है? क्या यह 360 Is या 180º है?
बाल्टीमार्क

3
@ बाल्टिमार्क, मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप क्या कर रहे हैं। यदि इसका नेविगेशन, शायद बाद का। यदि यह एक फैंसी स्नोबोर्डिंग जंप है, तो शायद पूर्व;)
SmacL

तो 1 और 359 का "सही" औसत (360/2)% 360 = 180 है ?? मुझे नहीं लगता।
को Sente में

1
@ सेंटी में: संख्यात्मक रूप से बोलना, निश्चित रूप से। उदाहरण के लिए, यदि कोण दिशाओं का प्रतिनिधित्व करते हैं, दिशाओं का नहीं, तो 359 और 1 का औसत निश्चित रूप से 180 है। यह सब व्याख्या का विषय है।
डेविड हैनक

4

सभी औसत की तरह, उत्तर मीट्रिक की पसंद पर निर्भर करता है। दिए गए मीट्रिक M के लिए, [1, N] में k के लिए [-pi, pi] में कुछ कोणों का औसत a_M है, जो कोण a_M है जो वर्ग दूरी d ^ 2_M (a_M, a_k) का योग न्यूनतम करता है। एक भारित माध्य के लिए, एक तो वजन w_k में समाहित होता है (जैसे कि sum_k w_k = 1)। अर्थात्,

a_M = arg min_x sum_k w_k d ^ 2_M (x, a_k)

मीट्रिक के दो सामान्य विकल्प फ्रोबेनियस और रीमैन मेट्रिक्स हैं। फ्रोबेनियस मीट्रिक के लिए, एक प्रत्यक्ष सूत्र मौजूद है जो परिपत्र आँकड़ों में औसत असर की सामान्य धारणा से मेल खाती है। विवरण के लिए "रोटेशन के समूह में साधन और एवरेजिंग", मैहर मोखेर, सियाम जर्नल, वॉल्यूम 24, अंक 24, अंक 1, 2002 देखें।
http://link.aip.org/link/?SJMAEL/24/1/1

यहाँ GNU ऑक्टेव 3.2.4 के लिए एक कार्य है जो गणना करता है:

function ma=meanangleoct(a,w,hp,ntype)
%   ma=meanangleoct(a,w,hp,ntype) returns the average of angles a
%   given weights w and half-period hp using norm type ntype
%   Ref: "Means and Averaging in the Group of Rotations",
%   Maher Moakher, SIAM Journal on Matrix Analysis and Applications,
%   Volume 24, Issue 1, 2002.

if (nargin<1) | (nargin>4), help meanangleoct, return, end 
if isempty(a), error('no measurement angles'), end
la=length(a); sa=size(a); 
if prod(sa)~=la, error('a must be a vector'); end
if (nargin<4) || isempty(ntype), ntype='F'; end
if ~sum(ntype==['F' 'R']), error('ntype must be F or R'), end
if (nargin<3) || isempty(hp), hp=pi; end
if (nargin<2) || isempty(w), w=1/la+0*a; end
lw=length(w); sw=size(w); 
if prod(sw)~=lw, error('w must be a vector'); end
if lw~=la, error('length of w must equal length of a'), end
if sum(w)~=1, warning('resumming weights to unity'), w=w/sum(w); end

a=a(:);     % make column vector
w=w(:);     % make column vector
a=mod(a+hp,2*hp)-hp;    % reduce to central period
a=a/hp*pi;              % scale to half period pi
z=exp(i*a); % U(1) elements

% % NOTA BENE:
% % fminbnd can get hung up near the boundaries.
% % If that happens, shift the input angles a
% % forward by one half period, then shift the
% % resulting mean ma back by one half period.
% X=fminbnd(@meritfcn,-pi,pi,[],z,w,ntype);

% % seems to work better
x0=imag(log(sum(w.*z)));
X=fminbnd(@meritfcn,x0-pi,x0+pi,[],z,w,ntype);

% X=real(X);              % truncate some roundoff
X=mod(X+pi,2*pi)-pi;    % reduce to central period
ma=X*hp/pi;             % scale to half period hp

return
%%%%%%

function d2=meritfcn(x,z,w,ntype)
x=exp(i*x);
if ntype=='F'
    y=x-z;
else % ntype=='R'
    y=log(x'*z);
end
d2=y'*diag(w)*y;
return
%%%%%%

% %   test script
% % 
% % NOTA BENE: meanangleoct(a,[],[],'R') will equal mean(a) 
% % when all abs(a-b) < pi/2 for some value b
% % 
% na=3, a=sort(mod(randn(1,na)+1,2)-1)*pi;
% da=diff([a a(1)+2*pi]); [mda,ndx]=min(da);
% a=circshift(a,[0 2-ndx])    % so that diff(a(2:3)) is smallest
% A=exp(i*a), B1=expm(a(1)*[0 -1; 1 0]), 
% B2=expm(a(2)*[0 -1; 1 0]), B3=expm(a(3)*[0 -1; 1 0]),
% masimpl=[angle(mean(exp(i*a))) mean(a)]
% Bsum=B1+B2+B3; BmeanF=Bsum/sqrt(det(Bsum)); 
% % this expression for BmeanR should be correct for ordering of a above
% BmeanR=B1*(B1'*B2*(B2'*B3)^(1/2))^(2/3);
% mamtrx=real([[0 1]*logm(BmeanF)*[1 0]' [0 1]*logm(BmeanR)*[1 0]'])
% manorm=[meanangleoct(a,[],[],'F') meanangleoct(a,[],[],'R')]
% polar(a,1+0*a,'b*'), axis square, hold on
% polar(manorm(1),1,'rs'), polar(manorm(2),1,'gd'), hold off

%     Meanangleoct Version 1.0
%     Copyright (C) 2011 Alphawave Research, robjohnson@alphawaveresearch.com
%     Released under GNU GPLv3 -- see file COPYING for more info.
%
%     Meanangle is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or (at
%     your option) any later version.
%
%     Meanangle is distributed in the hope that it will be useful, but
%     WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%     General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see `http://www.gnu.org/licenses/'.

4

मैं एक ऐसी विधि साझा करना चाहता हूं जिसका उपयोग मैंने एक माइक्रोकंट्रोलर के साथ किया था जिसमें फ्लोटिंग पॉइंट या त्रिकोणमिति क्षमताएं नहीं थीं। विविधताओं को सुचारू करने के लिए मुझे अभी भी "औसत" 10 कच्चे असर रीडिंग की आवश्यकता थी।

  1. जांचें कि क्या पहला असर 270-360 या 0-90 डिग्री (उत्तरी दो चतुर्थांश) की सीमा है
  2. यदि ऐसा है, तो इसे और बाद के सभी रीडिंग को 180 डिग्री से घुमाएं, सभी मानों को 0 <= वहन करने वाले <360 पर रखें। अन्यथा रीडिंग को अपने पास ले जाएं।
  3. एक बार 10 रीडिंग लेने के बाद संख्यात्मक औसत की गणना यह मानकर कि कोई रैपराउंड नहीं हुआ है
  4. यदि 180 डिग्री का घुमाव प्रभावी रहा हो, तो "सही" असर पाने के लिए गणना औसत को 180 डिग्री से घुमाएं।

यह आदर्श नहीं है; यह टूट सकता है। मैं इस मामले में इसके साथ दूर हो गया क्योंकि डिवाइस केवल बहुत धीरे-धीरे घूमता है। अगर कोई और खुद को ऐसे ही प्रतिबंधों के तहत काम करता हुआ पाता है तो मैं इसे वहाँ रखूँगा।


3

अंग्रेजी में:

  1. 180 के द्वारा स्थानांतरित किए गए सभी कोणों के साथ एक दूसरा डेटा सेट करें।
  2. दोनों डेटा सेट का विचरण करें।
  3. सबसे छोटे विचरण के साथ सेट किए गए डेटा का औसत लें।
  4. अगर यह औसत शिफ्ट किए गए सेट से है तो उत्तर को फिर से 180 से बदल दें।

अजगर में:

कोणों की एक # Numpy NX1 सरणी

if np.var(A) < np.var((A-180)%360):
    average = np.average(A)

else:
    average = (np.average((A-180)%360)+180)%360

यह ट्रिगर कार्यों के बिना अंतिम परिणाम प्राप्त करने का एक शानदार तरीका है, यह सरल और लागू करना आसान है।
इयान मर्सर

यह परिपत्र डेटा की किसी भी सीमा के लिए काम करता है; सिर्फ आधा गोलाकार सीमा द्वारा बदलाव; बहुत बढ़िया जवाब!
कप्तान शानदार

3

यहाँ पूर्ण समाधान है: (इनपुट डिग्री में असर की एक सरणी है (0-360)

public static int getAvarageBearing(int[] arr)
{
    double sunSin = 0;
    double sunCos = 0;
    int counter = 0;

    for (double bearing : arr)
    {
        bearing *= Math.PI/180;

        sunSin += Math.sin(bearing);
        sunCos += Math.cos(bearing);
        counter++; 
    }

    int avBearing = INVALID_ANGLE_VALUE;
    if (counter > 0)
    {
        double bearingInRad = Math.atan2(sunSin/counter, sunCos/counter);
        avBearing = (int) (bearingInRad*180f/Math.PI);
        if (avBearing<0)
            avBearing += 360;
    }

    return avBearing;
}

इस समस्या ने मुझे थोड़ी देर के लिए चकित कर दिया है, आपका समाधान काम करता है (Arduino का उपयोग करते हुए, इसलिए आपके कोड में कुछ परिवर्तन हुए हैं, लेकिन ज्यादा कुछ नहीं), मैं कम्पास पढ़ने और हर 50ms में रीडिंग ले रहा हूं और 16 x रीडिंग ऐरे में स्टोर कर रहा हूं, जो तब मैं उपयोग करता हूं ऊपर आपके फ़ंक्शन में, 0-360 के मुद्दे को हल किया गया है! धन्यवाद :)
एंडोलॉजी

3

अजगर में, [-180, 180) के बीच के कोणों के साथ

def add_angles(a, b):
  return (a + b + 180) % 360 - 180

def average_angles(a, b):
  return add_angles(a, add_angles(-a, b)/2)

विवरण:

दो कोणों के औसत के लिए दो औसत 180 ° अलग हैं, लेकिन हम करीब औसत चाहते हैं।

दिखने में, नीला (की औसत ) और हरा ( एक ) की पैदावार चैती बिंदु:

मूल

कोण 'चारों ओर लपेटें' (जैसे 355 + 10 = 5), लेकिन मानक अंकगणित इस शाखा बिंदु की उपेक्षा करेगा। हालांकि अगर कोण b शाखा बिंदु के विपरीत है, तो ( b + g) ) / 2 निकटतम औसत देता है: चैती बिंदु।

किसी भी दो कोणों के लिए, हम समस्या को घुमा सकते हैं ताकि कोणों में से एक शाखा बिंदु के विपरीत हो, मानक औसत प्रदर्शन करें, फिर वापस घुमाएं।

घुमायालौटा हुआ


2

मैं जटिल संख्याओं का उपयोग करके सदिश मार्ग पर जाऊंगा। मेरा उदाहरण पायथन में है, जिसमें अंतर्निहित जटिल संख्याएं हैं:

import cmath # complex math

def average_angle(list_of_angles):

    # make a new list of vectors
    vectors= [cmath.rect(1, angle) # length 1 for each vector
        for angle in list_of_angles]

    vector_sum= sum(vectors)

    # no need to average, we don't care for the modulus
    return cmath.phase(vector_sum)

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


2

यहां पूर्ण C ++ समाधान दिया गया है:

#include <vector>
#include <cmath>

double dAngleAvg(const vector<double>& angles) {
    auto avgSin = double{ 0.0 };
    auto avgCos = double{ 0.0 };
    static const auto conv      = double{ 0.01745329251994 }; // PI / 180
    static const auto i_conv    = double{ 57.2957795130823 }; // 180 / PI
    for (const auto& theta : angles) {
        avgSin += sin(theta*conv);
        avgCos += cos(theta*conv);
    }
    avgSin /= (double)angles.size();
    avgCos /= (double)angles.size();
    auto ret = double{ 90.0 - atan2(avgCos, avgSin) * i_conv };
    if (ret<0.0) ret += 360.0;
    return fmod(ret, 360.0);
}

यह युगल के वेक्टर के रूप में कोण लेता है, और औसत को एक डबल के रूप में लौटाता है। कोणों को डिग्री में होना चाहिए, और निश्चित रूप से औसत डिग्री में भी है।


avgCosx घटकों avgSinका औसत है , और y घटकों का औसत है। आर्कटेंट फ़ंक्शन के पैरामीटर हैं atan2( y, x )। तो, इसके बजाय आपका कोड नहीं होना चाहिए: atan2( avgSin, avgCos ) ??
माइक फिंच

मुझे यह एल्गोरिथ्म कहीं से मिला, मैं खुद इसके साथ नहीं आया था, इसलिए मुझे लगता है कि यह जिस तरह से सही है। साथ ही यह सही परिणाम भी देता है।
adam10603

2

अलनीतक के जवाब के आधार पर , मैंने कई कोणों के औसत की गणना के लिए एक जावा विधि लिखी है:

यदि आपके कोण रेडियन में हैं:

public static double averageAngleRadians(double... angles) {
    double x = 0;
    double y = 0;
    for (double a : angles) {
        x += Math.cos(a);
        y += Math.sin(a);
    }

    return Math.atan2(y, x);
}

यदि आपके कोण डिग्री में हैं:

public static double averageAngleDegrees(double... angles) {
    double x = 0;
    double y = 0;
    for (double a : angles) {
        x += Math.cos(Math.toRadians(a));
        y += Math.sin(Math.toRadians(a));
    }

    return Math.toDegrees(Math.atan2(y, x));
}

1

यहां एक विचार दिया गया है: वजन को ध्यान में रखते हुए हमेशा एक साथ निकटतम होने वाले कोणों के औसत की गणना करके औसत चलने का निर्माण करें।

एक और विचार: दिए गए कोणों के बीच सबसे बड़ा अंतर पाते हैं। उस बिंदु को ढूंढें जो इसे bisects करता है, और फिर सर्कल पर विपरीत बिंदु को संदर्भ शून्य से उठाता है, जिससे औसत की गणना की जा सके।


मैं अपने उत्तर की अनुशंसा नहीं करता, बल्कि स्टारब्ले के अत्यधिक रैंक वाले उत्तर की। कम्पास के केंद्र को 0,0 बिंदु के रूप में सोचना महत्वपूर्ण अवलोकन है।
जॉन 19/09 वफ़ल के साथ

1

आइए सर्कल के परिधि पर बिंदुओं के साथ इन कोणों का प्रतिनिधित्व करते हैं।

क्या हम मान सकते हैं कि ये सभी बिंदु वृत्त के एक ही आधे भाग पर आते हैं? (अन्यथा, "औसत कोण" को परिभाषित करने का कोई स्पष्ट तरीका नहीं है। व्यास पर दो बिंदुओं के बारे में सोचें, उदाहरण के लिए 0 डिग्री और 180 डिग्री --- औसत 90 डिग्री या 270 डिग्री है? जब हमारे पास 3 या अधिक होता है तो क्या होता है? समान रूप से बिंदुओं को फैलाना)

इस धारणा के साथ, हम उस अर्धवृत्त पर "मूल" के रूप में एक मनमाना बिंदु उठाते हैं, और इस मूल के संबंध में कोणों के दिए गए सेट को मापते हैं (इसे "सापेक्ष कोण" कहते हैं)। ध्यान दें कि सापेक्ष कोण का निरपेक्ष मान 180 डिग्री से कम है। अंत में, वांछित औसत कोण (निश्चित रूप से हमारी उत्पत्ति के सापेक्ष) प्राप्त करने के लिए इन सापेक्ष कोणों का अर्थ लें।


1

कोई एकल "सही उत्तर" नहीं है। मैं पुस्तक, केवी मर्डिया और पीई जूप, "दिशात्मक सांख्यिकी", (विले, 1999) को गहन विश्लेषण के लिए पढ़ने की सलाह देता हूं।


1

(बस अनुमान सिद्धांत या सांख्यिकीय निष्कर्ष से अपना दृष्टिकोण साझा करना चाहते हैं)

निंबले का परीक्षण एमएमएसई ^ कोणों के एक सेट का अनुमान प्राप्त करना है, लेकिन यह "औसत" दिशा खोजने के लिए विकल्पों में से एक है; कोई MMAE ^ अनुमान, या कुछ अन्य अनुमान "औसत" दिशा पा सकता है, और यह दिशा के आपके मीट्रिक मात्रात्मक त्रुटि पर निर्भर करता है; या अधिक आम तौर पर अनुमान सिद्धांत में, लागत समारोह की परिभाषा।

^ MMSE / MMAE न्यूनतम माध्य वर्ग / पूर्ण त्रुटि से मेल खाती है।

ackb ने कहा "औसत कोण phi_avg के पास संपत्ति होनी चाहिए जो sum_i | phi_avg-phi_i | ^ 2 न्यूनतम हो जाती है ... वे औसत कुछ करते हैं, लेकिन कोण नहीं"

---- आप माध्य-वर्ग अर्थों में त्रुटियों की मात्रा निर्धारित करते हैं और यह ज्यादातर सामान्य तरीकों में से एक है, हालांकि, एकमात्र तरीका नहीं है। अधिकांश लोगों द्वारा यहां (यानी यूनिट वैक्टर के योग और परिणाम के कोण प्राप्त करने के लिए) का जवाब वास्तव में उचित समाधानों में से एक है। यह (अनुमान सिद्ध किया जा सकता है) एमएल अनुमानक जो "औसत" दिशा के रूप में कार्य करता है, जो हम चाहते हैं, यदि वैक्टर की दिशाओं को वॉन मिल्स वितरण के रूप में मॉडलिंग की जाती है। यह वितरण फैंसी नहीं है, और यह केवल एक समय-समय पर 2 डी गासियन से नमूना वितरण है। ईकन देखें। (2.179) बिशप की पुस्तक "पैटर्न रिकॉग्निशन एंड मशीन लर्निंग" में। फिर से, किसी भी तरह से यह "औसत" दिशा का प्रतिनिधित्व करने के लिए एकमात्र सबसे अच्छा एक है, हालांकि, यह काफी उचित है जिसमें अच्छा सैद्धांतिक औचित्य और सरल कार्यान्वयन दोनों हैं।

निंबले ने कहा "अकब सही है कि इन वेक्टर आधारित समाधानों को कोणों का सही औसत नहीं माना जा सकता है, वे केवल यूनिट वेक्टर समकक्षों का एक औसत हैं"

----यह सच नहीं है। "यूनिट वेक्टर समकक्ष" एक वेक्टर की दिशा की जानकारी को प्रकट करता है। कोण वेक्टर की लंबाई पर विचार किए बिना एक मात्रा है, और यूनिट वेक्टर अतिरिक्त जानकारी के साथ कुछ है जो लंबाई 1. है आप अपनी "इकाई" वेक्टर को 2 की लंबाई के रूप में परिभाषित कर सकते हैं, यह वास्तव में कोई फर्क नहीं पड़ता।


1

यहां मूविंग एवरेज का उपयोग करने और मूल्यों को सामान्य बनाने के लिए देखभाल करने का एक पूरी तरह से अंकगणितीय समाधान है। यह तेज है और सही उत्तर देता है यदि सभी कोण सर्कल के एक तरफ हैं (एक दूसरे के 180 ° के भीतर)।

यह गणितीय रूप से ऑफसेट को जोड़ने के बराबर है जो मानों को रेंज (0, 180) में स्थानांतरित करता है, मतलब को शांत करता है और फिर ऑफसेट को घटाता है।

टिप्पणियां बताती हैं कि किसी भी समय एक विशिष्ट मूल्य किस सीमा तक हो सकता है

// angles have to be in the range [0, 360) and within 180° of each other.
// n >= 1
// returns the circular average of the angles int the range [0, 360).
double meanAngle(double* angles, int n)
{
    double average = angles[0];
    for (int i = 1; i<n; i++)
    {
        // average: (0, 360)
        double diff = angles[i]-average;
        // diff: (-540, 540)

        if (diff < -180)
            diff += 360;
        else if (diff >= 180)
            diff -= 360;
        // diff: (-180, 180)

        average += diff/(i+1);
        // average: (-180, 540)

        if (average < 0)
            average += 360;
        else if (average >= 360)
            average -= 360;
        // average: (0, 360)
    }
    return average;
}

1

खैर मुझे पार्टी में देर हो रही है लेकिन मुझे लगा कि मैं अपने 2 सेंट जोड़ूंगा क्योंकि मैं वास्तव में कोई निश्चित जवाब नहीं पा सकता हूं। अंत में मैंने मित्सुता पद्धति के निम्नलिखित जावा संस्करण को लागू किया, जो मुझे आशा है कि एक सरल और मजबूत समाधान प्रदान करता है। विशेष रूप से मानक विचलन दोनों को माप फैलाव प्रदान करता है और, अगर sd == 90 इंगित करता है, कि इनपुट कोण का परिणाम अस्पष्ट होता है।

संपादित करें: वास्तव में मैंने महसूस किया कि मेरे मूल कार्यान्वयन को और भी सरल बनाया जा सकता है, वास्तव में चिंताजनक रूप से सभी वार्तालापों और त्रिकोणमिति को देखते हुए अन्य उत्तरों पर विचार किया जा रहा है।

/**
 * The Mitsuta method
 *
 * @param angles Angles from 0 - 360
 * @return double array containing
 * 0 - mean
 * 1 - sd: a measure of angular dispersion, in the range [0..360], similar to standard deviation.
 * Note if sd == 90 then the mean can also be its inverse, i.e. 360 == 0, 300 == 60.
 */
public static double[] getAngleStatsMitsuta(double... angles) {
    double sum = 0;
    double sumsq = 0;
    for (double angle : angles) {
        if (angle >= 180) {
            angle -= 360;
        }
        sum += angle;
        sumsq += angle * angle;
    }

    double mean = sum / angles.length;
    return new double[]{mean <= 0 ? 360 + mean: mean, Math.sqrt(sumsq / angles.length - (mean * mean))};
}

... और आप सभी के लिए (जावा) वहाँ बाहर geeks, आप एक पंक्ति में माध्य कोण प्राप्त करने के लिए उपरोक्त दृष्टिकोण का उपयोग कर सकते हैं।

Arrays.stream(angles).map(angle -> angle<180 ? angle: (angle-360)).sum() / angles.length;

मेरा मानना ​​है कि आपको मित्सुडा विधि से कुछ याद आया। कृपया Lior Kogan stackoverflow.com/a/1828222/9265852
kykzk46

0

अलनीतक का सही समाधान है। Nick Fortesoscope का समाधान कार्यात्मक रूप से समान है।

जहां के विशेष मामले के लिए

(योग (x_component) = 0.0 && योग (y_component) = 0.0) // उदा। 2 कोण 10. 10. और 190. डिग्री ea।

योग के रूप में 0.0 डिग्री का उपयोग करें

कम्प्यूटेशनल रूप से आपको इस केस के लिए परीक्षण करना होगा क्योंकि atan2 (0, 0.) अपरिभाषित है और एक त्रुटि उत्पन्न करेगा।


पर glibc 'atan2' को (0, 0) के लिए परिभाषित किया गया है - परिणाम 0 है
Alnitak

0

औसत कोण phi_avg में वह गुण होना चाहिए जो sum_i | phi_avg-phi_ | ^ 2 न्यूनतम हो जाता है, जहां अंतर [-पाय, Pi) में होना चाहिए (क्योंकि यह दूसरे के आसपास जाने के लिए छोटा हो सकता है!)। यह आसानी से सभी इनपुट मानों को सामान्य करके प्राप्त किया जाता है [0, 2Pi), एक औसत औसत phi_run रखते हुए और सामान्य चयन करते हुए। phi_i-phi_run | से [-पाय, पाई) (2Pi जोड़कर या घटाकर)। ऊपर दिए गए अधिकांश सुझाव कुछ और करते हैं, जिसमें वह न्यूनतम संपत्ति नहीं होती है, यानी वे कुछ औसत करते हैं , लेकिन कोण नहीं।


0

मैंने @David_Hanak से उत्तर की मदद से समस्या को हल किया। जैसा कि वह बताता है:

एक ही अर्धवृत्त में रहते हुए दो अन्य के बीच "कोण" को इंगित करता है, जैसे 355 और 5 के लिए, यह 0 होगा, 180 नहीं। ऐसा करने के लिए, आपको यह जांचने की आवश्यकता है कि क्या दो कोणों के बीच का अंतर 180 से बड़ा है या नहीं। यदि हां, तो उपरोक्त सूत्र का उपयोग करने से पहले छोटे कोण को 360 से बढ़ाएं।

इसलिए मैंने जो किया वह सभी कोणों के औसत की गणना करता था। और फिर सभी कोण जो इस से कम हैं, उन्हें 360 से बढ़ाएं। फिर उन सभी को जोड़कर औसत को पुनर्गणना करें और उनकी लंबाई से विभाजित करें।

        float angleY = 0f;
        int count = eulerAngles.Count;

        for (byte i = 0; i < count; i++)
            angleY += eulerAngles[i].y;

        float averageAngle = angleY / count;

        angleY = 0f;
        for (byte i = 0; i < count; i++)
        {
            float angle = eulerAngles[i].y;
            if (angle < averageAngle)
                angle += 360f;
            angleY += angle;
        }

        angleY = angleY / count;

अच्छी तरह से काम।


0

पायथन फ़ंक्शन:

from math import sin,cos,atan2,pi
import numpy as np
def meanangle(angles,weights=0,setting='degrees'):
    '''computes the mean angle'''
    if weights==0:
         weights=np.ones(len(angles))
    sumsin=0
    sumcos=0
    if setting=='degrees':
        angles=np.array(angles)*pi/180
    for i in range(len(angles)):
        sumsin+=weights[i]/sum(weights)*sin(angles[i])
        sumcos+=weights[i]/sum(weights)*cos(angles[i])
    average=atan2(sumsin,sumcos)
    if setting=='degrees':
        average=average*180/pi
    return average

0

आप इस फ़ंक्शन का उपयोग मतलाब में कर सकते हैं:

function retVal=DegreeAngleMean(x) 

len=length(x);

sum1=0; 
sum2=0; 

count1=0;
count2=0; 

for i=1:len 
   if x(i)<180 
       sum1=sum1+x(i); 
       count1=count1+1; 
   else 
       sum2=sum2+x(i); 
       count2=count2+1; 
   end 
end 

if (count1>0) 
     k1=sum1/count1; 
end 

if (count2>0) 
     k2=sum2/count2; 
end 

if count1>0 && count2>0 
   if(k2-k1 >= 180) 
       retVal = ((sum1+sum2)-count2*360)/len; 
   else 
       retVal = (sum1+sum2)/len; 
   end 
elseif count1>0 
    retVal = k1; 
else 
    retVal = k2; 
end 

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

0

आप किसी भी प्रोग्रामिंग भाषा के लिए नीचे दिए गए लिंक में एक समाधान और थोड़ा स्पष्टीकरण देख सकते हैं: https://rosettacode.org/wiki/Aactions/Mean_angle

उदाहरण के लिए, C ++ समाधान :

#include<math.h>
#include<stdio.h>

double
meanAngle (double *angles, int size)
{
  double y_part = 0, x_part = 0;
  int i;

  for (i = 0; i < size; i++)
    {
      x_part += cos (angles[i] * M_PI / 180);
      y_part += sin (angles[i] * M_PI / 180);
    }

  return atan2 (y_part / size, x_part / size) * 180 / M_PI;
}

int
main ()
{
  double angleSet1[] = { 350, 10 };
  double angleSet2[] = { 90, 180, 270, 360};
  double angleSet3[] = { 10, 20, 30};

  printf ("\nMean Angle for 1st set : %lf degrees", meanAngle (angleSet1, 2));
  printf ("\nMean Angle for 2nd set : %lf degrees", meanAngle (angleSet2, 4));
  printf ("\nMean Angle for 3rd set : %lf degrees\n", meanAngle (angleSet3, 3));
  return 0;
}

आउटपुट:

Mean Angle for 1st set : -0.000000 degrees
Mean Angle for 2nd set : -90.000000 degrees
Mean Angle for 3rd set : 20.000000 degrees

या मतलाब समाधान :

function u = mean_angle(phi)
    u = angle(mean(exp(i*pi*phi/180)))*180/pi;
end

 mean_angle([350, 10])
ans = -2.7452e-14
 mean_angle([90, 180, 270, 360])
ans = -90
 mean_angle([10, 20, 30])
ans =  20.000

0

जबकि स्टारब्ले का उत्तर औसत यूनिट वेक्टर का कोण देता है, अंकगणित माध्य के कोण को अवधारणा को विस्तारित करना संभव है यदि आप स्वीकार करते हैं कि 0 से 2 * pi (या 0 °) की सीमा में एक से अधिक उत्तर हो सकते हैं। 360 °)। उदाहरण के लिए, 0 ° और 180 ° का औसत या तो 90 ° या 270 ° हो सकता है।

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

इस अवधारणा को किसी भी संख्या में आयामों के लिए बढ़ाया जा सकता है, क्योंकि इकाई क्षेत्र के साथ दूरी की गणना ठीक उसी तरह से की जा सकती है जैसे यूनिट सर्कल के साथ दूरी - दो यूनिट वैक्टर के डॉट उत्पाद के व्युत्क्रम कोसाइन।

हलकों के लिए हम इस औसत के लिए कई तरीकों से हल कर सकते हैं, लेकिन मैं निम्नलिखित O (n ^ 2) का प्रस्ताव करता हूं एल्गोरिथ्म (कोण रेडियन में हैं, और मैं यूनिट वैक्टर की गणना करने से बचता हूं):

var bestAverage = -1
double minimumSquareDistance
for each a1 in input
    var sumA = 0;
    for each a2 in input
        var a = (a2 - a1) mod (2*pi) + a1
        sumA += a
    end for
    var averageHere = sumA / input.count
    var sumSqDistHere = 0
    for each a2 in input
        var dist = (a2 - averageHere + pi) mod (2*pi) - pi // keep within range of -pi to pi
        sumSqDistHere += dist * dist
    end for
    if (bestAverage < 0 OR sumSqDistHere < minimumSquareDistance) // for exceptional cases, sumSqDistHere may be equal to minimumSquareDistance at least once. In these cases we will only find one of the averages
        minimumSquareDistance = sumSqDistHere
        bestAverage = averageHere
    end if
end for
return bestAverage

यदि सभी कोण एक दूसरे के 180 ° के भीतर हैं, तो हम एक सरल O (n) + O (सॉर्ट) एल्गोरिथम (फिर से रेडियन का उपयोग कर और यूनिट वैक्टर के उपयोग से बच सकते हैं) का उपयोग कर सकते हैं:

sort(input)
var largestGapEnd = input[0]
var largestGapSize = (input[0] - input[input.count-1]) mod (2*pi)
for (int i = 1; i < input.count; ++i)
    var gapSize = (input[i] - input[i - 1]) mod (2*pi)
    if (largestGapEnd < 0 OR gapSize > largestGapSize)
        largestGapSize = gapSize
        largestGapEnd = input[i]
    end if
end for
double sum = 0
for each angle in input
    var a2 = (angle - largestGapEnd) mod (2*pi) + largestGapEnd
    sum += a2
end for
return sum / input.count

डिग्री का उपयोग करने के लिए, बस pi को 180 के साथ बदलें। यदि आप अधिक आयामों का उपयोग करने की योजना बनाते हैं, तो आपको औसतन हल करने के लिए पुनरावृत्त विधि का उपयोग करने की सबसे अधिक संभावना होगी।


0

समस्या अत्यंत सरल है। 1. सुनिश्चित करें कि सभी कोण -180 और 180 डिग्री के बीच हैं। 2. सभी गैर-नकारात्मक कोणों को जोड़ें, उनका औसत लें, और COUNT को कितने 2 करें। सभी नकारात्मक कोणों के बारे में जानें, उनका औसत और COUNT को कितने में लें। 3. पोस_आवरेज माइनस नेगेटिव का अंतर लें। लाभ यदि अंतर 180 से अधिक है तो अंतर को 360 माइनस अंतर में बदल दें। अन्यथा केवल अंतर का संकेत बदलें। ध्यान दें कि अंतर हमेशा गैर-नकारात्मक होता है। औसत_एंगल बराबर वजन, सकारात्मक और नकारात्मक गणना के योग से विभाजित "सकारात्मक" प्लस के बराबर है।


0

यहां औसत कोणों के लिए कुछ जावा कोड हैं, मुझे लगता है कि यह काफी मजबूत है।

public static double getAverageAngle(List<Double> angles)
{
    // r = right (0 to 180 degrees)

    // l = left (180 to 360 degrees)

    double rTotal = 0;
    double lTotal = 0;
    double rCtr = 0;
    double lCtr = 0;

    for (Double angle : angles)
    {
        double norm = normalize(angle);
        if (norm >= 180)
        {
            lTotal += norm;
            lCtr++;
        } else
        {
            rTotal += norm;
            rCtr++;
        }
    }

    double rAvg = rTotal / Math.max(rCtr, 1.0);
    double lAvg = lTotal / Math.max(lCtr, 1.0);

    if (rAvg > lAvg + 180)
    {
        lAvg += 360;
    }
    if (lAvg > rAvg + 180)
    {
        rAvg += 360;
    }

    double rPortion = rAvg * (rCtr / (rCtr + lCtr));
    double lPortion = lAvg * (lCtr / (lCtr + rCtr));
    return normalize(rPortion + lPortion);
}

public static double normalize(double angle)
{
    double result = angle;
    if (angle >= 360)
    {
        result = angle % 360;
    }
    if (angle < 0)
    {
        result = 360 + (angle % 360);
    }
    return result;
}

-3

मेरे पास @Starblue की तुलना में एक अलग विधि है जो ऊपर दिए गए कुछ कोणों के "सही" उत्तर देती है। उदाहरण के लिए:

  • angle_avg ([350,10]) = 0
  • angle_avg ([- 90,90,40]) = 13.333
  • angle_avg ([350,2]) = 356

यह लगातार कोणों के बीच अंतर पर एक राशि का उपयोग करता है। कोड (Matlab में):

function [avg] = angle_avg(angles)
last = angles(1);
sum = angles(1);
for i=2:length(angles)
    diff = mod(angles(i)-angles(i-1)+ 180,360)-180
    last = last + diff;
    sum = sum + last;
end
avg = mod(sum/length(angles), 360);
end

1
आपका कोड के लिए अलग अलग जवाब देता है [-90,90,40]और [90,-90,40]; मुझे नहीं लगता कि एक गैर-कम्यूटेटिव औसत एक बहुत ही उपयोगी है।
मुशीफिल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.