Pandas: Rollfenster mit Schrittweite

Erstellt am 9. Feb. 2017  ·  38Kommentare  ·  Quelle: pandas-dev/pandas

Nur ein Vorschlag: Erweitern Sie rolling , um ein rollierendes Fenster mit einer Schrittweite zu unterstützen, wie z. B. rollapply(by=X) R.

Codebeispiel

Pandas - ineffiziente Lösung (Funktion auf jedes Fenster anwenden, dann aufschneiden, um jedes zweite Ergebnis zu erhalten)

import pandas
ts = pandas.Series(range(0, 40, 2))
ts.rolling(5).apply(max).dropna()[::2]

Anregung:

ts = pandas.Series(range(0, 40, 2))
ts.rolling(window=5, step=2).apply(max).dropna()

Inspiriert von R (siehe rollapply- Dokumente):

require(zoo)
TS <- zoo(seq(0, 40, 2))
rollapply(TS, 5, FUN=max, by=2)

8 12 16 20 24 28 32 36 40

Enhancement Needs Discussion Numeric Window

Hilfreichster Kommentar

"Dies könnte getan werden, aber ich würde gerne einen Anwendungsfall sehen, bei dem dies wichtig ist."

Egal an welchem ​​Projekt ich mit Pandas gearbeitet habe, ich habe diese Funktion fast immer vermisst, sie ist jedes Mal nützlich, wenn Sie die Anwendung nur ab und zu berechnen müssen, aber dennoch eine gute Auflösung in jedem Fenster benötigen.

Alle 38 Kommentare

Wenn Sie 'Standard'-Funktionen verwenden, sind diese vektorisiert und somit v schnell ( ts.rolling(5).max().dropna()[::2] ).

IIUC die Einsparung würde hier entstehen, wenn die Funktion nur in einem Bruchteil der Zeit angewendet wird (zB bei jedem n-ten Wert). Aber gibt es einen Fall, in dem das einen praktischen Unterschied macht?

Dies könnte getan werden, aber ich würde gerne einen Anwendungsfall sehen, bei dem dies wichtig ist. Dies würde auch die API "Gleiche Größe wie Eingabe zurückgeben" unterbrechen. Obwohl ich nicht glaube, dass dies wirklich schwer zu implementieren ist (obwohl es eine Reihe von Änderungen bei der Implementierung erfordern würde). Wir verwenden marginale Fenster (IOW, berechnen das Fenster und lassen Sie die verbleibenden Punkte ab und fügen Sie Punkte hinzu, die Sie gewinnen). Sie müssten also immer noch alles berechnen, aber Sie würden es einfach nicht ausgeben.

Danke für eure Antworten!

IIUC die Einsparung würde hier entstehen, wenn die Funktion nur in einem Bruchteil der Zeit angewendet wird (zB bei jedem n-ten Wert). Aber gibt es einen Fall, in dem das einen praktischen Unterschied macht?

Mein Anwendungsfall führt Aggregationsfunktionen (nicht nur max) über einige große Zeitreihen-Datenrahmen aus - 400 Spalten, Datenstunden bei 5-25 Hz. Ähnliches (Feature Engineering auf Sensordaten) habe ich in der Vergangenheit auch mit Daten bis 20 kHz gemacht. Das Ausführen von 30-Sekunden-Fenstern mit einem 5-Sekunden-Schritt spart einen großen Teil der Verarbeitung - z.

Ich kann natürlich auf numpy zurückgreifen, aber es wäre schön, wenn es dafür eine API auf höherer Ebene gäbe. Ich dachte nur, es wäre den Vorschlag wert, falls andere es auch nützlich finden würden - ich erwarte nicht, dass Sie ein Feature nur für mich entwickeln!

Sie können versuchen, zuerst auf ein höheres Frequenzintervall zu resamplimieren und dann zu rollen

etwas wie

df = df.resample('30s')
df.rolling(..).max() (oder welche Funktion auch immer)

Hey @jreback , danke für den Vorschlag.

Dies würde funktionieren, wenn ich nur max für meine Daten ausführen würde (Resample benötigt eine Reduktionsfunktion, sonst ist es standardmäßig mean , oder?):

df.resample('1s').max().rolling(30).max()

Ich möchte jedoch meine Reduktionsfunktion für 30 Sekunden Daten ausführen, dann 1 Sekunde vorwärts gehen und sie für die nächsten 30 Sekunden Daten ausführen usw. Die obige Methode wendet eine Funktion auf 1 Sekunde Daten an und dann eine weitere Funktion auf 30 Ergebnisse der ersten Funktion.

Hier ist ein kurzes Beispiel - das Ausführen einer Peak-to-Peak-Berechnung funktioniert nicht zweimal (offensichtlich):

# 10 minutes of data at 5Hz
n = 5 * 60 * 10
rng = pandas.date_range('1/1/2017', periods=n, freq='200ms')
np.random.seed(0)
d = np.cumsum(np.random.randn(n), axis=0)
s = pandas.Series(d, index=rng)

# Peak to peak
def p2p(d):
    return d.max() - d.min()

def p2p_arr(d):
    return d.max(axis=1) - d.min(axis=1)

def rolling_with_step(s, window, step, func):
    # See https://ga7g08.github.io/2015/01/30/Applying-python-functions-in-moving-windows/
    vert_idx_list = np.arange(0, s.size - window, step)
    hori_idx_list = np.arange(window)
    A, B = np.meshgrid(hori_idx_list, vert_idx_list)
    idx_array = A + B
    x_array = s.values[idx_array]
    idx = s.index[vert_idx_list + int(window/2.)]
    d = func(x_array)
    return pandas.Series(d, index=idx)

# Plot data
ax = s.plot(figsize=(12, 8), legend=True, label='Data')

# Plot resample then rolling (obviously does not work)
s.resample('1s').apply(p2p).rolling(window=30, center=True).apply(p2p).plot(ax=ax, label='1s p2p, roll 30 p2p', legend=True)

# Plot rolling window with step
rolling_with_step(s, window=30 * 5, step=5, func=p2p_arr).plot(ax=ax, label='Roll 30, step 1s', legend=True)

rolling window

@alexlouden aus deiner ursprünglichen beschreibung denke ich sowas wie

df.resample('5s').max().rolling('30s').mean() (oder welche Ermäßigungen auch immer) entspricht eher Ihren Wünschen

IOW, nehmen Sie alles, was sich in einem 5s-Bin befindet, reduzieren Sie es dann auf einen einzigen Punkt und rollen Sie dann über diese Bins. Diese allgemeine Idee ist, dass Sie viele Daten haben, die in kurzer Zeit zusammengefasst werden können, aber Sie möchten diese auf einer höheren Ebene veröffentlichen.

Hey @jreback , ich möchte eigentlich alle 5 Sekunden eine Funktion über 30 Sekunden Daten ausführen. Siehe die Funktion rolling_with_step in meinem vorherigen Beispiel. Der zusätzliche Schritt von max/mean funktioniert für meinen Anwendungsfall nicht.

@jreback , es besteht ein echter Bedarf für die Schrittfunktion, die in dieser Diskussion noch nicht herausgebracht wurde. Ich unterstütze alles, was @alexlouden beschrieben hat, aber ich möchte weitere Anwendungsfälle hinzufügen.

Angenommen, wir führen eine Zeitreihenanalyse mit Eingabedaten durch, die ungefähr 3 bis 10 Millisekunden abgetastet werden. Wir interessieren uns für Funktionen im Frequenzbereich. Der erste Schritt bei der Konstruktion besteht darin, die Nyquist-Frequenz herauszufinden. Angenommen durch Domänenwissen wissen wir, dass das 10 Hz beträgt (einmal alle 100 ms). Das heißt, die Daten müssen eine Frequenz von mindestens 20 Hz haben (einmal alle 50 ms), wenn die Features das Eingangssignal gut erfassen sollen. Wir können nicht auf eine niedrigere Frequenz resampeln. Letztendlich sind hier die Berechnungen, die wir durchführen:

df.resample('50ms').mean().rolling(window=32).aggregate(power_spectrum_coeff)

Hier haben wir eine Fenstergröße in Vielfachen von 8 gewählt, und wenn wir 32 wählen, beträgt die Fenstergröße 1,6 Sekunden. Die Aggregatfunktion gibt die einseitigen Frequenzbereichskoeffizienten und ohne die erste Mittelwertkomponente zurück (die fft-Funktion ist symmetrisch und mit einem Mittelwert am 0. Element). Es folgt die Beispiel-Aggregatfunktion:

def power_spectrum_coeff():
    def power_spectrum_coeff_(x):
        return np.fft.fft(x)[1 : int(len(x) / 2 + 1)]

    power_spectrum_coeff_.__name__ = 'power_spectrum_coeff'
    return power_spectrum_coeff_

Nun möchten wir dies in einem gleitenden Fenster von beispielsweise alle 0,4 Sekunden oder alle 0,8 Sekunden wiederholen. Es macht keinen Sinn, Berechnungen zu verschwenden und stattdessen alle 50 ms die FFT zu berechnen und dann später aufzuteilen. Darüber hinaus ist ein Resampling auf 400 ms keine Option, da 400 ms nur 2,5 Hz sind, was viel niedriger ist als die Nyquist-Frequenz, und dies führt dazu, dass alle Informationen aus den Funktionen verloren gehen.

Dies waren Funktionen im Frequenzbereich, die in vielen zeitreihenbezogenen wissenschaftlichen Experimenten Anwendung finden. Jedoch können auch einfachere Aggregatfunktionen im Zeitbereich wie die Standardabweichung nicht effektiv durch Resampling unterstützt werden.

Obwohl ich nicht glaube, dass dies wirklich schwer zu implementieren ist (obwohl es eine Reihe von Änderungen bei der Implementierung erfordern würde). Wir verwenden marginale Fenster (IOW, berechnen das Fenster und während Sie fortschreiten, lassen Sie die Punkte ab, die Sie verlassen und fügen Sie Punkte hinzu, die Sie gewinnen). Sie müssten also immer noch alles berechnen, aber Sie würden es einfach nicht ausgeben.

Den 'step'-Parameter zu haben und in der Lage zu sein, die tatsächlichen Berechnungen zu reduzieren, indem er ihn verwendet, muss das zukünftige Ziel von Pandas sein. Wenn der step-Parameter nur weniger Punkte zurückgibt, lohnt es sich nicht, da wir die Ausgabe sowieso schneiden können. Angesichts des damit verbundenen Aufwands empfehlen wir vielleicht allen Projekten mit diesen Anforderungen, Numpy zu verwenden.

@Murmuria können Sie dazu gerne einen Pull-Request einreichen. Es ist eigentlich nicht so schwer.

Während ich die Anfrage nach einem step Parameter in rolling() , möchte ich darauf hinweisen, dass es möglich ist das gewünschte Ergebnis mit dem base Parameter in resample() , wenn die Schrittweite ein ganzzahliger Bruchteil der Fenstergröße ist . Verwenden Sie das Beispiel von

pandas.concat([
    s.resample('30s', label='left', loffset=pandas.Timedelta(15, unit='s'), base=i).agg(p2p) 
    for i in range(30)
]).sort_index().plot(ax=ax, label='Solution with resample()', legend=True, style='k:')

Wir erhalten das gleiche Ergebnis (beachten Sie, dass die Linie auf beiden Seiten um 30 Sekunden verlängert wird):
rolling_with_step_using_resample

Dies ist je nach Art der Aggregation immer noch etwas verschwenderisch. Für den speziellen Fall der Spitze-zu-Spitze-Berechnung wie in @alexloudens Beispiel ist p2p_arr() fast 200x schneller, weil es die Reihe in eine 2D-Matrix umordnet und dann einen einzigen Aufruf von max() und min() .

Der Step-Parameter beim Rolling würde die Verwendung dieser Funktion auch ohne Datums-/Uhrzeitindex ermöglichen. Arbeitet schon jemand daran?

@alexlouden oben sagte dies:

Ich kann natürlich auf numpy zurückgreifen, aber es wäre schön, wenn es dafür eine API auf höherer Ebene gäbe.

Kann @alexlouden oder jemand anderes, der es weiß, bitte einen Einblick geben, wie man dies mit numpy macht? Nach meinen bisherigen Recherchen scheint es nicht trivial zu sein, dies auch in numpy zu tun. Tatsächlich gibt es hier ein offenes Problem https://github.com/numpy/numpy/issues/7753

Vielen Dank

Hallo @tsando - hat die Funktion rolling_with_step ich oben verwendet habe, bei dir nicht funktioniert?

@alexlouden danke, habe gerade diese Funktion überprüft und sie scheint immer noch von Pandas abzuhängen (nimmt eine Serie als Eingabe und verwendet auch den Serienindex). Ich habe mich gefragt, ob es einen rein numpy Ansatz gibt. In dem von mir erwähnten Thread https://github.com/numpy/numpy/issues/7753 schlagen sie eine Funktion vor, die numpy-Schritte verwendet, aber sie sind schwer zu verstehen und in Fenster- und Schritteingaben zu übersetzen.

@tsando Hier ist ein PDF des Blog- Posts, auf den ich oben verlinkt habe - es sieht so aus, als hätte der Autor seinen Github-Benutzernamen geändert und seine Site nicht wieder hochgeladen . (Ich habe es gerade lokal ausgeführt, um es in PDF zu konvertieren).

Meine obige Funktion war, dass ich gerade sein letztes Beispiel umwandelte, um mit Pandas zu arbeiten - wenn Sie numpy direkt verwenden wollten, könnten Sie Folgendes tun: https://gist.github.com/alexlouden/e42f1d96982f7f005e62ebb737dcd987

Hoffe das hilft!

@alexlouden danke! Ich habe es gerade mit einem Array der Form (13, 1313) ausprobiert, aber es gab mir diesen Fehler:

image

"Dies könnte getan werden, aber ich würde gerne einen Anwendungsfall sehen, bei dem dies wichtig ist."

Egal an welchem ​​Projekt ich mit Pandas gearbeitet habe, ich habe diese Funktion fast immer vermisst, sie ist jedes Mal nützlich, wenn Sie die Anwendung nur ab und zu berechnen müssen, aber dennoch eine gute Auflösung in jedem Fenster benötigen.

Ich stimme zu und unterstütze diese Funktion auch

Wird es fast jedes Mal benötigt, wenn es um Zeitreihen geht, könnte die Funktion eine viel bessere Kontrolle zum Generieren von Zeitreihenfunktionen sowohl für die Visualisierung als auch für die Analyse bieten. Unterstützen Sie diese Idee nachdrücklich!

stimme dieser Funktion zu und unterstütze sie auch

Dies wäre sehr hilfreich, um die Rechenzeit zu reduzieren und trotzdem eine gute Fensterauflösung beizubehalten.

Ich biete Ihnen einen Lösungscode, der weiter an Ihr spezielles Ziel angepasst werden kann.

def average_smoothing(signal, kernel_size, stride):
    sample = []
    start = 0
    end = kernel_size
    while end <= len(signal):
        start = start + stride
        end = end + stride
        sample.append(np.mean(signal[start:end]))
    return np.array(sample)

Ich stimme zu und unterstütze diese Funktion. Ich sehe, ist gerade in Stop-Motion.

Das Berechnen und anschließende Downsampling ist keine Option, wenn Sie TB an Daten haben.

Es wäre auch sehr hilfreich für das, was ich tue. Ich habe TB an Daten, für die ich verschiedene Statistiken von nicht überlappenden Fenstern benötige, um die lokalen Bedingungen zu verstehen. Mein aktuelles "Fix" besteht darin, nur einen Generator zu erstellen, der die Datenrahmen und die Ertragsstatistiken schneidet. Wäre sehr hilfreich diese Funktion zu haben.

Diese Funktion ist in der Tat ein Muss, wenn es um Zeitreihen geht!

Stimmen Sie zu, diese Funktion muss auf jeden Fall hinzugefügt werden. Ich versuche, laufende Fensterkorrelationen zwischen Aktienkursen durchzuführen und muss meine eigene Funktion dafür erstellen

Ich kann nicht glauben, dass es so eine grundlegende Funktion noch nicht gibt!
Wann wird dieses Problem gelöst?
Vielen Dank

Um zur "weiteren Diskussion" beizutragen:
Mein Anwendungsfall besteht darin, einen Min/Max/Median-Wert pro Stunde für einen Monat mit Daten mit einer Auflösung von 1 Sekunde zu berechnen. Es sind Energieverbrauchsdaten und es gibt Spitzen für 1-2 Sekunden, die ich beim Resampling verlieren würde. Abgesehen davon würde ein Resampling auf zB 5 Sekunden/1 Minute nichts daran ändern, dass ich immer noch 4k/1k Fenster pro Tag berechnen muss, die weggeworfen werden müssen, anstatt nur die benötigten 24 Fenster pro Tag berechnen zu können .

Es wäre möglich, dies zu umgehen, indem man groupby usw. verwendet, aber das scheint weder intuitiv noch so schnell zu sein wie die rollierende Implementierung (2 Sekunden für 2,5 Millionen Stunden lange Fenster mit Sortierung). Es ist beeindruckend schnell und nützlich, aber wir brauchen wirklich ein Schrittargument, um seine Leistung voll auszuschöpfen.

Ich habe mir das Problem angeschaut. Dies ist relativ trivial, aber die Art und Weise, wie der Code implementiert ist, wird bei einem flüchtigen Blick meiner Meinung nach erfordern, dass sich jemand durch die manuelle Bearbeitung aller rollenden Routinen quält. Keine von ihnen respektiert die Fenstergrenzen, die von den Indexerklassen vorgegeben werden. Wenn ja, wäre sowohl diese Anfrage als auch #11704 sehr leicht lösbar. Auf jeden Fall finde ich es überschaubar für jeden, der etwas Zeit damit verbringen möchte, Dinge aufzupolieren. Ich initiierte eine unausgegorene PR (wird voraussichtlich abgelehnt, nur für einen MVP), um zu zeigen, wie ich das Problem angehen würde.

Laufen:

import numpy as np
import pandas as pd

data = pd.Series(
    np.arange(100),
    index=pd.date_range('2020/05/12 12:00:00', '2020/05/12 12:00:10', periods=100))

print('1s rolling window every 2s')
print(data.rolling('1s', step='2s').apply(np.mean))

data.sort_index(ascending=False, inplace=True)

print('1s rolling window every 500ms (and reversed)')
print(data.rolling('1s', step='500ms').apply(np.mean))

ergibt

1s rolling window every 2s
2020-05-12 12:00:00.000000000     4.5
2020-05-12 12:00:02.020202020    24.5
2020-05-12 12:00:04.040404040    44.5
2020-05-12 12:00:06.060606060    64.5
2020-05-12 12:00:08.080808080    84.5
dtype: float64
1s rolling window every 500ms (and reversed)
2020-05-12 12:00:10.000000000    94.5
2020-05-12 12:00:09.494949494    89.5
2020-05-12 12:00:08.989898989    84.5
2020-05-12 12:00:08.484848484    79.5
2020-05-12 12:00:07.979797979    74.5
2020-05-12 12:00:07.474747474    69.5
2020-05-12 12:00:06.969696969    64.5
2020-05-12 12:00:06.464646464    59.5
2020-05-12 12:00:05.959595959    54.5
2020-05-12 12:00:05.454545454    49.5
2020-05-12 12:00:04.949494949    44.5
2020-05-12 12:00:04.444444444    39.5
2020-05-12 12:00:03.939393939    34.5
2020-05-12 12:00:03.434343434    29.5
2020-05-12 12:00:02.929292929    24.5
2020-05-12 12:00:02.424242424    19.5
2020-05-12 12:00:01.919191919    14.5
2020-05-12 12:00:01.414141414     9.5
2020-05-12 12:00:00.909090909     4.5
dtype: float64

Details zur Umsetzung finden Sie in der PR (oder hier: https://github.com/anthonytw/pandas/tree/rolling-window-step)

Obwohl ich gerne mehr Zeit damit verbracht hätte, es fertig zu stellen, habe ich leider keine mehr übrig, um die gruselige Arbeit der Überarbeitung aller Rollfunktionen in Angriff zu nehmen. Meine Empfehlung für jeden, der dies angehen möchte, wäre, die von den Indexerklassen generierten Fenstergrenzen zu erzwingen und die rolling_*_fixed/variable-Funktionen zu vereinheitlichen. Bei Start- und Endgrenzen sehe ich keinen Grund, warum sie unterschiedlich sein sollten, es sei denn, Sie haben eine Funktion, die mit ungleichmäßig abgetasteten Daten etwas Besonderes macht (in diesem Fall wäre diese spezielle Funktion besser in der Lage, die Nuance zu verarbeiten, also vielleicht eine Flagge setzen oder so).

Funktioniert dies auch für ein benutzerdefiniertes Fenster mit dem get_window_bounds() Ansatz?

Hallo zusammen, ich bitte auch den Vorschlag. Dies wäre eine wirklich nützliche Funktion.

Wenn Sie 'Standard'-Funktionen verwenden, sind diese vektorisiert und somit v schnell ( ts.rolling(5).max().dropna()[::2] ).

IIUC die Einsparung würde hier entstehen, wenn die Funktion nur in einem Bruchteil der Zeit angewendet wird (zB bei jedem n-ten Wert). Aber gibt es einen Fall, in dem das einen praktischen Unterschied macht?

Ich habe hier so ein Beispiel: https://stackoverflow.com/questions/63729190/pandas-resample-daily-data-to-annual-data-with-overlap-and-offset

Jeder N. wäre jeder 365. Die Fenstergröße ist während der Lebensdauer des Programms variabel und es kann nicht garantiert werden, dass der Schritt ein ganzzahliger Bruchteil der Fenstergröße ist.

Ich benötige im Grunde eine festgelegte Fenstergröße, die in Schritten von "Anzahl der Tage im betrachteten Jahr" angezeigt wird, was mit jeder Lösung, die ich bisher für dieses Problem gefunden habe, unmöglich ist.

Ich habe auch einen ähnlichen Bedarf mit folgendem Kontext (adaptiert aus einem realen und beruflichen Bedarf):

  • Ich habe einen chronologischen Datenrahmen mit einer Zeitstempelspalte und einer Wertespalte, die unregelmäßige Ereignisse darstellt. Wie der Zeitstempel, als ein Hund unter meinem Fenster vorbeikam und wie viele Sekunden sie brauchte, um vorbeizukommen. Ich kann für einen bestimmten Tag 6 Ereignisse haben und dann für die nächsten 2 Tage überhaupt kein Ereignis
  • Ich möchte eine Metrik (sagen wir die durchschnittliche Zeit, die Hunde vor meinem Fenster verbringen) mit einem rollierenden Fenster von 365 Tagen berechnen, das alle 30 Tage rollen würde

Soweit ich weiß, erlaubt mir die dataframe.rolling() API, die Dauer von 365 Tagen anzugeben, aber nicht die Notwendigkeit, 30 Tage mit Werten zu überspringen (was eine nicht konstante Anzahl von Zeilen ist), um den nächsten Mittelwert über einen anderen zu berechnen Auswahl von 365-Tage-Werten.

Offensichtlich wird der resultierende Datenrahmen, den ich erwarte, eine (viel) kleinere Anzahl von Zeilen haben als der anfängliche Datenrahmen "Hundeereignisse".

Nur um mit einem einfachen Beispiel mehr Klarheit über diese Anfrage zu bekommen.

Wenn wir diese Serie haben:

In [1]: s = pd.Series(range(5))

In [2]: s
Out[2]:
0    0
1    1
2    2
3    3
4    4
dtype: int64

und wir haben eine Fenstergröße von 2 und eine Schrittgröße von 1 . Dieses erste Fenster bei Index 0 würde ausgewertet, über das Fenster bei Index 1 , das Fenster bei Index 2 auswerten usw.?

In [3]: s.rolling(2, step=1, min_periods=0).max()

Out[3]:
0    0.0
1    NaN # step over this observation
2    2.0
3    NaN # step over this observation
4    4.0
dtype: float64

Ebenso wenn wir diese zeitbasierte Serie haben

In [1]: s = pd.Series(range(5), index=pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-06', '2020-01-09']))

In [2]: s
Out[2]:
2020-01-01    0
2020-01-02    1
2020-01-03    2
2020-01-06    3
2020-01-09    4
dtype: int64

und wir haben eine Fenstergröße von '3D' und eine Schrittgröße von '3D' . Wäre das das richtige Ergebnis?

In [3]: s.rolling('3D', step='3D', min_periods=0).max()

Out[3]:
2020-01-01    0.0       # evaluate this window
2020-01-02    NaN    # step over this observation (2020-01-01 + 3 days > 2020-01-02)
2020-01-03    NaN    # step over this observation (2020-01-01 + 3 days > 2020-01-03)
2020-01-06    3.0      # evaluate this window ("snap back" to this observation)
2020-01-09    4.0      # evaluate this window (2020-01-06 + 3 days = 2020-01-09)
dtype: float64

@mroeschke zum ersten Beispiel ([3]), die Ergebnisse sind nicht das, was ich erwarten würde. Ich gehe davon aus, dass dies ein nachfolgendes Fenster ist (z. B. bei Index = 0 wäre es das Maximum der Elemente bei -1 und 0, also nur max ([0]), dann sollte es einen "1"-Index vorwärts zu Index = 0 setzen +step=1, und die nächste Berechnung wäre max([0,1]), dann max([1,2]) usw. Was Sie anscheinend haben wollten, war eine Schrittgröße von zwei, also würden Sie gehe von index=0 zu index=0+2=2 (überspringe den Index 1) und fahre so fort. In diesem Fall ist es fast richtig, aber es sollte keine NaNs geben. Obwohl es in diesem Fall "nur" doppelt so groß sein kann In anderen Fällen ist es erheblich. Zum Beispiel habe ich etwa eine Stunde mit 500 Hz EKG-Daten für einen Patienten, das sind 1,8 Millionen Abtastwerte. Wenn ich alle zwei Minuten einen 5-Minuten-gleitenden Durchschnitt haben wollte, wäre das ein Array von 1,8 Millionen Elemente mit 30 gültigen Berechnungen und etwas weniger als 1,8 Millionen NaNs. :-)

Für die Indizierung ist Schrittgröße = 1 das aktuelle Verhalten, dh das interessierende Merkmal unter Verwendung von Daten im Fenster berechnen, das Fenster um eins verschieben und dann wiederholen. In diesem Beispiel möchte ich das interessierende Merkmal anhand der Daten im Fenster berechnen, dann um 60.000 Indizes verschieben und dann wiederholen.

Ähnliche Bemerkungen für die Zeit. In diesem Fall gibt es möglicherweise einige Unstimmigkeiten bezüglich der richtigen Implementierung dieses Fenstertyps, aber meiner Meinung nach besteht der "beste"(TM) Weg darin, ab dem Zeitpunkt t0 alle Elemente im Bereich zu finden (t0-window , t0], berechne das Feature und bewege dich dann um die Schrittgröße. Werfen Sie alle Fenster weg, die weniger als die minimale Anzahl von Elementen haben (kann konfigurierbar sein, Standardwert 1). Dieses Beispiel gilt für ein nachfolgendes Fenster, aber Sie können es ändern an jede Fensterkonfiguration anzupassen. Dies hat den Nachteil, dass in großen Lücken Zeit verschwendet wird, aber Lücken können intelligent gehandhabt werden und selbst wenn Sie naiv rechnen (weil Sie wie ich faul sind), habe ich diese Angelegenheit noch in der Praxis gesehen , da die Lücken normalerweise nicht groß genug sind, um in echten Daten eine Rolle zu spielen.

Vielleicht ist das klarer? Schauen Sie sich mein Beispiel + Code oben an, der es vielleicht besser erklärt.

Danke für die Klarstellung @anthonytw. Tatsächlich sieht es so aus, als müsste ich step als "Schritt zum Punkt" interpretieren.

Was die NaNs angeht, verstehe ich die Gefühle, die NaNs automatisch im Ausgabeergebnis zu löschen , aber wie in https://github.com/pandas-dev/pandas/issues/15354#issuecomment -278676420 von @jreback erwähnt , gibt es eine API-Konsistenzüberlegung, damit die Ausgabe dieselbe Länge wie die Eingabe hat. Es mag Benutzer geben, die die NaNs auch behalten möchten (vielleicht?), und dropna wäre nach der Operation rolling(..., step=...).func() noch verfügbar.

@mroeschke Ich denke, Ausnahmen sollten gemacht werden. Solange Sie einen expliziten Hinweis in die Dokumentation einfügen und das Verhalten nicht standardmäßig ist, wird niemand beeinträchtigt, wenn kein Vektor voller Müll zurückgegeben wird. Das Halten von NaNs verfehlt den halben Zweck. Ein Ziel besteht darin, die Anzahl der Durchführungen einer teuren Berechnung zu begrenzen. Das andere Ziel besteht darin, den Funktionsumfang auf ein überschaubares Maß zu minimieren. Dieses Beispiel, das ich Ihnen gegeben habe, ist real und nicht annähernd so viele Daten, wie man wirklich in einer Patientenüberwachungsanwendung verarbeiten muss. Ist es wirklich notwendig, 60000x den erforderlichen Speicherplatz zuzuweisen und dann das Array zu durchsuchen, um NaNs zu löschen? Für jedes Merkmal, das wir berechnen möchten?

Beachten Sie, dass eine Berechnung ein Array von Werten erzeugen kann. Was möchte ich mit einer EKG-Kurve machen? Berechnen Sie natürlich das Leistungsspektrum! Ich muss also genügend Speicherplatz für 1 vollständigen PSD-Vektor (150.000 Elemente) 1,8 Millionen Mal (2 TB Daten) zuweisen und dann durchfiltern, um die Teile zu erhalten, die mir wichtig sind (34 MB). Für alle Serien. Für alle Patienten. Ich glaube, ich muss mehr RAM kaufen!

Es ist auch erwähnenswert, dass NaN für einige Funktionen eine sinnvolle Ausgabe sein könnte. In diesem Fall kann ich den Unterschied zwischen einem sinnvollen NaN und den Junk-NaNs, die die Daten auffüllen, nicht mehr erkennen.

Obwohl ich den Wunsch verstehe, die API beizubehalten, ist dies keine Funktion, die bestehenden Code bricht (da es sich um eine neue Funktion handelt, die es zuvor nicht gab), und angesichts der Funktionalität gibt es keinen Grund, warum jemand erwarten würde, dass sie eine Ausgabe gleicher Größe. Und selbst wenn, genügt ein Hinweis in der Dokumentation zur Schrittweite. Die Nachteile überwiegen bei weitem alle Vorteile einer "konsistenten" API (für eine Funktion, die es vorher nicht gab, wohlgemerkt). Wenn Sie nicht auf diese Weise vorgehen, wird das Feature lahmgelegt, es lohnt sich in diesem Fall fast nicht einmal, es zu implementieren (meiner Erfahrung nach sind die Platzkosten fast immer der größere Faktor).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen