Umändern von Datumswerten

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
wikingerjonathan
User
Beiträge: 1
Registriert: Sonntag 4. Juni 2023, 21:59

Hey, also ich versuche gerade folgendes zu rechnen:
Daten pro Tag sind in einem df gespeichert. Zusätzlich stehen in einem anderen df_result Werte für den jeweiligen Monat. Nun soll pro Tag der wert von df geändert werden. Hierbei soll folgendes passieren: Die Daten in dem df sind schon in Monaten gruppiert. Das Ergebnis aus df_result soll nun für den jeweiligen Monat ausgelesen werden. Wenn das Ergebnis >1, sollen die Tageswerte auf 0 gesetzt werden und von dem Wert soll 1 subtrahiert werden. Das Ergebnis soll an die Berechnung des 2. Tages weitergegeben werden. Wenn das Ergebnis jedoch <1, aber >0, soll das jeweilige Ergebnis prozentual von dem bestehenden Wert in df abgezogen werden. Für die restlichen Tage im Monat enden hier dann jegliche Änderungen. Für den dritten Tag wird dann das umgeänderte Ergebnis aufgenommen. Und es passiert wieder dasselbe. Wenn das Ergebnis >1, sollen die Tageswerte auf 0 gesetzt werden und von dem Wert soll 1 subtrahiert werden. Das Ergebnis soll an die Berechnung des 3. Tages weitergegeben werden. Wenn das Ergebnis jedoch <1, aber >0, soll das jeweilige Ergebnis prozentual von dem bestehenden Wert in df abgezogen werden. Für die restlichen Tage im Monat enden hier dann jegliche Änderungen. Das geht so weiter bis das Ergebnis 0 ist.

Als Beispiel werden die Werte des df bei einem Ergebnis von 4.3 dann so verändert: Die ersten 4 Tage werden auf 0 gesetzt und von dem wert des 5ten Tages werden 30% abgezogen. Der Rest der Tage des Monates behält seine ursprünglichen Werte. Das ist was ich bis jetzt habe:

monate = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
werte = ['8.64', '7.64', '1.56', '3.1', '5.39', '8.33', '9.21', '3.1', '2.768', '0.37', '1.74', '9.93']
# Erstellen des Dataframes
df_result = pd.DataFrame({'Monat': monate, 'Wert': werte})
df_result['Wert'] = df_result['Wert'].astype(float)
#df = df.astype(float)
df_result['Ergebnis'] = df_result['Monat'].map(df_max.set_index('Monat')['Tag'] / 100) * df_result['Wert']

df = pd.read_excel(Xoko.xlsx)
# Datumsformat in 'date' in DateTime umwandeln
df['date'] = pd.to_datetime(df['date'], format='%d-%b')

#def group_by_month(date):
#return date.strftime('%b')

for month, group in df.groupby(df['date'].dt.month):
if not df_result[df_result['Monat'] == month].empty:
ergebnis = df_result.loc[df_result['Monat'] == month, 'Ergebnis'].values[0]

tageswerte = group['Tageswerte'].iloc[0]
month_abbr = monate[month - 1]

#if month_abbr in df_result['Monat'].values:
ergebnis = df_result.loc[df_result['Monat'] == monate[month-1], 'Ergebnis'].values[0]

for i in range(0, len(group)):
if ergebnis > 1:
tageswerte = 0
ergebnis -= 1
elif ergebnis > 0:
tageswerte = tageswerte - (tageswerte * ergebnis)
ergebnis = 0
else:
break

if i + 1 < len(group):
month_abbr = monate[month - 1]
ergebnis = df_result.loc[df_result['Monat'] == month_abbr, 'Ergebnis'].values[0]

if ergebnis == 0:
break

group.loc[group.index, 'Tageswerte'] = tageswerte

df.loc[group.index, 'Tageswerte'] = group['Tageswerte']

Das Problem hierbei ist, dass mittlerweile einfach alle Werte auf 0 gesetzt werden. Findet jemand den Fehler und kann mir helfen? Ich habe schon mehrere Sachen ausprobiert, aber irgendwie will das nicht.
Das würde mich sehr freuen.
Mit freundlichen Grüßen
wikingerjonathan
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wikingerjonathan: Das es da ein Objekt unter dem Namen `Xoko` gibt das ein `xlsx`-Attribut hat, glaube ich ja irgendwie nicht.

Warum sind denn da Zahlen als Zeichenketten im Code die dann in Zahlen umgewandelt werden? Den Schritt hätte man sich sparen können.

Das erste ``if`` in der Schleife sollte eigentlich *immer* `False` ergeben weil da Zeichenketten mit einer Zahl verglichen werden. Es wird auch nichts was in dem ``if``-Zweig definiert wird hinterher irgendwo verwendet. Es wäre schön wenn solch toter Code vor dem zeigen hier rausgeflogen wäre. 🙂

Im ``elif ergebnis > 0:``-Zweig ist `tageswerte` potentiell undefiniert. Falls das irgendwo vor dem gezeigten Code definiert wird, ist das zu weit weg von dieser Schleife. Der Name impliziert irgendwie auch, dass es da mehr als einen Wert gibt, die einzige Zuweisung wo ein literaler Wert zugewiesen wird ist eine 0‽

`ergebnis` wird am Anfang der Schleife sehr umständlich ermittelt. Es gibt für jeden Monat nur eine Zeile in dem Dataframe und Du hast den Monat als Zahl, also ist der gewünschte Wert in Zeile ``monat - 1``, also statt:

Code: Alles auswählen

        ergebnis = df_result.loc[df_result['Monat'] == monate[month-1], 'Ergebnis'].values[0]
ist das einfach nur:

Code: Alles auswählen

        ergebnis = df_result.iloc[month-1]["Ergebnis"]
Das gleiche kommt in der Schleife, leicht anders formuliert, noch mal vor.

Ich denke `df_result` ist hier nicht so wirklich sinnvoll als Dataframe. Das enthält 12 Zeilen und wird als Abbildung von Monat auf einen Wert ”missbraucht”. Da wäre ein Wörterbuch (`dict`) einfacher zu benutzen.

Bei `group` wird immer nur auf Werte der Spalte "Tageswerte" zugegriffen. Das könnte man *einmal* machen, und sich damit den Zugriff vereinfachen.

Überarbeitet könnte das dann so aussehen (ungetestet):

Code: Alles auswählen

    ...
    df_result = pd.DataFrame(
        {
            "Monat": "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(),
            "Wert": [
                8.64,
                7.64,
                1.56,
                3.1,
                5.39,
                8.33,
                9.21,
                3.1,
                2.768,
                0.37,
                1.74,
                9.93,
            ],
        }
    )
    df_result["Ergebnis"] = (
        df_result["Monat"].map(df_max.set_index("Monat")["Tag"] / 100)
        * df_result["Wert"]
    )

    df = pd.read_excel("Xoko.xlsx")
    df["date"] = pd.to_datetime(df["date"], format="%d-%b")
    #
    # TODO Sinnvoller Wert und falls möglich noch näher an die Schleife
    # verschieben in der das verwendet wird.
    #
    tageswerte = ...
    for month, group in df.groupby(df["date"].dt.month)["Tageswerte"]:
        ergebnis = df_result.iloc[month - 1]["Ergebnis"]
        for i in range(len(group)):
            if ergebnis > 1:
                tageswerte = 0
                ergebnis -= 1
            elif ergebnis > 0:
                tageswerte -= tageswerte * ergebnis
                ergebnis = 0
            else:
                break

            if i + 1 < len(group):
                ergebnis = df_result.iloc[month - 1]["Ergebnis"]

            if ergebnis == 0:
                break

            group.iloc[i] = tageswerte

        df.loc[group.index, "Tageswerte"] = group["Tageswerte"]
Wenn `ergebnis` hier einmal über 1 ist, dann kann `tageswerte` ja eigentlich nur noch 0 sein/bleiben, egal was sonst noch so passiert. Denn die einzige andere Veränderung an dem Wert ist 0 davon abzuziehen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wikingerjonathan: Ups, da war am Ende noch ein ``["Tageswerte"]`` zu viel — `group` enthält ja nur noch das. Man könnte den Ausdruck da auch deutlich einfacher mit `DataFrame.update()` formulieren.

Und dann habe ich mir noch mal die Beschreibung was passieren soll durchgelesen. Komplett ungetestet:

Code: Alles auswählen

    df_result = pd.DataFrame(
        {
            "Monat": "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(),
            "Wert": [
                8.64,
                7.64,
                1.56,
                3.1,
                5.39,
                8.33,
                9.21,
                3.1,
                2.768,
                0.37,
                1.74,
                9.93,
            ],
        }
    )
    ergebnis = (
        df_result["Monat"].map(df_max.set_index("Monat")["Tag"] / 100)
        * df_result["Wert"]
    )
    ergebnis.index += 1  # Index ist jetzt die Nummer des Monats.
    month_to_result = ergebnis.to_dict()

    df = pd.read_excel("Xoko.xlsx")
    df["date"] = pd.to_datetime(df["date"], format="%d-%b")

    for month, group in df.groupby(df["date"].dt.month)["Tageswerte"]:
        ergebnis = month_to_result[month]
        for i in range(len(group)):
            if ergebnis > 1:
                group.iloc[i] = 0
                ergebnis -= 1
            elif ergebnis > 0:
                group.iloc[i] -= group.iloc[i] * ergebnis
                break
            else:
                #
                # TODO Darf dieser Fall überhaupt vorkommen?  Hier eventuell
                # besser eine Ausnahme auslösen, damit fehlerhafte Daten nicht
                # einfach geräuschlos ignoriert werden.
                # 
                break  

        df.update(group)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten