knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(dplyr) library(rktiq) set.seed(0) # Signal-Dataframe für Plots vorbereiten x <- tibble::tibble(time = seq(lubridate::dmy_hm("01.03.16 00:00"), lubridate::dmy_hm("08.03.16 00:00"), by = "1 hour"), `011PE_BB35` = seq(1, -1, length.out = 24) %>% rep(7) %>% c(1), `011PE_BB05` = sin(1:169), `011PE_BB15` = rbinom(169, 1, prob = .2)) %>% as_tiqqle("wide") %>% as_long() %>% sample_n(300) %>% arrange(time)
Das vorliegende rktiq-Package ist eine Sammlung von Funktionen, mit denen Sensorsignale für maschinelles Lernen vorbereitet werden können. Aus Rohsignalen werden in einer Reihe von Verarbeitungsschritten Trainingsdaten erzeugt, mit deren Hilfe anchließend Klassifikations- und Regressionsmodelle trainiert werden. Mit diesen Modellen können bestimmte Ereignisse prognostiziert werden (z.B. Störungen). Neben den hierfür notwendigen Funktionen zum Datenimport, zur Datenvorbereitung und Merkmalsextraktion beinhaltet das Package ebenso Plotfunktionen zur Exploration der Daten.
Die hier zusammengefassten Funktionen haben sich in verschiedenen Projekten als nützlich erwiesen. Basierend auf den gesammelten Erfahrungen wurden die Funktionen durch Verallgemeinern und Modularisieren so gestaltet, dass sie auch auf andere Projekte und deren spezifische Signaltypen angewendet werden können. Aufgrund der Entstehungsgeschichte liegt der Anwendungsschwerpunkt allerdings im Bereich Predictive Maintenance*.
Um den Einstieg in die Verwendung des Packages zu erleichtern, soll in dieser Vignette ein kurzer Überblick über die einzelnen Funktionen und ihr Zusammenspiel gegeben werden. Implementierungsdetails sind in den entsprechenden Hilfeseite dokumentiert bzw. können anhand des (dokumentierten) Quellcodes nachvollzogen werden.
Damit bei zukünftigen Analysen die passenden Funktionen leicht gefunden und zugeordnet werden können, wurde ein möglichst systematisches und selbsterklärendes Namensschema im Package verwendet. So fangen bspw. alle Plotfunktionen mit plot_*, alle Ereignisfunktionen mit event_* und alle Fensterfunktionen mit window_* an.
Das Package binden wir durch folgenden Befehl in die aktuelle R-Session ein:
library(rktiq)
Beim Einlesen der Signale wird davon ausgegangen, dass die Rohdaten bereits sauber aus den ursprünglichen Datenquellen eingelesen und geeignet zusammengefasst wurden. Spezielle Ingest-Funktionen für diesen Zweck sind im Package nicht enthalten. Dies hat den Grund, dass in Analyseprojekten in der Regel die verwendeten Speichersysteme, Formate und Verzeichnisstrukturen sehr individuell sind. Eine allgemeingültige Ingest-Prozedur zu definieren, die allgemein genug ist, um die Vielzahl dieser Fälle abzubilden, und trotzdem einfach zu verwenden ist, ist ein eher unrealistisches Vorhaben. Von daher muss dieser Part projektspezifisch selbst implementiert werden.
Um vom rktiq-Package gelesen werden zu können, müssen die vorbereiteten
Signalrohdaten in einem Dataframe zusammengefasst sein, welcher ein langes
Format aufweist. Dieses Format zeichnet sich dadurch aus, dass mindestens eine
Spalte mit Zeitinformationen (d.h. Zeitstempel der Messung), mindestens eine
Spalte mit Signal-ID (d.h. Name des gemessenen Sensors) sowie mindestens eine
Spalte mit Signalwert (d.h. numerischer Messwert) vorhanden ist. Bei Vorliegen
dieser Datenstruktur könnenn wir die Signaldaten mittels der
harmonize()
-Funktion in das interne Standardformat überführen. Dieses als
Tiqqle bezeichnete Format ist im Grunde ein standardisierter Dataframe
(bzw. Tibble) mit zusätzlichen Attributen, die die interne Verarbeitung der
Daten erleichtern.
Nach dem Import der Daten können verschiedene Transformationen mit ihnen durchgeführt werden, um sie aufzuräumen und für die nachfolgende Exploration und Merkmalsberechnung vorzubereiten.
Ein erster Schritt hierbei kann das Schneiden der Signale sein. Dabei werden die
vorhandenen Daten zeitbasiert gefiltert und somit in kleinere Signalabschnitte
unterteilt. Dafür können wir den Start- und Endzeitpunkt des auszuschneidenden
Abschnitts an die Funktion crop()
übergeben:
crop(x, start = lubridate::dmy_hm("01.03.16 00:00"), end = lubridate::dmy_hm("08.03.16 00:00"))
Der resultierende Dataframe beinhaltet dann den Signalausschnitt, der zwischen den beiden angegebenen Zeitpunkten liegt. Mithilfe von weiteren Argumenten können wir das zusätzliche Auffüllen von Messpunkten am Anfang und Ende des Abschnitts steuern. Durch Übergabe von Zeitstempel-Vektoren werden mehrere Abschnitte gleichzeitig ausgeschnitten.
Gemessene Signalwerte beinhalten unter Umständen redundante Informationen. Dies
können bspw. sich wiederholende Messwerte sein, bei denen bei
aufeinanderfolgenden Messzeitpunkten keine Veränderung des Sensorwerts
aufgetreten ist. In diesem Fall würde es ausreichen, einen Messwert nur dann zu
speichern, wenn er sich tatsächlich vom vorherigen unterscheidet. Ein Messwert
wird hierbei solange implizit als unverändert angenommen, bis eine explizite
Wertänderung verzeichnet ist (Last observation carried forward). Um ein Signal
derart zu reduzieren, dass nur relevante Änderungen des Signalwerts beibehalten
werden, verwenden wir die Funktion condense()
.
Ein Extremfall von redundanten Informationen sind Signale, für die im gesamten
Zeitraum nur ein einziger Messwert registriert wurde. Diese Signale sind für die
Merkmalsextraktion höchstwahrscheinlich irrelevant und sollte daher nicht weiter
betrachtet werden. Konstante Signale werden mit der Funktion
remove_constant()
vollständig aus dem Dataframe entfernt.
Zur besseren Verarbeitbarkeit und Vergleichbarkeit der Signale können wir neben
der Entfernung von redundanten Messwerten weitere Transformationen mit ihnen
durchführen. Die erste Transformation mittels der Funktion limit()
ermöglicht die Bereinigung eines Signals um einen bestimmten Offset-Wert:
limit(x, which = "011PE_BB35", value_before = 57)
Hierbei wird standardmäßig von allen ursprünglichen Messwerten eines Signals ein konstanter numerischer Wert abgezogen. Mit den zusätzlichen Argumenten when, value_before und value_after wird ein einmaliger Wechsel des Offset-Werts im Zeitraum ermöglicht. Dies kann bspw. bei der Detektion von Unter-/Überschreitungen von Schwellwerten für ein Signal hilfreich sein.
Um verschiedene Wertebereiche von Signalmesswerten innerhalb eines Dataframes zu
vereinheitlichen, können wir die Funktion normalize()
einsetzen. Diese
normiert jedes Einzelsignal so, dass alle Messwerte innerhalb eines vorgegebenen
Wertebereichs liegen (z.B. im Intervall [0, 1]):
normalize(x, min = 0, max = 1)
Durch Anpassung der Argumente min und max können wir den Wertebereich entsprechend anpassen. Diese Normalisierung kann insbesondere für die Berechnung von Merkmalen und zum Plotten von Signalen nützlich sein.
Zusätzlich zur Anpassung der Messwerte eines Signals können ebenso dessen Zeitinformationen angepasst werden. Dies bedeutet nicht, dass nur die vorhandenen Zeitstempel verändert werden (z.B. zeitlichen Offset hinzufügen). Sondern vielmehr, dass zeitliche Intervalle aggregiert, für einzelne Signale fehlende Zeitstempel eingefügt und evtl. vorhandene zeitliche "Lücken" mit Messwerten aufgefüllt werden können. Während im erstgenannten Fall ein vom Originalverlauf abweichendes Signal entstehen kann, wird er bei den beiden anderen Zeitoperationen nicht verändert.
Die zeitliche Aggregation von Messwerten kann durch die Funktion thicken()
ausgeführt werden. Die Aggregation eines Signals in 1-Minuten-Intervalle
erreichen wir durch:
thicken(x, interval_sec = 60)
Standardmäßig wird hierbei derjenige Messwert beibehalten, der als erstes im jeweiligen Intervall auftritt. Durch Anpassung des fun-Arguments können aber auch andere Methoden umgesetzt werden (z.B. Mittelwertbildung).
Für den Fall, dass für einzelne Signale eines Dataframes Messwerte zu
unterschiedlichen Zeitpunkten aufgezeichnet wurden (nämlich immer dann, wenn
eine Wertänderung des jeweiligen Sensors verzeichnet wurde), können wir mit der
Funktion regularize()
für jeden auftretenden Zeitstempel einen
entsprechenden Messpunkt für jedes Signal hinzufügen. Somit existiert danach für
jeden Zeitstempel dieselbe Anzahl an Messwerten, welche der Anzahl der
auftretenden Signale entspricht.
Darüber hinaus kann mit derselben Funktion regularize()
die Umwandlung eines
Signals mit irregulärer Abtastung (d.h. mit zeitlichen "Lücken") in ein Signal
mit regulärer Abstastung (Resampling) ausgeführt werden. Ensprechend der
kleinsten im Signal auftretenden Abtastintervalle werden die Lücken aufgefüllt.
Da bei diesem Vorgehen unbeabsichtigt sehr kleine Abtastintervalle für die
Signale erzeugt werden können (und somit u.U. der verfügbare Arbeitsspeicher
nicht mehr ausreicht), sollten wir vor Anwendung der Regularisierungsfunktion
zunächst eine definierte zeitliche Abtastrate sicherstellen:
x %>% thicken(interval_sec = 60) %>% regularize()
Mit dem zugehörigen Argument fill_gap können wir das Auffüllen der Messwerte
der neu entstehenden Abtastpunkte steuern, da diese zunächst mit NA-Werten
initialisiert werden. Insgesamt kann die Funktion regularize()
als
Gegenstück zur o.g. Funktion condense()
angesehen werden, da sie dem
Dataframe redundante Signalinformationen hinzufügt.
Zur Visualisierung von Signalen werden im Package drei verschiedene Funktionen bereitgestellt. Je nachdem wie umfangreich die darzustellenden Signale sind (d.h. Anzahl Signale, Zeitraum), eignet sich ein bestimmter Plottyp u.U. besser als ein anderer. Die verfügbaren Funktionen liefern jeweils ein ggplot2-Objekt mit einfachem Layout zurück, das ggf. weiter angepasst werden kann.
Der einfachste Signalplot besteht in einer Liniendarstellung der Messwerte über
die Zeit mittels der Funktion plot_stacked()
. Dabei werden für ein Signal
die Zeitstempel auf der X-Achse und die zugehörigen Messwerte aus der Y-Achse
dargestellt. Aufeinanderfolgende Messwerte werden durch eine
treppenstufenförmige Linie verbunden, die solange horizontal verläuft bis der
nächste Messwert erreicht wird (s. nachfolgende Abbildung 1). Mehrere Signale
werden durch Überlagerung im selben Plotbereich dargestellt und lediglich durch
ihre Farbe gekennzeichnet. Durch Anpassung des Arguments has_legend können
wir eine zusätzliche Legende einblenden, welche die Farbzuordnung erläutert.
plot_stacked(x, has_legend = TRUE)
Eine Erweiterung des vorherigen Plots ist die Funktion plot_spread()
. Sie
erzeugt ebenso für jedes Signal einen Linienplot, allerdings wird jedes Signal
in einen separaten Plotbereich gezeichnet (Facet). Zur besseren Darstellung (und
Vergleichbarkeit) können diese Plotbereiche in einer Tabellenform mit Zeilen und
Spalten angeordnet werden. Standardmäßig werden hier alle Signalplots
untereinander in einer einzigen Spalte angeordnet (s. nachfolgende Abbildung
2). Mit den Argumenten nrow und ncol können wir die Größe der
zugrundeliegenden Tabelle jedoch verändern.
plot_spread(x)
Die dritte Visualisierungsfunktion plot_checkered()
stellt einen Plottyp für
Signale zur Verfügung, bei der die Darstellung um eine weitere Dimension
erweitert wird. Auf der X-Achse werden wie gehabt die Zeitstempel dargestellt,
auf der Y-Achse nun allerdings die Signale (eine Zeile pro Signal) und als
farbliche Information auf den Kreuzungspunkte den jeweiligen Messwert. Diese
Darstellungsform wird auch als Heatmap bezeichnet (s. nachfolgende Abbildung
3). Mittels dem Argument has_legend lässt sich dem Plot eine Legende
hinzufügen, die Aufschluss über die verwendete Messwert-Farb-Zuordnung gibt.
Damit aussagekräftige Plots entstehen, kann es u.U. sinnvoll sein, die Signale
vorher mittels normalize()
zu vereinheitlichen (s.o.).
x %>% plot_checkered(has_legend = TRUE)
Um in den Signalen relevante Veränderungen und Ereignisse zu bestimmen, die für das spätere maschinelle Lernen von Interesse sind (z.B. Störungen, Trends), werden im Package eine Reihe von ereignisbasierten Funktionen bereitgestellt. Diese werden in den folgenden Abschnitten näher erläutert und lassen sich grob in drei Bereiche einteilen: die Detektion, das Einlesen und das Auswählen von Ereignissen (Sampling).
Im Mittelpunkt steht hierbei die Idee, Ereignisse anhand der in den Signalen
verfügbaren Informationen zu bestimmen. Dies können bspw. Zeitpunkte sein, an
denen das Signal zulässige Grenzwerte über-/unterschreitet oder bestimmte
interessante Signalwerte vorliegen. Hierfür können wir die Funktion
event_detect()
einsetzen:
event_detect(x, which = c("011PE_BB05", "011PE_BB15"), op = `<`, test_value = 0)
Neben dem Signal-Dataframe x bekommt sie einen Stringvektor which übergeben, der die zu berücksichtigenden Signalnamen enthält. Die zugehörige Testbedingung wird anhand der Argumente op und test_value beschrieben. Während erstgenanntes eine Funktion ist, die zum Testen verwendet wird, entspricht letzterem der zu testende Signalwert.
Mit der vorgestellten Funktion können wir einzelne Signalereignisse finden, d.h.
Zeitpunkte zu denen die Testbedingung erstmalig eingetreten ist. Diese
Ereignisse besitzen ausschließlich einen Startzeitpunkt. Zur Bestimmung von
Ereignissen, die einen Start- und einen Endzeitpunkt besitzen, kann die Funktion
event_match_seq()
eingesetzt werden. Hierbei wird zunächst mittels
event_detect()
die Menge der Startereignisse detektiert und anschließend
durch wiederholte Anwendung der Funktion die Menge der Endereignisse. Mithilfe
der Funktion event_match_seq()
können wir dann eine zeitliche Verbindung
zwischen den beiden Ereignismengen herstellen:
start <- event_detect(x, which = c("011PE_BB05", "011PE_BB15"), op = `<`, test_value = 0) end <- event_detect(x, which = c("011PE_BB05", "011PE_BB15"), op = `>=`, test_value = 0) event_match_seq(start, end)
Dabei wird jedem Startereignis aus start ein passendes Endereignis aus
end zugeordnet, indem deren zeitliche Nähe als Indikator für deren
Zusammengehörigkeit herangezogen wird. Mit den Argumenten time_var_x und
time_var_y kann der jeweilige Spaltenname mit der Zeitinformation angepasst
werden. Mittels is_renamed kann die Benennung des Ergebnis-Dataframes
beeinflusst werden. Mit remove_na können wir fehlende Einträge im Ergebnis
vermeiden, d.h. Ereignisse, denen kein passendes Gegenstück zugeordnet werden
konnte. Ein komplexerer Ansatz zur Ereigniszuordnung ist in der Funktion
event_match_frequent()
implementiert. Details hierzu können in der
dazugehörigen Hilfeseite nachgelesen werden.
Neben der beschriebenen signalbasierten Ermittlung von Ereignissen, können bei deren Detektion ebenso "externe" Faktoren eine Rolle spielen. Hierbei werden die Ereignisse von Systemen generiert, welche die Signale nicht direkt überwachen, sondern den Gesamtzustand des technischen Systems bzw. dessen Umwelt berücksichtigen. Dies können bspw. Alarmmeldungen von Maschinen sein, manuell hinzugefügte Ereignisse oder Ereignisse, die auf zusätzlichen Daten basieren.
Da diese Ereignisse nicht direkt aus den Signalen abgeleitet werden können,
bietet das Package eine Funktion harmonize_event()
, um extern
bereitgestellte Ereignisse einzulesen bzw. in das standardisierte Format zu
überführen. Analog zum Einlesen von Signalen (s.o.) obliegt das Schreiben
geeigneter Ingest-Funktionen den Anwendern. Das Standardformat von
Ereignis-Dataframes umfasst im Grunde nur einen Start- und Endzeitpunkt.
Zusätzliche ereignisbezogene Informationen werden in Zusatzspalten gespeichert,
über die der Dataframe bei Bedarf gefiltert werden kann.
Eine weitere Möglichkeit, Ereignisse zu bestimmen, besteht darin, innerhalb einer gegebenen Zeitspanne zufällig Ereignisse auszuwählen bzw. zu platzieren. Dies spielt beim maschinellen Lernen insbesondere bei der Erzeugung von Trainings- und Testdaten eine Rolle. Hierbei werden bestimmte zeitliche Ausschnitte der Signale (Fenster) zur Merkmalsextraktion herangezogen, die jeweils einen Start- und einen Endzeitpunkt besitzen.
Um zu diesem Zweck geeignete zufällige Stichproben der Ereignisse zu ziehen,
werden insgesamt vier Funktionen bereitgestellt: sample_random()
und
sample_random_sequential()
sowie sample_balanced()
und
sample_balanced_sequential()
. Anhand der Namen lässt sich bereits erkennen,
dass sie ähnliche Aufgaben bewältigen. Während die ersten beiden Funktionen ein
zufälliges Sampling durchführen, wird bei den letzten beiden Funktionen eine
gewisse Klassenverteilung (hinsichtlich einer Menge von Zielereignissen)
berücksichtigt. Die mit *_sequential()
benannten Funktionen stellen jeweils
Implementierungsvarianten der Grundfunktionen dar. Details hierzu finden wir in
der jeweiligen Hilfeseite.
Die beiden *_random_*
-Funktionen bestimmen in einem Zeitraum zufällig eine
feste Menge an Ereignissen. Hierbei übergeben wir neben der Anzahl der
Ereignisse und dem zu betrachtenden Zeitintervall noch die gewünschte
Ereignislänge:
sample_random(n = 100, int_start = lubridate::dmy_hm("01.03.16 00:00"), int_end = lubridate::dmy_hm("08.03.16 00:00"), event_length_in_sec = 60)
Mit dem zugehörigen Argument offtime können wir zusätzlich einen Ereignis-Dataframe übergeben, der Zeitfenster innerhalb des Gesamtzeitraums beinhaltet, aus denen keine Ereignis-Stichproben gezogen werden dürfen. Dies können bspw. Zeitabschnitte sein, in den bekannterweise unzuverlässige Signale gemessen wurden. Durch das Argument event_overlap_in_sec wird die potentielle zeitliche Überlappung zwischen Ereignissen gesteuert. Mit dem weiteren Argument .seed kann die Reproduzierbarkeit der zufälligen Stichproben abgesichert werden.
Die beiden *_balanced_*
-Funktionen bestimmen ebenfalls in einem Zeitraum
zufällig eine feste Menge an Ereignissen. Allerdings wird hierbei zusätzlich
eine Menge an Zielereignissen herangezogen, um möglichst ausgewogene Stichproben
an Ereignissen zu erhalten. Diese Zielereignisse können beispielsweise Störungen
oder Alarme sein. Für den Aufbau eines entsprechenden Prognosemodells werden
möglichst klassenbalancierte Trainingsdaten benötigt, bei denen in etwa gleich
viele positive und negative Trainingsfenster vorliegen. Positive Beispiele sind
in diesen Zusammenhang Fenster, die im Vorfeld eines Zielevents liegen (mit
einer gewissen zeitlichen Nähe). Negative Beispiele befinden sich entsprechend
zeitlich weit von Zielereignissen entfernt.
Das klassenbalancierte Sampling stoßen wir analog zum zufälligen Sampling an:
target <- tibble::tribble( ~start, ~end, lubridate::dmy_hm("03.03.16 09:51"), lubridate::dmy_hm("03.03.16 10:13"), lubridate::dmy_hm("07.03.16 23:07"), lubridate::dmy_hm("07.03.16 23:48") ) sample_balanced(n = 100, int_start = lubridate::dmy_hm("01.03.16 00:00"), int_end = lubridate::dmy_hm("08.03.16 00:00"), target_event = target, target_cut_in_sec = 3600, event_length_in_sec = 60)
Zusätzlich wird mittels des Arguments target_event ein Ereignis-Dataframe übergeben, der die zu Zielereignisse beinhaltet. Durch target_cut_in_sec können wir den vor einem Zielereignis liegenden Zeithorizont beeinflussen, der zur Unterscheidung von positiven und negativen Beispiele herangezogen wird. Analog zum zufälligen Sampling gibt es die Argumente offtime, event_overlap_in_sec und .seed, mit denen sich das jeweilige Verhalten der Funktion anpassen lässt.
Mithilfe der zuvor bestimmten Ereignisse wollen wir die zugrundeliegenden Signale so vorbereiten, dass daraus beschreibende Merkmale abgeleitet werden können. Hierbei können drei Verarbeitungsschritte stattfinden: das Schneiden, das Korrigieren und das Zusammenfassen von Signalfenstern.
Analog zur weiter oben eingeführten Funktion crop()
kann mittels der
Funktion window_crop()
für eine Ereignismenge die zugehörigen Signalfenster
zurechtgeschnitten werden:
event <- tibble::tribble( ~start, ~end, lubridate::dmy_hm("03.03.16 09:51"), lubridate::dmy_hm("03.03.16 10:13"), lubridate::dmy_hm("07.03.16 23:07"), lubridate::dmy_hm("07.03.16 23:48") ) window_crop(x, start = event$start, end = event$end)
Dabei erzeugen wir für jedes Ereignis aus event einen zugehörigen Signal-Dataframe, der einen entsprechenden zeitlichen Ausschnitt der Signaldaten umfasst. Die resultierenden Signalfenster werden als Liste zurückgegeben.
Durch das Schneiden der Signalfenster kann es sein, dass die enthaltenen zeitlichen Informationen angepasst werden müssen. Auf diese Weise können wir fensterübergreifende Vergleichbarkeit sicherstellen, die für die nachfolgende Merkmalsberechnung wichtig sein kann.
Eine erste Anpassung kann darin bestehen, mit der Funktion window_align()
die Signalfenster zeitlich auszurichten. Hierbei werden die absoluten in
relative Zeitinformationen überführt, sodass alle Fenster denselben
Startzeitpunkt aufweisen. Als zweite Korrektur kann mit der Funktion
window_stretch()
die Länge der Signalfenster vereinheitlicht werden. Dabei
steuern wir mittels des Arguments max_in_sec den neuen gemeinsamen letzten
Zeitstempel der Signalfenster. Alle anderen davorliegenden Zeitstempel werden
entsprechend angepasst, ihre relativen Positionen zueinander bleiben erhalten.
Die dritte Art der zeitlichen Anpassung von Signalfenstern ist mit
window_truncate()
möglich. Diese Funktion beschneidet die Menge der
Signalfenster auf die Länge des kürzesten Signalfensters, d.h. Informationen
können hierbei verlorengehen.
Durch Verkettung der verschiedenen Funktionen zur Fensterkorrektur können wir
einheitliche Signalfenster herstellenn, deren Zeitinformation gut miteinander
kombinierbar ist Auf diese Weise können die Signale verschiedener Signalfenster
zusammengefasst werden. Zur Aggregation kann die Funktion window_merge()
eingesetzt werden. Neben der Liste der zusammenzufassenden Signalfenster können
wir im Argument fun eine spezielle Verschmelzungsfunktion übergeben, welche
die Signalwerte gleicher Zeitpunkte zusammenfasst. Der Default-Wert bei der
Verschmelzung ist die Funktion mean()
, d.h. die Signale werden gemittelt.
Abschließend können wir aus den vorbereiteten Signalfenstern nun eine Reihe von beschreibenden Merkmalen extrahieren. Diese Merkmale (oder auch Features) beinhalten eine kompakte numerische Repräsentation der Signalverläufe der Sensordaten. Kombinieren wir diese Merkmale mit der entsprechenden Klasseninformation (also bspw. ob innerhalb eines gegebenen Zeithorizonts nach dem Signalfenster eine Störung auftritt oder nicht), so erhalten wir potentielle Trainingsdaten für maschinelle Lernverfahren. Diese Algorithmen sind in der Lage, statistische Muster in den Daten in Form von mathematischen Modellen zu erfassen, die wiederum für Prognosezwecke eingesetzt werden können.
Mit der Funktion feature_all()
können wir zunächst die Menge der verfügbaren
Merkmalstypen abfragen:
feature_all()
Die Berechnungsdetails der r length(feature_all()) - 1
unterschiedlichen
Merkmalstypen können in der jeweiligen Hilfeseite nachgeschlagen werden, z.b.
durch ?fit_linear
. Mit der Funktion feature()
können wir nun für eine
Menge von Signalfenstern die entsprechenden beschreibenden Merkmale berechnen:
feat <- feature(x, feat = list("stat" = list(), "hist_equi" = list("nr_bins" = 3, "is_relative" = FALSE)))
Neben der per x übergebenen Liste mit vorbereiteten Signalfenstern wird durch das Argument feat die Menge der zu berechnenden Merkmalstypen in einer benannten Liste festgelegt und geeignet parametriert. Die Auswahl der Merkmalstypen geschieht hierbei durch den Namen des jeweiligen Listenelements, also im obigen Beispiel "stat" und "hist_equi". Die zugehörigen Argumente werden wiederum in einer benannten Liste übergeben, also "nr_bins" und "is_relative" für den Merkmalstyp "hist_equi". Sollten keine weiteren Argumente für den ausgewählten Merkmalstyp existieren bzw. wird die Berechnung mit den entsprechenden Default-Werten gewünscht, so können wir an dieser Stelle eine leere Liste übergeben (siehe Merkmalstyp "stat" oben).
Standardmäßig liefert die Funktion feature()
einen Merkmals-Dataframe im
breiten Format zurück, der die fensterweise berechneten Einzelmerkmale
beinhaltet. Mittels der zusätzlichen Argumente as_df und as_wide können
wir den Typ und das Format der zurückgegebenen Datenstruktur anpassen. Per
weiterem Argument add_id kann das Hinzufügen einer Fenster-ID gesteuert
werden.
Der resultierende Merkmals-Dataframe kann direkt als Grundlage für
anschließendes maschinelles Lernen verwendet werden. Die hierfür benötigte
Klasseninformation können wir mit der Funktion event_target()
herleiten und
dann mit den Merkmalen verknüpfen:
class <- event_target(x, target_event = target, target_cut_in_sec = 3600) feat <- dplyr::mutate(feat, label = class$label)
Für eine Ereignismenge x mit den zugrundeliegenden zeitlichen Positionen der Signalfenster wird unter Zuhilfenahme einer Zielereignismenge target_event und eines anzusetzenden Zeithorizonts target_cut_in_sec das zugehörige Klassenlabel bestimmt. Durch die weiteren Argumente keep_label und keep_time können wir im Detail beeinflussen, welche Klasseninformation zurückgegeben werden soll. So ist es bspw. möglich, als potentielle Regressionsgröße die Zeit zum nächsten Zielereignis beizubehalten.
In dieser Vignette wurden die Grundzüge der Verwendung des rktiq-Packages erläutert und anhand von Beispielen demonstriert. Hierbei wurden schrittweise die zugrundeliegenden Sensorsignale eingelesen, vorbereitet und visualisiert. Danach wurde gezeigt, wie anhand der Signale gewisse Ereignisse bestimmt und diese wiederum in Form von Signalfenstern vorbereitet werden können. Abschließend wurden hierfür Merkmale berechnet, die als Ausgangspunkt für maschinelles Lernen dienen können.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.