pandas df Wert in einem anderen df suchen bzw. auf Vorhandensein prüfen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
antilet
User
Beiträge: 8
Registriert: Freitag 12. März 2021, 16:10

Hallo liebe Python-Profis,

ich versuche in einem pandas.df diverse Datumsberechnungen/ -umwandlungen durchzuführen.
Bisher konnte ich mir alles ergoogeln, aber jetzt stehe ich vor einem Problem, was ich so nicht gelöst bekomme:

Ich möchte aus meinem Ziel df, das in der Spalte 'Datum' ein fortlaufendes Datum hat, gegen einen anderen df oder liste mit dem Datum von Feiertagen prüfen,
ob das Datum aus dem Ziel df im Feiertags df enthalten ist.

Mein Ansatz funktioniert leider nicht:

Code: Alles auswählen

pd_datum['ist_feiertag'] = pd_datum.apply( lambda x: 1 if x.Datum in pd_feiertage.FEIERTAG else 0, axis=1)
Ich hatte schon auf typ-Gleichheit in der Spalten in der df geprüft, sind beide 'datetime64[ns]'

Es wird kein Fehler geworfen, aber die Zielspalte trägt immer eine 0 - was bedeutet, dass mein apply nicht funktioniert. :(

Ich freue mich auf erhellende Antworten. :idea:
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Suchst du join?
antilet
User
Beiträge: 8
Registriert: Freitag 12. März 2021, 16:10

Hmmm, ich vermute nicht, aber ich habe auch kein so richtig schönes Beispiel gefunden.
Ich habe folgendes versucht:

Code: Alles auswählen

pd_datum.join(pd_feiertage, on=[pd_datum.Datum, pd_feiertage.FEIERTAG], how='left', lsuffix='L_', rsuffix = 'R_' )
das wirft einen Fehler:

Code: Alles auswählen

ValueError: len(left_on) must equal the number of levels in the index of "right"
Scheinbar erwartet Join, dass beide DFs gleich lang sind - oder habe ich was verkehrt gemacht?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Wenn das Datum nicht dein Index ist, könnte es auch merge sein.
antilet
User
Beiträge: 8
Registriert: Freitag 12. März 2021, 16:10

Vielen Dank. Das erzeugt einen neuen df (oder geht das auch inplace?) und am Ende stehen keine 0 und 1 in der Spalte - das könnte man vermutlich aber auch hinbekommen.
Ich habe es jetzt anders gelöst - weiß nicht, warum ich da nicht gleich drauf gekommen bin...

Code: Alles auswählen

def ist_feiertag(datum):
    if datum in feiertage:
        return 1
    else:
        return 0

# und für den df dann:
pd_datum['ist_feiertag'] = pd_datum.apply( lambda x: ist_feiertag(x.Datum.strftime("%Y-%m-%d")), axis=1)
Das passt für mich erstmal so :)
Vielen Dank.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Ohne Beispieldaten ist es schwierig zu helfen. Bei Deinem Code passen offensichtlich die Datentypen nicht zusammen. Du versuchst ein Datumsobjekt mit einem String zu vergleichen, natürlich findet Python da nichts.
Deshalb ist es wichtig, auch gleich die passenden Daten mit in die Frage zu schreiben.
In Deinem Fall ist es also wichtig, dass alle Daten vom Typ Datum sind und dann ist `isin` die richtige Methode:

Code: Alles auswählen

import pandas as pd
import io

feiertage = pd.read_csv(io.StringIO("""Feiertag
31.03.2023
17.04.2023
29.04.2023
01.05.2023"""), parse_dates=['Feiertag'])

datum = pd.read_csv(io.StringIO("""Datum
01.01.2023
29.04.2023
30.04.2023
01.05.2023
03.05.2023
"""), parse_dates=['Datum'])
datum['ist_feiertag'] = datum.Datum.isin(feiertage.Feiertag)
Wenn Du Wahrheitswerte hast, dann sind die Zahlen 0 und 1 nicht das richtige. Man sollte immer mit den passenden Datentypen arbeiten, das Datum in einen String umzuwandeln ist falsch.
antilet
User
Beiträge: 8
Registriert: Freitag 12. März 2021, 16:10

Vielen Dank, @Sirius3 , du hast vermutlich recht.
Allerdings waren unterschiedliche Datentypen für mich nicht ersichtlich.
Ich hatte schon auf typ-Gleichheit in der Spalten in der df geprüft, sind beide 'datetime64[ns]'
Obwohl mich das schon etwas wundert, da ich 'gefühlt' (bin halt noch am Anfang) beide df's gleich befüllt habe:

Code: Alles auswählen

feiertage = ['2022-12-24', '2022-12-25', '2022-12-26', '2022-12-31', '2023-01-01']
pd_feiertage['FEIERTAG'] = pd.to_datetime([x for x in feiertage], format = "%Y-%m-%d")

startdatum = date(2022, 5, 28)
endedatum = date(2023, 12, 31)
pd_datum['Datum'] = pd.to_datetime([date.fromordinal(wert) for wert in range(startdatum.toordinal(), endedatum.toordinal()+1)], format = "%Y-%m-%d")
Sicher hast du recht, dass 0 und 1 daten-technisch nicht so sinnvoll ist, hier war der Treiber, dass am Ende 0 und 1 ausgegeben werden soll, also habe ich es auch einfach so gespeichert.
Am Ende sollen alle benötigten Spalten ausgegeben werden (dienen als Basis für ein großes Insert-Statement).

Eine andere Frage, die mit dem oben vorgeschlagenen Merge zusammenhängt:
Gehe ich recht in der Annahme, dass es in pandas keine window-Funktionen wie in einer Datanbank oder ähnliches gibt, mit der filtern und gruppieren inplace in einer eigenen Spalte umsetzbar ist?
Ich habe mit filtern und anschließendem GroupBy die Basis-Daten für 4 weitere Spalten ermittelt.
Ich vermute, der einzige Weg ist, diese an den 'Master'-df zu mergen und dann die NaN mit Nullen aufzufüllen und alles was nicht 0 ist gegen eine 1 zu tauschen (gibt es dafür eine Funktion? - quasi replace(feld, '<>0', 1 ) - das wäre top :)
Irgendwie finde ich das mit dem Merge nicht so elegant. Bislang fand ich die meisten python-Lösungen einfach elegant oder elegant einfach - so macht das dann auch mehr Spaß ;-)
Dein "datum['ist_feiertag'] = datum.Datum.isin(feiertage.Feiertag)" gefällt mir auch deutlich besser als mein lambda-Gewurstel (wobei ich immer froh bin, wenn's funktioniert...)
Antworten