Wie pandas Rollen-Objekte arbeiten?
Edit: ich kondensierten dieser Frage gegeben, dass es wohl zu sehr involviert, um mit zu beginnen. Das Fleisch der Frage in Fett unten.
Ich würde gerne wissen, mehr über das Objekt, das tatsächlich erstellt, wenn Sie DataFrame.rolling
oder Series.rolling
:
print(type(df.rolling))
<class 'pandas.core.window.Rolling'>
Etwas hintergrund: betrachten Sie die oft verwendete alternative mit np.as_strided
. Dieses code-snippet selbst ist nicht wichtig, aber Ihr Ergebnis ist mein Bezugspunkt, diese Frage zu stellen.
def rwindows(a, window):
if a.ndim == 1:
a = a.reshape(-1, 1)
shape = a.shape[0] - window + 1, window, a.shape[-1]
strides = (a.strides[0],) + a.strides
windows = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
return np.squeeze(windows)
Hier rwindows
wird eine 1d-oder 2d - ndarray
- und build-rolling "Blöcke" gleich der angegebenen Größe der Fenster (wie unten). Wie funktioniert ein .rolling
Objekt zu vergleichen, um die ndarray
Ausgabe unten? Ist es ein iterator, mit bestimmten gespeicherten Attribute für jeden block? Oder etwas ganz anderes? Ich habe versucht, das Spiel mit der tab-Taste auf das Objekt mit Attributen/Methoden wie __dict__
und _get_index()
und Sie ' re nicht zu sagen mir viel. Ich habe auch gesehen, ein _create_blocks
Methode in der pandas-ist es überhaupt ähneln die strided
Methode?
# as_strided version
a = np.arange(5)
print(rwindows(a, 3)) # 1d input
[[0 1 2]
[1 2 3]
[2 3 4]]
b = np.arange(10).reshape(5,2)
print(rwindows(b, 4)) # 2d input
[[[0 1]
[2 3]
[4 5]
[6 7]]
[[2 3]
[4 5]
[6 7]
[8 9]]]
Teil 2, extra credit
Mit Hilfe der NumPy-Ansatz oben (OLS Umsetzung hier) ist notwendig durch die Tatsache, dass func
innerhalb pandas.core.Fenster.Ins Rollen.bewerben muss
produzieren einem einzigen Wert aus einer ndarray-Eingang *args und **kwargs sind
an die Funktion übergeben
Also das argument kann nicht sein, ein anderes Rollen-Objekt. I. e.
def prod(a, b):
return a * b
df.rolling(3).apply(prod, args=((df + 2).rolling(3),))
-----------------------------------------------------------------------
...
TypeError: unsupported operand type(s) for *: 'float' and 'Rolling'
Also das ist wirklich, wo meine Frage oben stammt. Warum ist es, dass die übergebene Funktion muss ein NumPy-array und erzeugen einen einzelnen skalaren Wert, und was hat das zu tun mit der Gestaltung einer .rolling
Objekt?
- Ich denke, diese Frage ist zu weit gefasst und sollte genauer sein, ohne die Verzweigung in mehrere Fragen
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich schlage vor, Sie haben einen Blick auf den source-code, um zu bekommen, in die nitty gritty der was Rollen hat. Insbesondere schlage ich vor, Sie haben einen Blick auf die
rolling
Funktionen in generic.py und window.py. Von dort können Sie einen Blick auf dieWindow
Klasse, die verwendet wird, wenn Sie ein Fenster-Typ oder der Standard -Rolling
Klasse. Die Letzte erbt von_Rolling_and_Expanding
und letztlich_Rolling
und_Window
.Sagte, ich gebe meine zwei Cent: Pandas " ganze rolling-Mechanismus stützt sich auf die numpy-Funktion
apply_along_axis
. Insbesondere es wird verwendet, hier in pandas. Es ist verwendet in Verbindung mit derwindows.pyx
cython-Modul. In geht Ihrer Serie, heraus kommt die aggregierten rollenden Fenster. Für typische Aggregatfunktionen verarbeitet Sie für Sie effizient, aber für eigene diejenigen (mitapply()
) verwendet es eineroll_generic()
inwindows.pyx
.Die Rollen-Funktion in pandas betreibt auf pandas-Daten-frame-Spalten unabhängig voneinander. Es ist nicht eine python-iterator, und faul ist geladen, was bedeutet, nichts berechnet, bis Sie sich ein aggregation-Funktion. Die Funktionen, die tatsächlich gelten die rolling window-Daten nicht verwendet werden, bis rechts, bevor eine aggregation durchgeführt.
Einer Quelle der Verwirrung könnte sein, dass Sie denken von die rollenden Objekt als dataframe. (Sie haben den Namen des Rollen-Objekts
df
in deinem letzten code-snippet). Es ist wirklich nicht. Es ist ein Objekt produzieren kann dataframes durch die Anwendung von Aggregationen über das Fenster-Logik, die es beherbergt.Lambda versorgen Sie angewendet wird für jede Zelle Ihres neuen dataframe. Es dauert ein Fenster nach hinten (entlang jeder Spalte) in Ihrer alten dataframe, und es Aggregate, die es einer einzelnen Zelle in der neuen dataframe. Die aggregation kann Dinge wie
sum
,mean
etwas Gewohnheit, die Sie gemacht haben, usw., über einige Fenster-Größe, sagen wir 3. Hier sind einige Beispiele:... die können auch erfolgen durch:
... und produziert:
(Die erste Spalte ist der index-Wert und kann ignoriert werden, hier und für die folgenden Beispiele.)
Beachten Sie, wie wir lieferten eine vorhandene numpy-aggregation-Funktion. Das ist die Idee. Wir sollen in der Lage sein zu liefern, was wir wollen, solange es passt zu dem, was die aggregation-Funktionen haben, d.h., nehmen Sie einen Vektor, der die Werte und erzeugen einen einzelnen Wert aus. Hier ist noch eins wo wir Sie erstellen Sie eine benutzerdefinierte Aggregatfunktion in diesem Fall die L2-norm des Fensters:
wenn Sie nicht vertraut sind mit lambda-Funktionen, das ist das gleiche wie:
... nachgeben:
Nur um sicher zu gehen, können wir es manuell überprüfen, dass
np.sqrt(0**2 + 1**2 + 2**2)
ist in der Tat2.236068
.[In Ihrer ursprünglichen Bearbeiten, in der letzten code-snippet, Ihr code ist wahrscheinlich scheitern früh, als Sie erwarten. Es nicht vor dem Aufruf von
df.apply(...)
Sie versuchen, hinzufügen, ein rollendes Objekt mit dem Namendf
die Nummer 2, bevor es übergeben wird, umdf.apply(...)
. Das rollende Objekt, ist nicht etwas, was Sie tun, Operationen auf. Die aggregation-Funktion, die Sie geliefert haben, auch nicht entsprechen, wird eine Aggregatfunktion im Allgemeinen. Diea
ist eine Liste mit den Werten des Fensters, derb
würde eine ständige zusätzlichen parameter, den Sie übergeben. Es kann ein Rollen-Objekt, wenn Sie wollen, aber wäre es nicht in der Regel etwas, was Sie gerne tun würden. Um es klar, hier ist etwas, das ähnlich ist zu, was Sie Taten, in der ursprünglichen Bearbeiten, aber Sie funktioniert:Es ist ein erfundenes Beispiel, aber ich zeige es um den Punkt, dass Sie übergeben können, was Sie wollen, als eine Konstante, auch das rollende Objekt, das Sie mit sich selbst. Der dynamische Teil ist das erste argument
a
in Ihrem Fall oderwindow_list
in meinem Fall. Alle definierten Fenster, in form von individuellen Listen übergeben werden, die Funktion eins nach dem anderen.Basierend auf Ihrem weiteren Kommentaren dieser könnte das sein, was du suchst:
fügt arrays/Vektoren zu jedem Wälzlager block so produzieren:
Beachten Sie, dass es nur funktioniert, wenn Sie tun es auf eine Spalte zu einem Zeitpunkt. Wenn Sie wollen, um einige der Mathematik auf die Fenster, bevor Sie speichern es Weg
keep
das ist gut so.Sagte, ohne mehr input, was genau Sie versuchen zu erreichen, es ist schwer zu konstruieren, ein Beispiel, das zu Ihren Bedürfnissen passt.
Wenn Ihr Ziel ist, erstellen Sie einen dataframe in den rückständigen Variablen dann würde ich eher mit echten Spalten mit
shift()
:... geben:
(Möglicherweise gibt es einige schöner Weg, es zu tun, aber es bekommt den job zu erledigen.)
Hinsichtlich Ihrer Variablen
b
in deinem ersten code-snippet, erinnern DataFrames in pandas sind in der Regel nicht so gehandhabt, wie Tensoren beliebiger Abmessungen/Objekt. Wahrscheinlich können Sie Sachen, was auch immer Sie wollen, aber letztendlich strings, Zeit-Objekte, ints und floats ist, was erwartet wird. Das könnten die Gründe sein die Designer der pandas nicht die Mühe gemacht haben mit dem rolling-aggregation für nicht-Skalare Werte. Sie nicht sogar scheinen, wie eine einfache Zeichenfolge zulässig ist, als Ausgang der aggregation-Funktion.Sowieso, ich hoffe, das beantwortet einige deiner Fragen. Wenn nicht, lassen Sie mich wissen, und ich werde versuchen, Ihnen zu helfen, in den Kommentaren, oder ein update.
Letzte Hinweis auf die
_create_blocks()
Funktion der rollende Gegenstände.Den
_create_blocks()
Funktion übernimmt die re-Indizierung und Klasseneinteilung, wenn Sie diefreq
argumentrolling
.Wenn Sie freq mit, sagen wir, Wochen, so dass
freq=W
:... dann bekommen wir die eingeteilten (nicht Rollen) original-Daten Woche für Woche:
Beachten Sie, dass dies nicht die Ausgabe der aggregierten Rollen. Das ist einfach die neuen Blöcke, wie Sie funktioniert. Nach dieser. Wir machen eine aggregation wie
sum
und erhalten:... die Check-out mit einer test-Summierung: 50 = 2 + 9 + 16 + 23.
Wenn Sie nicht
freq
als argument, es gibt einfach die original-Daten-Struktur:... die produziert ...
... und ist für Rollen Fenster-aggregation.
(df + 2).rolling(3)
, das ist ein rollendes Objekt, in die der aggregation-Funktion wie eine Konstante, die dann versuche zu tun, Arithmetik (*) zwischen Fenster-Daten (float64 ndarray) und die neue rolling-Objekt. Rollende Gegenstände sind nur helper-Objekte, Sie sind eigentlich nicht zu tun, Operationen auf Ihnen, andere als Aggregationen. Es ist eindf
- Objekt-Fabrik, wenn das Sinn macht.[0, 1, 2, 3, 4]
: wollen Sie produzieren so etwas wie[[0, 1, 2] * 2, [1, 2, 3] * 3, [2, 3, 4] * 4]
? Wenn ja, können Sie es durchdef prod(a): return myagg(a * a[-1])
= das Fenster mal das Letzte element aus dem Fenster. Aber wie ich schon sagte, haben Sie immer noch zu aggregieren über dem Fenster, d.h., ersetzenmyagg
mit der Summe, oder bedeuten, oder so etwas. Die Ausgabe der Rollen ist immer ein einzelner Wert. Mitsum
stattmyagg
erhalten Sie[sum(0,2,4), sum(3,6,9), sum(8,12,16)]
=[6, 18, 36]
.rolling
Objekt inargs=(rol,)
ist hilfreich, aber leider sind die meisten Ihrer Antwort bekräftigte die Dinge, die ich bereits kannte. Aber was ich letztendlich wie man ist, um zu produzieren ein Spalten-Vektor (und dann transponieren), oder ein Zeilen-Vektor, der für jeden rolling-block, sondern als eine einzige Skalare. Aber es sieht aus wie es gibt keinen Weg daran vorbei, dass direkt.a
in Ihremprod(a, b)
aggregation Funktion. Fragen Sie sich, was ist der nächste Schritt. Was wollen Sie tun, mit der inneren Vektoren, die Sie produzieren mit Rollen? In der Regel wäre, zu aggregieren gewisser Weise. Wenn Sie einfach wollen halten Sie Sie, dann können Sie meineshift(...)
Beispiel. Dort erhalten Sie die Fenster und/oder Vektor, die als Zeilen, Spaltena
,a-1
, unda-2
im Beispiel._create_blocks
? Dies ist der Kern meiner Frage. Zum Beispiel, wenn ichblocks, obj, index == df.rolling(window=2)._create_blocks(how=None)
die resultierendeblocks
ist nicht das, was ich erwarte. (Es scheint, zurückzukehren, nur in der ursprünglichendf
.) Dablocks
geschlungen ist, über in die code, auf die Sie verlinkten, würde ich erwarten, dass es zu enthalten, die die Sammlung von verschiedenen "Fenster" Blöcke.freq
argumentrolling()
, zusätzlich zum auswählen der Spalte für die aggregation bei Verwendung deron
argumentrolling()
. Ich füge einen Hinweis auf Sie am Ende der Antwort.apply()
. Es ist eine cython-Funktion mit dem Namenroll_generic()
. Es gibt nichts gutes, auf der Suche über ihn, d.h., es ist ziemlich low-level-code. Es gleitet über Ihre Serie mit Indizes und wendet die Aggregatfunktion auf den Fenstern.