Übersicht
In diesem Abschnitt wird beschrieben, wie Sie Ihre Abfragen zur Anomalieerkennung ordnungsgemäß konfigurieren. Im Allgemeinen müssen Sie vier verschiedene Parametertypen abstimmen:
- Datenauswahlparameter, die angeben, welche Daten in unsere Analyse aufgenommen werden. Beispiele:
QueryDataSetRequest.dimensionNames
,QueryDataSetRequest.pinnedDimensions
undQueryDataSetRequest.testedInterval
. - Zusammenfassungsparameter, die angeben, wie mehrere Ereignisse gruppiert werden, um einen Wert zu generieren, der verwendet wird, um Slices zu vergleichen. Beispiele:
ForecastParams.aggregatedDimension
. - Prognoseparameter, die zum Konfigurieren der für die Berechnung der erwarteten Werte verwendeten Prognosealgorithmen verwendet werden. Beispiele:
ForecastParams.holdout
,ForecastParams.forecastHistory
undForecastParams.minDensity
. - Sensibilisierung von Parametern, die bei Änderung die Anzahl der gemeldeten Anomalien, die Latenz und die Rechenressourcen erhöhen oder verringern können. Beispiele:
ForecastParams.maxPositiveRelativeChange
,ForecastParams.maxNegativeRelativeChange
undForecastParams.forecastExtraWeight
.
Vorbereitung
Folgen Sie der Einrichtungsanleitung in unserer Kurzanleitung, damit Sie alle Befehle in dieser Anleitung ausführen können.
Wir zeigen Ihnen, wie sich jeder Parameter auf die zurückgegebenen Ergebnisse auswirkt. Dazu fragen Sie das öffentliche Demo-Dataset ab, das bereits mit Daten aus dem GDELT-Projekt vorab geladen wurde.
Speichern Sie die folgende Abfrage als query.json
in Ihrem Arbeitsverzeichnis:
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 1.0,
maxNegativeRelativeChange: 1.0,
forecastExtraWeight: 200.0
}
}
Wie in der Kurzanleitung beschrieben, können Sie eine Abfrage mit dem folgenden Befehl ausführen:
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query
In diesem Leitfaden ändern wir die verschiedenen Parameter in query.json
, um zu zeigen, wie sich die Ausgabe auf die Ausgabe auswirkt. Sie können die Datei bearbeiten und mithilfe des obigen gcurl
-Befehls die Abfragen bearbeiten und die Abfragen abrufen. Diese werden in der Kurzanleitung als Offensive entfernt.
Datenauswahl
Eine Abfrage zur Anomalieerkennung prüft, ob in einem bestimmten Datensatz Anomalien innerhalb eines bestimmten Zeitintervalls sind. Dabei werden die Daten in einigen Dimensionen unterteilt und optional einige Werte für einige Dimensionen gefiltert. In diesem Abschnitt wird beschrieben, wie Sie diese Schritte zur Datenauswahl steuern.
Zeitintervall-Spezifikation
Mit QueryDataSetRequest.tested_interval
können Sie festlegen, welches Zeitintervall auf Anomalien geprüft werden soll. In query.json
geben wir an, dass wir Anomalien erkennen möchten, die am Tag des 15. April 2019 aufgetreten sind:
...
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
...
Wenn wir beispielsweise Anomalien feststellen möchten, die am 15. April 2019 zwischen 13 Uhr und 14:00 Uhr aufgetreten sind, legen wir stattdessen testedInterval
auf:
...
testedInterval: {
startTime: "2019-04-15T13:00:00Z",
length: "3600s"
},
...
TIPP: Spielen Sie mit dem Wert testedInterval
, indem Sie unterschiedliche Startzeiten und unterschiedliche Längen festlegen und herausfinden, wie die zurückgegebenen Anomalien variieren.
Datenschnitt
Bei der Erkennung von Anomalien innerhalb eines bestimmten Zeitintervalls müssen wir auch angeben, wie die Ereignisse in Datensegmente gruppiert werden. Setzen Sie dazu dimensionNames
auf die Dimensionen, die Sie im Dataset aufteilen möchten.
In query.json
werden die Daten nur nach der Dimension "EntityLOCATION" unterteilt: dimensionNames: ["EntityLOCATION"]
. Sie sehen, dass alle Segmente in der Ergebnisliste einfach unterschiedliche Werte für die Dimension "EntityLocation" sind.
Wenn wir die Daten stattdessen über mehrere Dimensionen aufteilen möchten, können wir mehrere Dimensionsnamen angeben:
{
dimensionNames: ["EntityLOCATION", "EntityORGANIZATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 1.0,
maxNegativeRelativeChange: 1.0,
forecastExtraWeight: 50.0
}
}
Beim Ausführen dieser Abfrage stellen wir fest, dass die resultierenden Segmente Werte über die beiden angegebenen Dimensionen "EntityLOCATION" und "EntityORGANIZATION" übernehmen. (Es wird nur das erste Anomaliesegment angezeigt, das zurückgegeben wird):
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query
{
"name": "projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104",
"anomalyDetectionResult": {
"anomalies": [
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Seine"
},
{
"name": "EntityORGANIZATION",
"stringVal": "AP"
}
],
"result": {
"holdoutErrors": {},
"trainingErrors": {},
"forecastStats": {
"numAnomalies": 1
},
"testedIntervalActual": 344
},
"status": {}
},
...
Filtern
Wenn Sie nur eine Teilmenge des Datasets analysieren möchten, können Sie nur nach Ereignissen filtern, die bestimmte Werte für bestimmte Dimensionen enthalten, indem Sie pinnedDimensions
festlegen.
Beispiel für das Filtern nach EntityORGANIZATION
und das Segmentieren nach EntityLOCATION
(nur das erste Ergebnis anzeigen):
$ cat query.json
{
dimensionNames: ["EntityLOCATION"],
pinnedDimensions: [
{
name: "EntityORGANIZATION",
stringVal: "AP"
}
],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 1.0,
maxNegativeRelativeChange: 1.0,
forecastExtraWeight: 250.0
}
}
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query
{
"name": "projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104",
"anomalyDetectionResult": {
"anomalies": [
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Seine"
}
],
"result": {
"holdoutErrors": {},
"trainingErrors": {},
"forecastStats": {
"numAnomalies": 1
},
"testedIntervalActual": 344
},
"status": {}
},
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Ile de la Cite"
}
],
"result": {
"holdoutErrors": {},
"trainingErrors": {},
"forecastStats": {
"numAnomalies": 1
},
"testedIntervalActual": 282
},
"status": {}
},
...
Aggregation
Die Standardaggregationsmethode zählt die Anzahl der Ereignisse im Segment.
Sie können auch angeben, dass Ereignisse aggregiert werden sollen, indem Sie eine numerische Dimension summieren. Das wird dadurch angegeben, dass für ForecastParams.aggregatedDimension
die numerische Dimension festgelegt wird, die Sie summieren möchten.
Prognosekonfiguration
Zur Berechnung des erwarteten Werts während des getesteten Zeitintervalls verwenden wir Prognosealgorithmen, die anhand der historischen Werte für das Segment vorhersagen, welchen Wert der Wert für das Testintervall haben sollte.
HINWEIS: Die Werte für ein Segment sind durch die Aggregationsmethode angegeben.
Prognoseverlauf
Die Menge der in unserer Zeitachse enthaltenen Daten wird durch den Parameter ForecastParams.forecastHistory
angegeben.
Im ersten Beispiel gilt:
- Wir haben
forecastHistory: "2592000s"
festgelegt, um anzugeben, dass Ereignisse zwischen dem 16. März 2019 und dem 15. April 2019 (30 Tage, 259.000 Sekunden) abgerufen werden sollen und eine Zeitachse zwischen diesen beiden Tagen erstellt wird. - Jeder Datenpunkt in der Zeitachse deckt einen Zeitraum ab, der der Länge des getesteten Intervalls entspricht (in unserem Beispiel
86400s
– 1 Tag). - Die Zeitachse hat 30 Punkte und jeder Punkt enthält den aggregierten Wert für die Ereignisse an diesem Kalendertag. Wenn wir als Aggregationsmethode zählen, hat der erste Zeitachsenwert den Wert der Gesamtzahl der Ereignisse am 16. März 2019, den zweiten vom 17. März 2019 usw.
Sie können die Verlaufswerte für Zeitachsen aufrufen, die im Feld ForecastResult.history
zurückgegeben werden. Sie wird nur zurückgegeben, wenn in der Anfrage QueryDataSetRequest.returnTimeseries
auf true
festgelegt ist.
HINWEIS: Wir erstellen eine Zeitachse im Timeseries
-Proto-Objekt als eine Sammlung von Punkten (definiert als TimeseriesPoint
), die nach Zeit sortiert sind und einen Wert (TimeseriesPoint.value
) der aggregierte Wert für das Segment während des Zeitintervalls [TimeseriesPoint.time
, TimeseriesPoint.time + testedInterval.length
].
Wenn Sie ForecastParams.forecastHistory
erhöhen und einen längeren Verlauf aufnehmen, können Sie bestimmte saisonale Muster erfassen und möglicherweise die Genauigkeit der Prognose erhöhen, da sie mehr Daten enthält. Beispiel: Wenn monatliche Muster für die Saisonabhängigkeit von forecastHistory
auf 30 Tage festgelegt sind, können diese Muster nicht erfasst werden. In diesem Fall sollten wir den forecastHistory
. Wir haben also mehrere monatliche Muster in unseren analysierten Zeitachsen (z. B. wenn monatliche Muster von 100 bis 300 Tagen erkannt werden sollten), hängt aber auch von den tatsächlichen Mustern ab.
Ausgehend vom ersten Beispiel sollten Sie testedInterval.length
auf 3600s
(1 Stunde) reduzieren und ForecastParams.forecastHistory
auf 8640000s
(100 Tage) erhöhen. Hierdurch wird die Anzahl der Punkte in der Zeitachse history
auf 2.400 erhöht, sodass der Vorgang präziser ist und ein längerer Zeitraum abgedeckt wird.
Holdout/Testintervall
Zur Bewertung der Qualität unserer Vorhersage trainieren wir nur die ersten X% der Zeitachse. Der letzte Teil der Zeitachse wird zu Bewertungszwecken gespeichert und vom Parameter ForecastParams.holdout
gesteuert.
Der Parameter ForecastParams.holdout
steht für einen Prozentsatz im Bereich von 0 bis 100 und gibt an, wie viele Daten für Testzwecke aufbewahrt werden sollen. In unserem Beispiel haben wir holdout: 10.0
angegeben. Die letzten 10% der Zeitachse werden also beibehalten, um zu beurteilen, wie gut die Vorhersage basierend auf den ersten 90% funktioniert.
Wenn wir in unserem ersten Beispiel 30 Zeitachsenpunkte haben, bedeutet dies, dass die ersten 27 Punkte für das Training und die letzten 3 Punkte für das Testen/Auswerten des Modells erhalten bleiben.
Die Fehler, die wir während des Hold-Zeitraums messen, werden in ForecastResult.holdoutErrors
zurückgegeben. Diese Fehler werden zur Berechnung der unteren und oberen Grenzen (testedIntervalForecastLowerBound
und testedIntervalForecastUpperBound
) verwendet. Höhere Holdout-Fehler führen zu einer stärkeren Prognosebindung und bei niedrigeren Fehlern liegen uns engere Grenzen vor (und gegen ForecastResult.testedIntervalForecast
).
Der Holdout-Wert sollte sich in den niedrigen Prozentpunkten (3 bis 10 %) befinden. Er sollte jedoch genügend Datenpunkte enthalten, da diese Fehler für die Berechnung der Prognosegrenzen erforderlich sind.
Minimale Dichte
Die Mindestdichte, die durch den Parameter ForecastParams.minDensity
angegeben wird, gibt an, wie viele nicht leere Zeitachsen mit einer Zeitachse vorhanden sein müssen, um als potenzielle Anomalie betrachtet zu werden.
Ähnlich wie beim Holdout handelt es sich um einen Prozentwert im Bereich von 0 bis 100.
Die Anzahl der Punkte wird mit der Anzahl der erwarteten Punkte zwischen testedInterval.startTime - forecastHistory
und testedInterlal.startTime
verglichen.
Beispiel: Wenn wir 30 erwartete Zeitachsenpunkte haben (wie im ersten Beispiel, in dem testedInterval.length
auf 1 Tag und forecastHistory
auf 30 Tage festgelegt wird) und legen wir minDensity
fest. 80 an, dann akzeptieren wir nur Zeitachsen, die 24 Punkte und mindestens ein Ereignis enthalten.
HINWEIS: In unserem Beispiel wurde minDensity
auf 0 gesetzt. Wir empfehlen, beim Erkennen von Spitzen auch auf 0 gesetzt zu werden.
Horizont
Der durch ForecastParams.horizonTime
angegebene Zeithorizont gibt einfach an, wie viel in die Zukunft vom Testintervall aus vorhergesagt werden soll, um die Werte basierend auf der historischen Zeitachse vorherzusagen.
Wenn QueryDataSetRequest.returnTimeseries
auf "true" gesetzt wird, werden die prognostizierten Zeitachsen für jedes Segment in ForecastResult.forecast
zurückgegeben und enthält die vorhergesagten Werte zwischen testedInterval.startTime +
testedInterval.length
und testedInterval.startTime + testedInterval.length +
horizonTime
.
Empfindlichkeit
Basierend auf den prognostizierten Grenzen und dem tatsächlichen Wert während des getesteten Intervalls für ein Segment werden wir es möglicherweise als Anomalie basierend auf den Empfindlichkeitsparameter klassifizieren. Diese Parameter sind:
ForecastParameters.maxPositiveRelativeChange
gibt an, wie viel der tatsächliche Wert im Vergleich zutestedIntervalForecastUpperBound
erhöht werden kann.ForecastParameters.maxNegativeRelativeChange
gibt an, wie stark der tatsächliche Wert im Vergleich zutestedIntervalForecastLowerBound
verringert werden kann.ForecastParameters.forecastExtraWeight
wird als zusätzliche Gewichtung beim Vergleich der tatsächlichen und der Prognosegrenzen verwendet. Ein höheres Gewicht kann hilfreich sein, wenn kleinere kleinere Varianzen ignoriert werden sollen.
HINWEIS Wir haben verschiedene Parameter für positive und negative Änderungen, weil wir unseren Kunden die Möglichkeit geben möchten, unterschiedliche Schwellenwerte für Lastspitzen und -senkungen festzulegen oder eine der anderen zu deaktivieren, indem sie sehr hohe Höchstwerte festlegen.
HINWEIS: Der maximale praktische Wert für maxNegativeRelativeChange
beträgt 1,0 für eine positive Zeitachse (z. B. wenn die Anzahl der Ereignisse als Aggregationsmethode gezählt wird), da ein Wert nicht mehr als 100% des tatsächlichen Werts
Als Basis versuchen Sie, alle diese Empfindlichkeitsparameter auf 0 zu setzen:
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 0.0,
maxNegativeRelativeChange: 0.0,
forecastExtraWeight: 0.0
}
}
Dies ist die sensibelste Abfrage, die wir ausführen können, und markiert alle Anomalien, die testedIntervalActual
außerhalb der Grenzen [testedIntervalForecastLowerBound
, testedIntervalForecastUpperBound
] haben.
Dies mag auf den ersten Blick scheinen, was wir wollen (und in einigen Anwendungen nützlich sein könnten), doch werden wir die meisten Anomalien ignorieren, da dies zu falsch positiven Ergebnissen führt.
Die Ausführung dieser Baseline führt zu ca. 2.500 Anomalien.
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query \
| grep "testedIntervalActual" | wc -l
2520
Wenn wir sowohl maxPositiveRelativeChange
als auch maxNegativeRelativeChange
auf 1,0 erhöhen, stellen wir fest, dass die Anzahl der Anomalien auf etwa 1.800 reduziert wird. Dies ist jedoch nicht für Segmente mit kleineren Abweichungen vorgesehen, aber dennoch eine große Anzahl von Segmenten klassifiziert ist, die als Anomalien eingestuft werden.
Wenn wir nur an den größten Spitzen in den Nachrichten an diesem Tag interessiert sind, könnten wir auch forecastExtraWeight
erhöhen. Dadurch werden Ereignisse mit geringem Volumen herausgefiltert. Legen wir dafür den Wert 200.0 fest, das den endgültigen query.json
erhält.
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 1.0,
maxNegativeRelativeChange: 1.0,
forecastExtraWeight: 200.0
}
}
Bei der Ausführung der vorherigen Abfrage werden nur drei Anomalien zurückgegeben, die alle mit dem Feuer von Noter Dame verknüpft sind. Dies war das am häufigsten genannte Ereignis in den Nachrichten am 15. April 2019:
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query \
| grep stringVal
"stringVal": "Ile de la Cite"
"stringVal": "Notre Dame"
"stringVal": "Seine"
Abfrageleistung und Ressourcennutzung
Neben der Reduzierung der Geräusche und dem Herausfiltern von weniger relevanten Segmenten kann die Reduzierung der Empfindlichkeit bei der Anomalieerkennung auch die Abfragelatenz und die Ressourcennutzung erheblich reduzieren.
Eine Erhöhung der forecastExtraWeight
führt in der Regel zu einer spürbaren Reduzierung der anormalen Slice-Ereignisse. Dieser Parameter ist außerdem der wichtigste Empfindlichkeitsparameter, der erhöht werden sollte, um die Abfrageleistung zu verbessern.
Sie können mit verschiedenen Empfindlichkeitsparametern experimentieren, um zu sehen, wie sie sich auf die Leistung der Abfrage auswirken. Beispiel:
$ cat query.json
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 0.0,
maxNegativeRelativeChange: 0.0,
forecastExtraWeight: 0.0
}
}
$ time gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query \
| grep stringVal | wc -l
2580
real 0m26.765s
user 0m0.618s
sys 0m0.132s
Wir stellen fest, dass die stärksten Parameter dazu führen, dass unsere Abfrage ~26.7s dauert. Durch die Reduzierung der Empfindlichkeit erhöht sich der Geschwindigkeitswert um bis zu 3,4 Sekunden:
$ cat query.json
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
forecastHistory: "2592000s",
holdout: 10.0,
minDensity: 0.0,
maxPositiveRelativeChange: 1.0,
maxNegativeRelativeChange: 1.0,
forecastExtraWeight: 200.0
}
}
$ time gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/timeseries-insights-api-demo/datasets/webnlp-201901-202104:query \
| grep stringVal | wc -l
3
real 0m3.412s
user 0m0.681s
sys 0m0.047s
Nächste Schritte
- Timelines Insights API – Konzepte
- Weitere Informationen zur REST API