Iteration über Pandas Dataframe

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Servus Forum,

es stellte sich mir die Frage wie ich in einem Pandas DataFrame einen Vergleich erstelle, der jeweils die drei aufeinanderfolgenden Zeilen einer Spalte miteinander vergleicht.

Ich habe hierzu in zahlreichen Internetseiten gelesen, dass man keine for Schleife, oder die iterrows Funktion verwenden
sollte, da diese sehr langsam sind.
Es sollte eher eine Vektorisierung angestrebt werden.

Wie würde soetwas umgesetzt werden?
Ich habe mich mit der Vektorisierung noch nie beschäftigt und habe auch noch keinen passenden Eintrag gefunden,
der mir eine gute Erklärung geliefert hat.

LG
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie vergleicht man drei Zahlen miteinander?
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Es geht wie anstelle einer for Schleife dies in ein Vektorisierung umgesetzt wird
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Mach doch mal ein Beispiel, dass wir sehen können, was Du machen möchtest.
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

ich habe folgenden DataFrame

Code: Alles auswählen

import pandas as pd

jahrestemperatur = pd.DataFrame({"Datum": ["01.01.1900", "01.01.1910","01.01.1920","01.01.1930","01.01.1940","01.01.1950","01.01.1960"], 
"Temperatur": [-12, -3, -25, -8, 0, 3, -16]})

	Datum	Temperatur
0	01.01.1900	-12
1	01.01.1910	-3
2	01.01.1920	-25
3	01.01.1930	-8
4	01.01.1940	0
5	01.01.1950	3
6	01.01.1960	-16
Jetzt möchte ich über den DataFrame iterieren und jeweils drei aufeinanderfolgende Jahre vergleichen, ob die Temperatur gestiegen ist.
Im Internet ist zu lesen, dass man die Funktion iterrows(), oder eine for Schleife nicht verwenden soll, da diese sehr langsam sind.
Bei 7 Zeilen ist dies zwar egal, aber was mache ich, wenn es sich um 7000, oder noch mehr Zeilen handelt?

LG
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hartmannsgruber: Also willst Du da mit einem Fenster drüber gehen? https://pandas.pydata.org/docs/user_guide/window.html
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du zwei Temperaturen vergleichen willst, dann gibt es `diff`:

Code: Alles auswählen

jahrestemperatur['Temperatur'].diff()
Wenn der Wert >0 ist, dann steigt die Temperatur, sonst fällt die Temperatur.
Wie sieht diese Operation bei drei Werten aus?
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Als Ansatzpunkt:

Code: Alles auswählen

#!/usr/bin/env python3
import pandas as pd


def is_strictly_increasing(data):
    return data.is_monotonic_increasing and data.is_unique


def main():
    jahrestemperatur = pd.DataFrame(
        {
            "Datum": [
                "01.01.1900",
                "01.01.1910",
                "01.01.1920",
                "01.01.1930",
                "01.01.1940",
                "01.01.1950",
                "01.01.1960",
            ],
            "Temperatur": [-12, -3, -25, -8, 0, 3, -16],
        }
    )
    print(jahrestemperatur.rolling(3).agg(is_strictly_increasing) > 0)


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

0    False
1    False
2    False
3    False
4     True
5     True
6    False
Name: Temperatur, dtype: bool
Die ersten beiden sind `False` weil da das Ergebnis mit NaN vorbelegt ist, und ab da ist es immer `True` wenn die beiden vorhegehenden und der aktuelle Wert strikt monoton steigend sind, und `False` andernfalls.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Mit den beiden Lösungen sollte das Problem gelöst sein.

Ich habe aber jetzt mal eine ganz andere Frage.
Woher wisst Ihr (__blackjack__, Sirius3) so viel über Python, (egal welches Gebiet, ob GUI, Allgemein, Datenbanken, oder jetzt Datenanalyse).
Macht Ihr dies Hauptberuflich, oder woher habt Ihr dieses umfangreich Wissen?
Allein die Pandas Bibliothek ist ja so umfangreich, woher weiß man da welche Funktionen es überhaupt gibt?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Für Pandas gibt es eine gute Dokumentation. Wenn man die richtigen Stichworte kennt, findet man da relativ schnell, welche Funktion wie zu benutzen ist.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hartmannsgruber: Ganz allgemein Erfahrung. Geboren wird man mit dem Wissen ja leider nicht. 🙂 Und dann ist das Stichwort was Sirius3 ja schon genannt hat: Stichworte. Das Konzept so eines Teilbereichs den man über eine Folge von Werten schiebt, heisst nicht nur bei Pandas „window“/„rolling window“ oder so ähnlich. Wo ich den Begriff das erste mal gehört habe, kann ich nicht sagen, aber ich kannte den vor Pandas schon, und auch schon bevor ich den in verschiedenen anderen Kontexten gesehen habe, beispielsweise Funktionen bei Datenbanken die unter der Überschrift „window functions“ in dokumentiert sind. Jedes mal wenn man das Konzept im Zusammenhang mit dem Begriff „window“ sieht, verankert sich das fester, dass man das als Stichwort parat hat, wenn man so etwas (wieder) braucht.

Und dann ist es naheliegend auch bei Bibliotheken die man noch nicht kennt, auch nach diesem Stichwort zu suchen, wenn man so eine Funktionalität sucht. Entweder in der Dokumentation der Bibliothek direkt, oder wenn man da nicht fündig wird, weil die das vielleicht anders nennen, im Netz nach „window functions for <bibliotheksname>“ zu suchen. Oder allgemein „<konzeptname> for <bibliotheksname>“. Das hilft oft auch wenn man den Namen eines ähnlichen Konzepts kennt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Wenn man sich über die Jahre ein gutes "Stichwortverzeichnis" im Kopf zurechtlegt hat dies demnach enorme Vorteile im weiteren Umgang mit anderen Bibliotheken und co.
Der Erfahrungswert ist wohl hier wie auch in jeder anderen Branchen unschlagbar.

Eine letzte Frage hätte ich aber noch.
Das mit dem Fenstern habe ich mir gemerkt und auch schon nachgeschlagen.
Wie greift man aber auf einzelne Indexwerte eines solchen Fensters zu?
Mir scheint es so, als würde hier das Fenster immer nur im Ganzen bearbeitet werden.

Also in etwa so:

Code: Alles auswählen

jahrestemperatur.rolling(3)[0] < jahrestemperatur.rolling(3)[1] > jahrestemperatur.rolling(3)[2] 
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hartmannsgruber: `rolling()` ist noch kein Fenster, sondern ein Objekt das die Fenster ”liefert”. Zum Beispiel an eine Funktion die man wie in meinem Beispiel an die `agg()`-Methode übergibt. Die Funktion bekommt `DataFrame`-Objekte. Und der Rückgabewert landet dann als Ergebnis in einem `Series`-Objekt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Nehmen wir das genannte Beispiel.
Es wird nun eine Funktion in .agg aufgerufen.
In dieser Funktion soll nun auf die einzelnen Indizes zugreifen.

Es taucht dann der Fehler auf, dass [0] nicht gefunden wird was ja verständlich ist,
da nach dem ersten Aufruf der Index 0 nicht mehr dabei ist.

Code: Alles auswählen

#!/usr/bin/env python3
import pandas as pd


def is_strictly_increasing(data):
    #print(data[0])
    #print(data[1])
    #print(data[2])
    
    if data[0] > data[1] < data[2]:
        return True


    #return data.is_monotonic_increasing and data.is_unique


def main():
    jahrestemperatur = pd.DataFrame(
        {
            "Datum": [
                "01.01.1900",
                "01.01.1910",
                "01.01.1920",
                "01.01.1930",
                "01.01.1940",
                "01.01.1950",
                "01.01.1960",
            ],
            "Temperatur": [-12, -3, -25, -8, 0, 3, -16],
        }
    )
    print(jahrestemperatur.rolling(3).agg(is_strictly_increasing) > 0)


if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hartmannsgruber: Du kannst so schlicht und einfach nicht auf `DataFrame`\s zugreifen. Ein ``data[0]`` bedeutet, greife auf die Spalte mit dem Label 0 zu. So eine Spalte gibt es nicht. Es gibt da nur die Spalten "Datum" und "Temperatur". Du willst da ja wahrscheinlich in Spalte "Temperatur" auf die Zeilen mit dem `iloc`-Index 0, 1, und 2 zugreifen. Dann musst Du auch genau *das* machen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Wenn ich die Funktion wie oben aufrufe erhalte ich folgende Ausgabe:

Code: Alles auswählen

0   -12.0
1    -3.0
2   -25.0
dtype: float64
1    -3.0
2   -25.0
3    -8.0
dtype: float64
2   -25.0
3    -8.0
4     0.0
dtype: float64
3   -8.0
4    0.0
5    3.0
dtype: float64
4     0.0
5     3.0
6   -16.0
dtype: float64	
Wenn ich versuche nun während des Funktionsaufrus darauf zu zu greifen, erhalte ich immer die selben Fehler:

Code: Alles auswählen

print(data[0]) # -> KeyError: 0
print(data["Temperatur"][0] # -> KeyError: 'Temperatur'
print(data[0]["Temperatur"] # -> IndexError: invalid index to scalar variable.

print(data.iloc(0)) 
print(data.iloc(1)) # -> ValueError: No axis named 1 for object type <class 'pandas.core.series.Series'>

print(data["Temperatur"].iloc(0)) # -> KeyError: 'Temperatur'
print(data.iloc(0)["Temperatur"]) # -> TypeError: Cannot index by location index with a non-integer key
bitte um Erklärung wie das gehen soll....
Wenn das eine größere Baustelle ist/wird, wie schafft man es mit einer for Schleife in Python schnell über eine Liste mit 20.000 Einträgen zu iterieren?
Dann werfe ich einfach das pandas raus und gut ists.
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Verstehe ich das Problem nicht oder suchst du einfach nur die korrekte Verwendung von iloc?

Code: Alles auswählen

# einzubinden in den vorherigen Beispielcode:
# ...

def is_strictly_increasing(data):
    print(data.iloc[0])
    return data.is_monotonic_increasing and data.is_unique

# ...
Antworten