Data.table: rollierende Funktionen, rollierende Aggregate, gleitendes Fenster, gleitender Durchschnitt

Erstellt am 21. Apr. 2018  ·  39Kommentare  ·  Quelle: Rdatatable/data.table

Um Anforderungen an einer einzigen Stelle zu sammeln und ~4 Jahre alte Diskussionen zu aktualisieren, die dieses Thema erstellen, um die Funktion _Rollende Funktionen_ (auch bekannt als _Rollende Aggregate_, _Gleitendes Fenster_ oder _gleitender Durchschnitt_/_Gleitende Aggregate_) abzudecken.

Rollfunktionen

  • [x] Rollmean
  • [x] Rollsumme
  • [ ] Rollmin
  • [ ] Rollmax
  • [ ] Rollmedian
  • [ ] rollprod
  • [ ] rollsd
  • [ ] rollvar
  • [ ] Rollrank
  • [x] rollapply (vom Benutzer bereitgestellter SPASS)
  • [ ] Rollregression (sehr gefragt)
  • [ ] Rollkor?
  • [ ] Rollcov?

Merkmale

  • [x] mehrere Spalten gleichzeitig
  • [x] mehrere Fenster gleichzeitig
  • [x] mehrere Spalten und mehrere Fenster gleichzeitig
  • [x] Eingabe atomarer Vektoren und einzelnes Fenster gibt atomare Vektoren zurück
  • [x] Liste von Vektoren verschiedener Länge
  • [x] ausrichten: links/Mitte/rechts
  • [x] Umgang mit NAs
  • [x] Füllkonstante
  • [x] lange Vektorunterstützung
  • [ ] teilweise Fensterunterstützung (bei Bedarf in ea766f2499034cedf6abf872440268b78979147c zu finden)
  • [x] Unterstützung für adaptive Fenster
  • [x] Verwenden Sie openmp, um die Berechnung mehrerer Spalten/Fenster zu parallelisieren
  • [x] Rundungsfehlerkorrektur
  • [x] Timing im ausführlichen Modus aus paralleler Region (blockiert durch ~#3422~, #3423)
feature request

Hilfreichster Kommentar

@mattdowle beantwortet Fragen von PR

Warum machen wir das in data.table? Warum integrieren wir es, anstatt zu bestehenden Paketen beizutragen und diese aus data.table zu verwenden?

  1. Es wurden 3 verschiedene Probleme erstellt, die nach dieser Funktionalität in data.table fragten. Auch mehrere SO-Fragen mit dem Tag data.table. Benutzer erwarten, dass dies im Umfang von data.table liegt.
  2. data.table passt perfekt für Zeitreihendaten und rollierende Aggregate sind dort ziemlich nützliche Statistiken.

meine Vermutung ist, dass es auf die Syntax (Funktionen nur möglich oder praktisch, wenn sie in data.table eingebaut sind; zB innerhalb [...] und optimiert) und den Einbau von data.table-Interna in die Rolling-Funktion auf C-Ebene ankommt; zB froll* sollte sich bewusst sein und data.table-Indizes und Schlüssel verwenden. Wenn dies der Fall ist, sind weitere Einzelheiten hierzu erforderlich; zB ein einfaches kurzes Beispiel.

Mir persönlich geht es um Schnelligkeit und das Fehlen von Abhängigkeitsketten, die heutzutage nicht mehr einfach zu erreichen sind.
Schlüssel/Indizes könnten für frollmin/frollmax nützlich sein, aber es ist unwahrscheinlich, dass der Benutzer einen Index für die Kennzahlvariable erstellt. Es ist unwahrscheinlich, dass der Benutzer einen Index für die Kennzahlvariable erstellt, auch haben wir diese Optimierung für Min/Max noch nicht durchgeführt. Ich sehe nicht viel Sinn für die GForce-Optimierung, da der zugewiesene Speicher nach dem Roll*-Aufruf nicht freigegeben, sondern als Antwort zurückgegeben wird (im Gegensatz zu nicht rollierendem Mittelwert, Summe usw.).

Wenn es kein überzeugendes Argument für die Integration gibt, sollten wir stattdessen zu den anderen Paketen beitragen.

Ich habe oben einige aufgeführt. Wenn Sie nicht überzeugt sind, empfehle ich Ihnen, eine Frage an data.table-Benutzer zu stellen, auf Twitter zu fragen usw., um die Antwort zu überprüfen. Diese Funktion wurde lange Zeit und von vielen Benutzern nachgefragt. Wenn die Antwort Sie nicht überzeugt, können Sie dieses Problem schließen.

Alle 39 Kommentare

Vorgeschlagene rollmean Implementierung, vereinfacht.

x = data.table(v1=1:5, v2=1:5)
k = c(2, 3)
i - single column
j - single window
m - int referring to single row
w - current row's sum of rolling window
r - answer for each i, j



md5-be70673ef4a3bb883d4f334bd8fadec9



for i in x
  for j in k
  r = NA_real_
  w = 0
    for m in 1:length(i)
      w = w + i[m]
      w = w - i[m-j]
      r[m] = w / j

ja, und viele weitere gerollte Funktionen folgen derselben Grundidee (einschließlich
rollierende Standardabweichung/jedes erwartungsbasierte Moment und jede Funktion
wie ein Rollenprodukt, das invertierbares * anstelle von + verwendet, um innerhalb zu aggregieren
das Fenster

I vorgesehen immer Fenster Funktionalität rollend als die Datenmenge in mehrere überlappende Gruppen Gruppierung (Windows). Dann würde die API ungefähr so ​​aussehen:

DT[i, j,
   by = roll(width=5, align="center")]

Wenn dann j mean(A) , können wir es intern durch rollmean(A) ersetzen – genau wie wir es gerade mit gmean() tun. Oder j kann eine beliebig komplizierte Funktionalität enthalten (z. B. eine Regression für jedes Fenster ausführen), in diesem Fall würden wir .SD data.table bereitstellen – genau wie bei Gruppen im Augenblick.

Auf diese Weise müssen Sie nicht mehr als 10 neue Funktionen einführen, sondern nur eine. Und es fühlt sich auch im Geiste data.table-y an.

Ja zustimmen

Am Sa, 21. April 2018, 15:38 Uhr Pasha Stetsenko [email protected]
schrieb:

Ich habe mir die Rolling Window-Funktionalität immer als Gruppierung der
Datensatz in mehrere überlappende Gruppen (Fenster). Dann würde die API aussehen
etwas wie das:

DT[i, j,
by = roll(width=5, align="center")]

Wenn j dann, sagen wir, mean(A) enthält, können wir es intern durch . ersetzen
rollmean(A) -- genau wie wir es gerade mit gmean() machen. Oder ich kann
eine beliebig komplizierte Funktionalität enthalten (sagen wir eine Regression für
jedes Fenster), in diesem Fall würden wir .SD data.table dazu liefern – genau
wie wir es gerade mit Gruppen machen.

Auf diese Weise müssen Sie nicht mehr als 10 neue Funktionen einführen, sondern nur eine. Und es
fühlt sich data.table-y auch im Geiste an.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Rdatatable/data.table/issues/2778#issuecomment-383275134 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AHQQdbADiE4aAI1qPxPnFXUM5gR-0w2Tks5tquH8gaJpZM4TeTQf
.

@st-pasha interessante Idee, sieht aus wie data.table-y spirit, bringt aber viele Einschränkungen mit sich und ist für diese Kategorie von Funktionen nicht wirklich geeignet.


  • wie man Rollmean nach Gruppe durchführt
DT[, rollmean(V1, 3), by=V2]
  • wie man unterschiedliche Fenstergrößen für verschiedene Spalten berechnet
DT[, .(rollmean(V1, 3), rollmean(V2, 100))]
  • wie man Rollmean außerhalb von [.data.table berechnet, da wir jetzt Shift zulassen
rollmean(rnorm(10), 3)
  • wie man Anfragen unterstützt wie
DT[, .(rollmean(list(V1, V2), c(5, 20)), rollmean(list(V2, V3), c(10, 30)))]
  • wie man mean und rollmean im selben j Anruf anruft
DT[, .(rollmean(V1, 3), mean(V1)), by=V2]

Normalerweise aggregieren wir bei der Verwendung von by Daten in eine kleinere Anzahl von Zeilen, während Rollfunktionen immer einen Vektor mit derselben Länge wie die Eingabe zurückgeben. Diese Arten von Funktionen in SQL haben API im folgenden Stil:

SELECT AVG(value) OVER (ROWS BETWEEN 99 PRECEDING AND CURRENT ROW)
FROM tablename;

Sie können es immer noch wie folgt mit GROUP BY kombinieren:

SELECT AVG(value) OVER (ROWS BETWEEN 99 PRECEDING AND CURRENT ROW)
FROM tablename
GROUP BY group_columns;

In SQL bleiben diese Funktionen also in SELECT was sich in DT auf j bezieht.
In DT könnten wir dasselbe erreichen mit:

DT[, rollmean(value, 100)]
DT[, rollmean(value, 100), group_columns]

Rollende Funktionen passen in dieselbe Funktionskategorie wie shift die auch dieselbe Anzahl von Zeilen zurückgibt, die bei der Eingabe erhalten wurde.
Shift in SQL sieht so aus:

SELECT LAG(value, 1) OVER ()
FROM tablename;

mean und rollmean sind nicht nur verschiedene Funktionen, sondern verschiedene Kategorien von Funktionen. Einer wollte nach Gruppen aggregieren, ein anderer überhaupt nicht. Dies ist in SQL leicht sichtbar, wo wir GROUP BY für den Rolling Functions-Typ verwenden, sondern GROUP BY für Aggregate wie mean (eventuell wird beim Gruppieren die Gesamtsumme der Gewährung erhalten) Klausel ist nicht vorhanden).
Ich sehe keinen guten Grund, die gleichen Optimierungsregeln wie für mean anzuwenden, besonders wenn es nicht wirklich für den Anwendungsfall geeignet ist, und das alles nur aus Gründen der data.table-y Geist. Der aktuelle Vorschlag ist auch data.table-y-Spirit, er kann leicht mit := kombiniert werden, genau wie shift . Es fügt nur eine Reihe neuer Funktionen hinzu, die derzeit in data.table nicht verfügbar sind.

@jangorecki Danke, das sind alles gültige Überlegungen. Natürlich haben verschiedene Menschen unterschiedliche Erfahrungen und unterschiedliche Ansichten darüber, was als "natürlich" angesehen werden sollte.

Es ist möglich, Rollmean nach Gruppe durchzuführen: Dies ist nur eine Gruppierung auf 2 Ebenen: DT[, mean(V1), by=.(V2, roll(3))] . Ich sehe jedoch nicht, wie ich mit meiner Syntax unterschiedliche Fenstergrößen für verschiedene Spalten erstellen kann ...

Ich muss zugeben, dass ich noch nie zuvor SQL-Syntax für Rolling-Joins gesehen habe. Es ist interessant, dass sie Standard-Aggregatoren wie AVG aber die Windowing-Spezifikation darauf anwenden. Wenn man sich die Transact-SQL-Dokumentation ansieht, gibt es dort einige interessante Ideen, zum Beispiel die Unterscheidung zwischen logischer/physischer Zeilenauswahl. Sie erlauben verschiedene "OVER"-Operatoren für verschiedene Spalten, aber in allen Beispielen, die sie geben, wird dieselbe OVER-Klausel mehrmals wiederholt. Es deutet also darauf hin, dass dieser Anwendungsfall viel häufiger vorkommt und daher die Verwendung einer einzelnen roll() Gruppe zu weniger Wiederholungen führen würde.

Außerdem liefert diese SO-Frage einen interessanten Einblick, warum die OVER-Syntax überhaupt in SQL eingeführt wurde:

Sie können GROUP BY SalesOrderID verwenden. Der Unterschied besteht darin, dass Sie mit GROUP BY nur die aggregierten Werte für die Spalten haben können, die nicht in GROUP BY enthalten sind. Im Gegensatz dazu können Sie mit Fenster-Aggregatfunktionen anstelle von GROUP BY sowohl aggregierte als auch nicht aggregierte Werte abrufen. Das heißt, obwohl Sie dies in Ihrer Beispielabfrage nicht tun, können Sie sowohl einzelne OrderQty-Werte als auch deren Summen, Zählungen, Durchschnitte usw. über Gruppen derselben SalesOrderIDs abrufen.

Es scheint also, dass die Syntax entworfen wurde, um die Beschränkung von Standard-SQL zu umgehen, bei der Gruppierungsergebnisse nicht mit nicht aggregierten Werten kombiniert werden konnten (dh die Auswahl von A und mean(A) im selben Ausdruck). data.table hat jedoch keine solche Einschränkung, so dass es mehr Freiheit bei der Wahl der Syntax hat.


Wenn wir jetzt wirklich einen Schritt voraus sein wollen, müssen wir in einer breiteren Perspektive denken: Was sind die "rollenden" Funktionen, wofür werden sie verwendet, wie können sie erweitert werden usw. Hier ist meine Meinung, die kommt aus der Sicht eines Statistikers:

Die Funktion "Rollender Mittelwert" wird verwendet, um einige verrauschte Eingaben zu glätten. Nehmen wir an, Sie haben Beobachtungen im Laufe der Zeit und möchten eine Vorstellung von der "durchschnittlichen Menge" haben, die sich dennoch im Laufe der Zeit ändern würde, wenn auch sehr langsam. In diesem Fall kommt "rollender Mittelwert über die letzten 100 Beobachtungen" oder "rollender Mittelwert über alle vorherigen Beobachtungen" in Betracht. Wenn Sie eine bestimmte Größe über einen Bereich von Eingaben beobachten, können Sie sie ähnlich glätten, indem Sie den "rollenden Mittelwert über ±50 Beobachtungen" anwenden.

  • Die erste Erweiterung besteht also darin, sich "glatte Fenster" anzusehen: Stellen Sie sich einen Mittelwert über vergangene Beobachtungen vor, bei dem der Beitrag umso geringer ist, je weiter eine Beobachtung in der Vergangenheit liegt. Oder ein Durchschnitt von Beobachtungen in der Nähe über einem Gaußschen Kernel.
  • Zweitens sind adaptive Fenster. Wenn Sie beispielsweise eine verrauschte Eingabe über ein Intervall [0, 1] definiert haben, führt die Glättung mit einem ±N-Fenster zu einem verzerrten Ergebnis in der Nähe der Kanten. Ein unverzerrter Schätzer würde die Form des Fensters basierend auf dem Abstand von der Kante anpassen.
  • Resample-Glättung: Die Beschränkung, genau so viele Beobachtungen wie in den Quelldaten zu erzeugen, ist zu einschränkend. Wenn Sie sich Ihre Daten als verrauschte Beobachtungen einer zugrunde liegenden Funktion vorstellen, ist es durchaus sinnvoll, die geglätteten Werte dieser Funktion auf einem Netz zu berechnen, das gröber/feiner als die ursprüngliche Eingabe ist. Oder vielleicht haben die Originaldaten unregelmäßige Abstände und Sie möchten sie auf ein regelmäßiges Raster neu abtasten.
  • Klappmesser: Für jede Beobachtung möchten Sie den Durchschnitt/die Regression über alle Beobachtungen außer der aktuellen berechnen.
  • K-fache Aufteilung: Daten als mehrere Gruppen anzeigen, wobei jede Gruppe nur einen kleinen Teil der Beobachtungen ausschließt.

All dies kann als erweiterte Gruppierungsoperatoren implementiert werden, wobei Rolling Window nur eines der Elemente auf dieser Liste ist. Davon abgesehen verstehe ich nicht, warum wir nicht beides haben können.

Ich muss zugeben, dass ich noch nie zuvor SQL-Syntax für Rolling-Joins gesehen habe.

Ich nehme an, Sie meinen Rolling Functions, das Problem hat nichts mit Rolling Joins zu tun.

Sie erlauben verschiedene "OVER"-Operatoren für verschiedene Spalten, aber in allen Beispielen, die sie geben, wird dieselbe OVER-Klausel mehrmals wiederholt. Es deutet also darauf hin, dass dieser Anwendungsfall viel häufiger vorkommt und daher die Verwendung einer einzelnen roll()-Gruppe zu weniger Wiederholungen führen würde.

Es ist nur eine Frage des Anwendungsfalls, wenn Sie dasselbe OVER() viele Male aufrufen, finden Sie es möglicherweise performanter, GROUP BY , eine Lookup-Tabelle zu erstellen und in anderen Abfragen wiederzuverwenden. Welche Beispiele es auch immer gibt, die Wiederholung von OVER() ist erforderlich, um das Lokalitätsmerkmal für jede bereitgestellte Kennzahl beizubehalten. Meine Anwendungsfälle aus Data Warehouses waren nicht so einfach wie die aus Microsoft-Dokumenten.

Im Gegensatz dazu können Sie mit Fenster-Aggregatfunktionen anstelle von GROUP BY sowohl aggregierte als auch nicht aggregierte Werte abrufen.

In data.table führen wir := und by in einer Abfrage aus, um dies zu erreichen.

Es scheint also, dass die Syntax entworfen wurde, um die Beschränkung von Standard-SQL zu umgehen, bei der Gruppierungsergebnisse nicht mit nicht aggregierten Werten kombiniert werden konnten (dh die Auswahl von A und Mittelwert(A) in demselben Ausdruck). data.table hat jedoch keine solche Einschränkung, so dass es mehr Freiheit bei der Wahl der Syntax hat.

Es ist keine große Einschränkung von SQL, sondern nur das Design von GROUP BY, dass es aggregiert, genauso wie unsere by aggregiert. Eine neue API war erforderlich, um neue Fensterfunktionalitäten abzudecken. Die Gruppierung für die SQL-Fensterfunktion kann für jeden Funktionsaufruf mit FUN() OVER (PARTITION BY ...) bereitgestellt werden, wobei _partition by_ der lokalen Gruppierung für einzelne Kennzahl entspricht. Um Flexibilität von SQL zu erreichen, müssten wir also j = mean(V1, roll=5) oder j = over(mean(V1), roll=5) und diese API in j behalten. Dennoch kann dieser Ansatz nicht alle oben genannten Anwendungsfälle unterstützen.

Sie können es glätten, indem Sie "rollendes Mittel über ±50 Beobachtungen" anwenden.

Dafür wird das Argument align verwendet.

Die erste Erweiterung besteht also darin, sich "glatte Fenster" anzusehen: Stellen Sie sich einen Mittelwert über vergangene Beobachtungen vor, bei dem der Beitrag umso geringer ist, je weiter eine Beobachtung in der Vergangenheit liegt. Oder ein Durchschnitt von Beobachtungen in der Nähe über einem Gaußschen Kernel.

Es gibt viele Varianten (nahezu unbegrenzte Anzahl) von gleitenden Durchschnitten, die häufigste Glättungsfensterfunktion (außer Rollmean/SMA) ist der exponentielle gleitende Durchschnitt (EMA). Was aufgenommen werden sollte und was nicht, ist nicht trivial zu entscheiden, und eigentlich ist es am besten, diese Entscheidung entsprechend den Funktionsanfragen zu treffen, die von Benutzern kommen werden, bisher wurde keine solche angefordert.

All dies kann als erweiterte Gruppierungsoperatoren implementiert werden, wobei Rolling Window nur eines der Elemente auf dieser Liste ist.

Sicherlich können sie das, aber wenn Sie sich SO und die in unserem Repo erstellten Probleme ansehen, werden Sie feststellen, dass diese wenigen rollierenden Funktionen hier für über 95 % der Anfragen von Benutzern verantwortlich sind. Ich freue mich, an EMA und anderen MAs zu arbeiten (obwohl ich nicht sicher bin, ob data.table der beste Ort dafür ist), aber als separates Thema. Einige Benutzer, mich eingeschlossen, warten bereits seit 4 Jahren auf einen einfachen gleitenden Durchschnitt in data.table.

Hier ist meine Meinung aus der Sicht eines Statistikers

Mein Standpunkt stammt aus dem Data Warehousing (wo ich die Fensterfunktion mindestens einmal pro Woche verwendet habe) und der Preistrendanalyse (wo ich Dutzende verschiedener gleitender Durchschnitte verwendet habe).

rollmean Entwurf wird in den Zweig roll verschoben. Ich habe festgestellt, dass die meisten anderen Pakete, die Rolling Mean implementieren, nicht gut mit na.rm=FALSE und NAs in der Eingabe umgehen können. Diese Implementierung verarbeitet NA konsistent zu mean , was aufgrund von ISNAN Aufrufen zusätzlichen Overhead verursacht. Wir könnten API eine schnellere, aber weniger sichere Version erlauben, wenn der Benutzer sicher ist, dass keine NAs in der Eingabe sind.
PR ist in #2795

@mattdowle beantwortet Fragen von PR

Warum machen wir das in data.table? Warum integrieren wir es, anstatt zu bestehenden Paketen beizutragen und diese aus data.table zu verwenden?

  1. Es wurden 3 verschiedene Probleme erstellt, die nach dieser Funktionalität in data.table fragten. Auch mehrere SO-Fragen mit dem Tag data.table. Benutzer erwarten, dass dies im Umfang von data.table liegt.
  2. data.table passt perfekt für Zeitreihendaten und rollierende Aggregate sind dort ziemlich nützliche Statistiken.

meine Vermutung ist, dass es auf die Syntax (Funktionen nur möglich oder praktisch, wenn sie in data.table eingebaut sind; zB innerhalb [...] und optimiert) und den Einbau von data.table-Interna in die Rolling-Funktion auf C-Ebene ankommt; zB froll* sollte sich bewusst sein und data.table-Indizes und Schlüssel verwenden. Wenn dies der Fall ist, sind weitere Einzelheiten hierzu erforderlich; zB ein einfaches kurzes Beispiel.

Mir persönlich geht es um Schnelligkeit und das Fehlen von Abhängigkeitsketten, die heutzutage nicht mehr einfach zu erreichen sind.
Schlüssel/Indizes könnten für frollmin/frollmax nützlich sein, aber es ist unwahrscheinlich, dass der Benutzer einen Index für die Kennzahlvariable erstellt. Es ist unwahrscheinlich, dass der Benutzer einen Index für die Kennzahlvariable erstellt, auch haben wir diese Optimierung für Min/Max noch nicht durchgeführt. Ich sehe nicht viel Sinn für die GForce-Optimierung, da der zugewiesene Speicher nach dem Roll*-Aufruf nicht freigegeben, sondern als Antwort zurückgegeben wird (im Gegensatz zu nicht rollierendem Mittelwert, Summe usw.).

Wenn es kein überzeugendes Argument für die Integration gibt, sollten wir stattdessen zu den anderen Paketen beitragen.

Ich habe oben einige aufgeführt. Wenn Sie nicht überzeugt sind, empfehle ich Ihnen, eine Frage an data.table-Benutzer zu stellen, auf Twitter zu fragen usw., um die Antwort zu überprüfen. Diese Funktion wurde lange Zeit und von vielen Benutzern nachgefragt. Wenn die Antwort Sie nicht überzeugt, können Sie dieses Problem schließen.

Ich habe festgestellt, dass sparklyr Rolling-Funktionen in einem sehr großen Dataset sehr gut unterstützen kann.

@harryprince könnte ein bisschen mehr Licht ins Dunkel bringen, indem er Beispielcode zur Verfügung stellt, wie Sie es in Sparklyr machen?
Gemäß "Fensterfunktionen" dplyr-Vignette

Walzaggregate arbeiten in einem Fenster mit fester Breite. Sie finden sie weder in Basis R noch in dplyr, aber es gibt viele Implementierungen in anderen Paketen, wie z. B. RcppRoll.

AFAIU Sie verwenden eine benutzerdefinierte Spark-API über Sparklyr, für die die dplyr-Schnittstelle nicht implementiert ist, richtig?

In dieser Ausgabe geht es um rollierende Aggregate, andere "Typen" von Fensterfunktionen sind schon lange in data.table .

Es wäre auch hilfreich, ein Beispiel bereitzustellen, damit wir die (In-Memory-)Leistung mit sparklyr / SparkR können.

Mir ist gerade diese Frage eingefallen:

Wie berechnet man unterschiedliche Fenstergrößen für verschiedene Spalten?

hat in der Tat einen breiteren Anwendungsbereich und gilt nicht nur für rollierende Funktionen.

Zum Beispiel scheint es völlig vernünftig zu sein, zu fragen, wie man den durchschnittlichen Produktpreis nach Datum und dann nach Woche und dann vielleicht nach Woche + Kategorie auswählen kann – alles innerhalb derselben Abfrage. Sollten wir jemals eine solche Funktionalität implementieren, könnte die natürliche Syntax dafür lauten

DT[, .( mean(price, by=date), 
        mean(price, by=week), 
        mean(price, by=c(week, category)) )]

Wenn diese Funktionalität bereits implementiert wäre, wäre es ein einfacher Sprung von dort zu rollenden Mitteln gewesen:

DT[, .( mean(price, roll=5), 
        mean(price, roll=20), 
        mean(price, roll=100) )]

Ich sage nicht, dass dies eindeutig besser ist als rollmean(price, 5) – werfen Sie nur einige Alternativen ein, die in Betracht gezogen werden sollten ...

@st-pasha

wie man den durchschnittlichen Produktpreis nach Datum und dann nach Woche und dann vielleicht nach Woche+Kategorie auswählt – alles innerhalb derselben Abfrage.

AFAIU dies ist bereits mit ?groupingsets , aber noch nicht in [.data.table eingebunden.

@jangorecki , @st-pasha und Co. -- Danke für all eure Arbeit daran! Ich bin neugierig, warum die teilweise Fensterunterstützung aus dem Bereich entfernt wurde. Gibt es Potenzial für diese Funktionalität, um wieder auf die Roadmap zu gelangen? Würde mir manchmal nützlich sein und eine Funktionslücke schließen, die meines Wissens weder in zoo noch in RcppRoll ausgefüllt wurde.

Diese Stack Overflow-Frage ist ein gutes Beispiel für eine fortlaufende Anwendung, die von einem partial = TRUE Argument profitieren könnte.

@msummersgill Danke für das Feedback. Im ersten Beitrag habe ich explizit Commit sha verlinkt, wo Teilfenster-Feature-Code zu finden ist. Die dort vorhandene Implementierung wurde später entfernt, um die Komplexität des Codes zu reduzieren. Es verursachte auch geringe Leistungskosten, selbst wenn diese Funktion nicht verwendet wurde. Diese Funktion kann (und sollte wahrscheinlich) anders implementiert werden, zuerst komplett wie sie ist, und dann einfach das fehlende Teilfenster mit einer zusätzlichen Schleife von 1:window_size . Der Overhead dieser Funktion ist also nur spürbar, wenn Sie sie verwenden. Trotzdem stellen wir diese Funktionalität über das Argument adaptive bereit, wobei die Funktion partial nur ein Sonderfall von adaptive Rolling Mean ist. Es gibt ein Beispiel, wie man partial mit adaptive im ?froll Handbuch erreicht . Hier einfügen:

d = as.data.table(list(1:6/2, 3:8/4))
an = function(n, len) c(seq.int(n), rep(n, len-n))
n = an(3, nrow(d))
frollmean(d, n, adaptive=TRUE)

Natürlich ist es nicht so effizient wie eine nicht adaptive Rollfunktion, die eine zusätzliche Schleife verwendet, um nur ein Teilfenster zu füllen.
AFAIK zoo hat partial Funktion.

Haben Sie Pläne, der data.table rollende Regressionsfunktionen hinzuzufügen?

@waynelapierre wenn es eine Nachfrage dafür geben wird, dann ja. Du hast mein +1

danke das ist super. Allerdings nur eine Frage. Ich sehe nur einfache rollierende Aggregate, wie einen rollenden Mittelwert oder rollenden Median. Implementieren Sie auch verfeinerte Rollfunktionen wie Rolling DT Dataframes? Sagen wir, erstelle einen rollenden DT mit den letzten 10 Obs und führe eine lm Regression darauf aus.

Vielen Dank!

@randomgambit Ich würde sagen, es liegt außerhalb des Geltungsbereichs, es sei denn, es wird eine große Nachfrage danach bestehen. Es wäre nicht sehr schwierig, es schneller zu machen als Basis-R/zoo, indem man nur verschachtelte Schleifen in C verarbeitet. Aber wir sollten versuchen, es mit dem "Online"-Algorithmus zu implementieren, um verschachtelte Schleifen zu vermeiden. Das ist schwieriger und wir könnten es irgendwann für jede Statistik tun, also müssen wir diese Statistiken irgendwann abschneiden.

@jangorecki interessant danke. Das bedeutet, dass ich weiterhin tsibble , um ... DATA.TABLES in ein tibble einzubetten! überwältigt :D

Es wurde versucht, frollmean zu verwenden, um eine nichtparametrische "Logistikkurve" zu berechnen, die P[y | x] für binäres y wobei die nächsten Nachbarn von x . War überrascht, dass y als logical y gespeichert wurde, nicht automatisch in integer :

DT = data.table(x = rnorm(1000), y = runif(1000) > .5)
DT[order(x), .(x, p_y = frollmean(y, 50L))]

Fehler in froll(fun = "mean", x = x, n = n, fill = fill, algo = algo, align = ausrichten, :
x muss vom Typ numerisch sein

Ein Beispiel dafür, wie sich vektorisierte x / n Argumente auf die Leistung auswirken können.
https://github.com/AdrianAntico/RemixAutoML/commit/d8370712591323be01d0c66f34a70040e2867636#r34784427
weniger Schleifen, Code leichter zu lesen, viel schneller (10x-36x Geschwindigkeit).

frrollapply bereit: https://github.com/Rdatatable/data.table/pull/3600

    ### fun             mean     sum  median
    # rollfun          8.815   5.151  60.175
    # zoo::rollapply  34.373  27.837  88.552
    # zoo::roll[fun]   0.215   0.185      NA
    # frollapply       5.404   1.419  56.475
    # froll[fun]       0.003   0.002      NA

Hallo Leute, wird FUN (benutzerdefiniert) an frollapply übergeben, um ein R-Objekt oder data.frame (data.table) zurückzugeben, x an frollapply übergeben, könnte data.table mit Zeichen sein, das nicht in numerisch umgewandelt wird, dann könnte FUN weitermachen label und frrollapply eine Liste zurückgeben? dann können wir eine rollierende Regression oder rollierende Tests durchführen, wie beispielsweise Benfords Tests oder eine Zusammenfassung von Etiketten.

Es ist immer sinnvoll, ein reproduzierbares Beispiel zu liefern. Zur Verdeutlichung... in einem solchen Szenario möchten Sie frollapply(dt, 3, FUN) eine Liste der Länge nrow(dt) wobei jedes Listenelement data.table von FUN(dt[window]) ?
frollapply(x=dt, n=3, fun=FUN)[[3]] entspricht FUN(dt[1:3])
frollapply(x=dt, n=3, FUN=FUN)[[4]] entspricht FUN(dt[2:4])
Ist das korrekt? @jerryfuyu0104

Derzeit unterstützen wir mehrere Spalten, die an das erste Argument übergeben werden, aber wir verarbeiten sie separat, Schleifen. Wir bräuchten wahrscheinlich ein zusätzliches Argument multi.var=FALSE , wenn es auf true gesetzt ist, würde es nicht über x laufen (wie jetzt: list(FUN(x[[1]]),FUN(x[[2]])) ), sondern alle Spalten übergeben FUN(x) .

irgendein Update dafür?

Ich unterstütze diese vorherige Anfrage.

Wäre es außerdem möglich, ein "partielles" Argument zu unterstützen, um partielle Fenster zuzulassen?

@eliocamp könnten Sie partial Fenster ist?

@eliocamp wäre es möglich, "partielle" Argumente zu unterstützen. Sie wissen das vielleicht schon, aber die Unterstützung für diese Funktionalität ist bereits vorhanden, mit dem adaptive=TRUE Argument, siehe Beispiele für Details.

Es würde bedeuten, die Funktion von Anfang bis Ende zu berechnen, anstatt den halben Fensterpunkt zu bilden.
Bei einem rollierenden Mittelwert der Breite 11 wäre das erste zurückgegebene Element beispielsweise der Mittelwert der Elemente 1 bis 6. Das zweite der Mittelwert des 1. bis 7. usw.

@jangorecki oh, danke, das wusste ich nicht! Ich werde das überprüfen.

Stimmen Sie zu, wir brauchen teilweise Argumente, nicht nur aus Bequemlichkeit, sondern auch aus Gründen der Geschwindigkeit. adaptive=TRUE fügt einen Overhead hinzu.
Und ja, wir brauchen auch eine rollierende Regression, also die Bereitstellung mehrerer Variablen und deren gleichzeitige Rollierung, nicht jede einzeln.
Es gibt kein Update über den Status dieser.

Ich würde gerne helfen, aber meine C++-Kenntnisse sind absolut nicht vorhanden. :sweat: Denkst du, es könnte für absolute Neulinge geeignet sein?

Wir programmieren nicht in C++, sondern in C. Ja, es ist ein guter Anfang. Genau das habe ich auf Frollmean gemacht.

Ich schaue mir den Code an und es scheint entmutigend. Aber ich werde Sie auf jeden Fall aktualisieren.

Aber nun zu einer weiteren Anfrage: frollmean(.SD) sollte Namen beibehalten. Allgemeiner gesagt sollte froll* Namen beibehalten, wenn die Eingabe eine Liste mit Namen ist.

Als häufiger Benutzer von data.table finde ich es äußerst nützlich, "zeitbewusste" Funktionen zu haben, wie sie derzeit im Paket tsibble . Leider wurde dieses Paket um dplyr herum entwickelt. Ich frage mich, ob eine data.table-Implementierung möglich sein könnte. Die in dieser Ausgabe vorgeschlagenen Fensterfunktionen sind eine Teilmenge dieser Funktionen.

@ywhcuhk Danke für das Feedback, ich dachte eigentlich, dass dieses Problem bereits zu viel verlangt. Das meiste davon ist gut mit noch geringem Gewicht bedeckt Rolle , die sehr schnell ist. Was die anderen Funktionen angeht, schlage ich vor, für jede Funktion, an der Sie interessiert sind, eine neue Ausgabe zu erstellen, sodass die Diskussion, ob wir implementieren/pflegen möchten, für jede einzeln entschieden werden kann. Nur wenn ich mir die Readme-Datei von tstibble anschaue, sehe ich nichts Neues, das es bietet ...
Sein Titel ist "Tidy Temporal Data Frames", aber es scheint nicht einmal temporale Joins anzubieten.

Danke @jangorecki für die Antwort. Vielleicht ist es ein kontextabhängiges Problem. Die Datenstruktur, mit der ich mich am häufigsten beschäftige, ist als "Paneldaten" bekannt, mit einer ID und einer Uhrzeit. Wenn das Programm dieses Datenmerkmal "kennt", werden viele Operationen, insbesondere Zeitreihenoperationen, sehr einfach gemacht. Für jemanden, der STATA kennt, sind es die Operationen, die auf tsset und xtset basieren, wie Lead, Lag, Fill Gap usw. Ich denke, der "Index" in der data.table kann verbessert werden in irgendeiner Weise, um solche Operationen zu ermöglichen.

Natürlich können diese Operationen in data.table-Funktionen wie shift und by . Ich dachte nur, dass die index in data.table viel Potenzial haben, das erforscht werden muss. Ich stimme zu, dass dies zu einem anderen Thema gehören sollte. Aber ich weiß nicht, wie ich es verschieben soll, ohne die obigen Diskussionen zu verlieren ...

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen