(Valószínűleg borzalmasan fogalmazok, terminológia szempontjából kövezzetek meg :) . )
Adott x db szám, és szeretnék egy átlagot (számtani közepet), anélkül, hogy tárolnom kellene az adatgyűjtés végéig az összes számot. Kevés matematikai tudásom alapján megoldhatónak tűnt, rosszul megfogalmazva: csak az átlagot tárolom, és az új adattal annak számolom ki az átlagát, és azt tárolom tovább. Így mindig csak egy számot kell tárolnom.
Próbáltam gyorsan egy egyszerű tesztet csinálni, lehet az jobban érthető egyeseknek, összehasonlítottam a két algoritmust, nem ugyan az az eredmény jön ki, de egymáshoz "nagyjából" közeli.
Kérdések: van-e ilyen algoritmus, és jó irányba próbálkoztam?
- - - - -
$nums = array();
for ($i = 0; $i < 100; $i++){
$nums[] = rand(0,1000);
}
$sum = 0;
foreach ($nums as $num){
$sum += $num;
}
$avg = $sum / count($nums);
unset($sum);
var_dump($avg);
unset($avg);
$first = 1;
foreach ($nums as $num){
if ($first){
$avg = $num;
$first = 0;
} else {
$avg = ( $avg + $num ) / 2 ;
}
}
var_dump($avg);
Hozzászólások
Amit te keresel, az a futóátlag.
Van vele probléma a lebegőpontos számítás korlátai miatt.
De az a lényege, hogy:
- tárolod, hogy hány mért érteket láttál eddig
- mi ezeknek az összege
Amikor bejön egy új érték, akkor a countert megnöveled, és az összeget is. Az átlag természetesen összeg / mért értékek száma.
Hülye voltam, ez is elég elegáns megoldás, összeget és darabszámot tárolni. Egyébként addig eljutottam, hogy valószínűleg kerekítési hibák lehetnek, a lebegőpontosság miatt, kb. mire leírtad lett egy gyanum, nem hiszem, hogy feloldható lesz általam :). De amit írsz megoldást tökéletesnek tűnik, kicsit memória igényesebb a szumma miatt, de egye fene.
Ha nem válaszolnék kommentben, hát küldj privátot!
Nem. Amit te írsz, az a futóátlag. Amit ő keres, azt mozgóátlagnak hívják tudtommal, bár lehet nem emlékszek rá pontosan, vagy nem ez a magyar neve. Természetesen a futóátlag jobb megoldás, pontosabb átlagot ad. De mindkettő elég egyszerűen kivitelezhető.
“A computer is like air conditioning – it becomes useless when you open Windows.” (Linus Torvalds)
Nincs olyan, hogy egyik megoldás jobb a másiknál. Másra valók. Más a mögöttük lévő modell.
Látom, te is megütköztél rajta. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
Hűha, már az átlagokban sem lehet megbízni? Mi az, hogy pontosabbat ad? Van, ami becsül, van, ami meg számol?
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
Szerintem nem elég az átlagot letárolni, kell az is, hogy eddig hány inputod volt. Ha mondjuk 1000 érték átlaga 5, és a következő input 10, akkor nem igaz, hogy az új átlag 7,5.
Most így hirtelen, ha van n számod, aminek az átlaga k, akkor a következő x input után az új átlag = (n*k+x)/(n+1)
Kicsit hülyén fogalmazva, a példádban az 5 mint átlag nagyobb súlyú kéne legyen, mint a 10? Kipróbálom a képleted, köszi!
Ha nem válaszolnék kommentben, hát küldj privátot!
például, igénytelenül excelben :)
Nagyon is
Az osszeget es a darabszamot nyilvantartod. Ha uj szam jon, az osszeget noveled vele, a darabszamot inkrementalod, es az uj atlag a ketto hanyadosa (osszeg/darabszam). Arra persze figyelni kell, hogy az osszeget eleg nagy szamkent abrazoljuk.
Amugy ha ilyesmi feladat van, altalaban ablakos csuszoatlag kell nekem, es egy sima alulatereszto szurovel szoktam megoldani. Az uj ertek az elozo ertek es az uj szam valamilyen sulyozott szamtani kozepe. (pl. potmetert teker a felhasznalo, de zajos a jel) Igy eleg az aktualis erteket szamontartani.
A strange game. The only winning move is not to play. How about a nice game of chess?
Látom ez már hasonló gondolatmenet szülötte mint ami nekem kell, nálam is hardware korlátok miatt merült fel a kérdés, köszi, megnézem részleteiben.
Ha nem válaszolnék kommentben, hát küldj privátot!
moving average?
Az lesz, fentebb már megkaptam magyarul :).
Ha nem válaszolnék kommentben, hát küldj privátot!
jaja, ha nezed, akkor kb ugyanabban a percben irtunk :D
Annyi hogy egy meeting miatt kicsit kesobb nyomtam ra a submit-ra :D
Sose bánd, mivel angolul elsőre running average-et kerestem volna, így hogy megírtad már tudok érdemben utánaolvasósdit játszani.
Ha nem válaszolnék kommentben, hát küldj privátot!
A mozgóátlag meg a futóátlag nem ugyanaz, erre figyeljünk oda!
A mozgóátlag esetén az átlag alapjául szolgáló sokaság folyamatosan változik úgy, hogy kerülnek belüle ki is elemek.
A futóátlag pedig egy minimalizált memóriahasználatú átlagszámítás a teljes addig megfigyelt sokaságra.
Az átlag tulajdonképpen összeg. Csak le van normálva a minták számával.
Én úgy szoktam, hogy összegzem az eddigi adatokat és az adatok számát (sum és n), és amikor épp kell az átlag, elosztom.
Túlcsordulás az egyetlen ellenséged, de ma, a sokbites korban nekem ez a viszonylag kicsi számokkal nem akkora gond.
Túlcsordulás ellen ott van gelei képlete.
Ha a szumma túlcsodulna, akkor a szorzat is abból a képletből, nem?
Lehet úgyis gondolkodni, hogy:
(old_avg*n + value)/(n+1) = old_avg + (value - old_avg)/(n+1)
ps.: remélem nem basztam el :)
Na ezt tuti lopom :D amilyen egyszerű, olyan nagyszerű. Szerintem nem lett elkeferintve.
Egy próbát rátoltam és szerintem sem. Szavakkal: az átlagtól az átlagos eltéréssel eltolja az átlagot. ;)
Nyilván az is túlcsordul (hiszen újra kiszámolja az összeget), tehát apró javítással:
Ja de én direkt az összeget tárolom, mert így nem szenvedek mindig kerekítési pontatlanságot.
Nem annyi és nem olyan nagy számot szoktam átlagolni, hogy a túlcsordulás veszélye fennálljon.
Valamint az átlagra nem is minden minta után van szükségem. Így egy csomó számolást megspórolok. Nincs szorzás és osztás, csak összeadás egy normál mintaérkezéskor.
Ha bármikor is felmerül a túlcsordulás lehetősége, akkor arra ott a bigdecimal-szerű típus szinte minden platformon.
https://iotguru.cloud
Látom, már mindenki mindent leírt, de ha valamiféle aluláteresztő szűrés a cél, ahol a régebbi értékek súlya azoktól távolodva exponenciálisan csökken, s a legfrissebb értékek súlya relatív nagyobb, akkor semmiképp sem feledkeznék meg az exponenciális átlagolásról. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
A mozgóablakos átlagolás is aluláteresztő szűrés.
Egyébként jól mondod, helye van itt megemlíteni az exponenciális átlagolást is.
Fel kell hívni a figyelmet viszont arra, hogy a mozgó ablakos és a kumulálódó átlagolások között különbség van, nem ugyanarra jók.
A kumulálódónál a modell konstans várható értéket feltételez, azaz DC jelet (nyilván zajjal terhelve).
A mozgó ablakos átlagolásoknál pedig egy ,,lassan változó", zajjal terhelt jelet feltételez a modell.
Hát ja, meg amire futásidőd van. Mert ha ömlik be DMA-n az A/D konverterről a mintavételezett adat, s röptében kell ezzel valamit kezdeni, akkor az exponenciális átlagolás törésponti frekvenciája is abból adódik ki, ami nagyjából épp megfelel, és össze tudod rakni egy shiftelésből, összeadásból, meg egy 3-mal való osztásból az egészet. Tapasztalat. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
Persze. Az exponenciálist is nyilván ablakozod. Mikrokontrollerben én is ad-hoc módon valósítom meg ezeket, ahogyan kiadja. Célnak általában megfelel; a szellemiség a lényeg. Ööö akarom mondani a jelmodell.
Vannak speciális esetek, amikor jön az adat, de nem mindig van szükséged az átlagra, csak egyszer-egyszer. Azt is megoldom sima összegzéssel és mintaszámolással, hogy ne kelljen gyakran szorozni-osztani.
Adott n értékenként pedig le lehet kumulálni, amit utána egy súllyal veszek figyelembe (általában az addigi n, vagy ha feledtetni akarom a múltat, akkor <n).
Most veszem észre, mit írtál, és egy pillanatig még el is hittem neked! :) Az exponenciális szűrő sima egytárolós tag, tehát a Laplace-transzformáltja valami 1/(1 + sT), ha jól gondolom. Szóval leköveti az a lassú változásokat törésponti frekvenci alatt. A gyorsakra meg csillapít -20 dB/dekáddal töréspont fölött.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
Bocsáss meg, pontatlan voltam. A kumulálódó alatt a sima kezdetektől való átlagolást értettem.
Tudom, hogy elvileg az exponenciális is kumulálódó (szigorú értelemben), de pont a csökkenő súly miatt azt én már ablakosnak tekintettem.
Akkor egyetértünk. Ebben van a nagyszerűsége. Nem kell ablakozni, a múlt exponenciálisan, aszimptotikusan enyészik nullává. Ráadásul a számábrázolás miatt idővel - na jó, mintával - tényleg teljesen el fog tűnni a múlt.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
Így van. Ezért is gondolok rá, mint ablakozó átlagolásra - mégha literally ez nem is helytálló.
Most látom, az, amit itt php-ban írtál, az épp exponenciális átlagolás. Lehet azért ezt egy picikét lassítani is, pl:
$avg = ( 2 * $avg + $num ) / 3 ;
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE