Einen gleitenden Durchschnitt mit MongoDB berechnen
Bei der Arbeit mit einer Vielzahl an Messwerten kommt man oft in die Situation, dass man in der großen Datenmenge die wesentlichen Entwicklungen nicht mehr erkennen kann - man sieht praktisch den Wald vor lauter Bäumen nicht mehr. Hierbei hilft es, wenn man sich nicht zu sehr auf die Einzelwerte fokussiert, sondern stattdessen den gleitenden Durchschnitt (moving average) über einen Zeitraum betrachtet. Dies glättet die Kurve, so dass sprunghafte Änderungen weniger relevant werden und der allgemeine Trend in den Vordergrund rückt:
Beispieldaten
In unserem Beispiel stützen wir uns auf einfache Daten, die folgende Struktur haben:
{
"_id": ObjectId("63ca9e13f0a91511db9cc25c"),
"ts": ISODate("2022-12-01T00:00:00Z"),
"value": 113
}
Wesentlich ist in diesem Fall vor allem der Timestamp und der Wert zu dieser Zeit. Insgesamt haben wir folgende Daten in unserer Collection (der gleitende Durchschnitt ist das berechnete Ergebnis):
Datum | Wert | Gleitender Durchschnitt |
---|---|---|
01.12.2022 | 113,00 | 113,00 |
02.12.2022 | 129,00 | 121,00 |
03.12.2022 | 102,00 | 114,67 |
04.12.2022 | 191,00 | 140,67 |
05.12.2022 | 111,00 | 134,67 |
06.12.2022 | 155,00 | 152,33 |
07.12.2022 | 196,00 | 154,00 |
08.12.2022 | 115,00 | 155,33 |
09.12.2022 | 155,00 | 155,33 |
10.12.2022 | 149,00 | 139,67 |
11.12.2022 | 164,00 | 156,00 |
12.12.2022 | 165,00 | 159,33 |
13.12.2022 | 163,00 | 164,00 |
14.12.2022 | 144,00 | 157,33 |
Einen gleitenden Durchschnitt mit $setWindowFields berechnen
Zum Berechnen des gleitenden Durchschnitts erstellen wir eine Aggregation-Pipeline, deren zentrale Stage $setWindowFields
darstellt, die seit MongoBD 5.0 verfügbar ist. Diese Stage führt Berechnungen auf Datenbereichen in der Collection aus und fügt das Ergebnis als neue Felder an das Dokument an:
[{
$setWindowFields: {
partitionBy: null,
sortBy: {
ts: 1
},
output: {
avg: {
$avg: '$value',
window: {
range: [
-2,
0
],
unit: 'day'
}
}
}
}
}]
Folgendes ist bei obigem Beispiel zu beachten:
- Die Angabe von
partitionBy
ermöglicht es, die Datenbereiche in Partitionen aufzugliedern. So kann beispielsweise für jeden Sensor der gleitende Durchschnitt gesondert berechnet werden. In unseren Beispieldaten ist dies jedoch nicht relevant, so dass wir übernull
signalisieren, dass keine Partitionen gebildet werden müssen. - Das Window wird anhand des Datumsbereichs gebildet, da wir
range
verwendet haben. Dies wird als time range window bezeichnet. Über die Unitday
geben wir an, dass die Grenzen für den Bereich anhand der Tage gebildet werden. Der Range[-2, 0]
gibt also an, dass wir die Daten der letzten beiden und des aktuellen Tages im Fenster einschließen wollen. Die Grenzen sind hier also inklusive. - Durch die Verwendung der window function
$avg
bilden wir den Durchschnitt über die Werte und legen ihn im Feldavg
ab. - Bei der Verwendung eines time range windows ist es notwendig, ein
sortBy
anzugeben, das ausschließlich aus Datumswerten besteht. Deshalb wird in unserem Fall nach demts
-Feld sortiert.
Dies führt zu folgender Dokumentenstruktur nach der Stage:
{
"_id": ObjectId("63ca9e13f0a91511db9cc269"),
"ts": ISODate("1670976000000"),
"value": 144,
"avg": 157.33333333333334
}
Anschließend können die Dokumente weiter angepasst werden; außerdem können in der $setWindowFields
-Stage auch mehrere Felder mit unterschiedlichen Fenstern berechnet werden. Durch eine abschließende $merge
-Stage können die Daten in einer Collection abgelegt werden, so dass sie zukünftig ohne Berechnung verfügbar sind.
Fazit
Ein gleitender Durchschnitt hilft dabei, Trends und Entwicklungen in Daten erkennen zu können. Die mächtige Stage $setWindowFields
erlaubt die Berechnung von Felder für einen bestimmten Datenausschnitt, so dass es mit MongoDB auf einfache Weise möglich ist, einen gleitenden Durchschnitt zu berechnen.
Geschäftsführer
- Einen gleitenden Durchschnitt mit MongoDB berechnen
- Lücken füllen mit $densify und $fill
- Materialized Views mit $out und $merge
- Deltas berechnen mit $setWindowFields
- Gesamtwerte und prozentuale Anteile ermitteln
- Wer hat gewonnen? Ranking in der Aggregation Pipeline