Optimierung meines Codes

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
Schorsch90
User
Beiträge: 3
Registriert: Donnerstag 8. Februar 2024, 13:31

Hallo an alle,

ich habe vor einiger Zeit mit einem Kollegen einen Code erstellt, der mir aus bestimmten Datensätzen einen Volumenstrom berechnet und mir zusätzlich noch das Zapfprofil über das gesamte Jahr ausgibt. Da mein Kollege mir nicht mehr helfen kann, bitte ich hier in diesem Forum um Hilfe. Nun zu den Details. Mithilfe eines bestimmten Tools habe ich sekündliche Messwerte in fünf sekündliche Werte mitteln lassen und in entsprechenden .csv- Dateien gespeichert. Hierbei handelt es sich um ein Warmwasser- Zapfprofil für den Zeitraum eines knappen Monats (28 Tage). Pro Tag habe ich 17280 Zeilen mit Werten ( kommt zustande wenn man (3600s/h*5)*24h rechnet). Nun kommt der Code zum Einsatz. Der Code berechnet mir für jeden Tag dieses Zeitraumes den Zapfvolumenstrom und am Ende wird das zusätzlich auf das gesamte Jahr unter Berücksichtigung der Ferienzeiten erweitert, damit ich ein Jahreszapfprofil habe. Jetzt zu meinem Problem: Der Code gibt mir anstelle von 6.307.200 Zeilen/ Jahr nur 6.307.187 Zeilen/ Jahr aus. Es fehlen also genau Zeilen und ich komme nicht darauf, was ich ändern muss, um den korrekten Wert zu bekommen. Ich teile hier den relevanten Teil des Codes mit der Bitte um einen Rat, was ich ändern bzw. verbessern muss.

import pandas as pd
import numpy as np

df = pd.DataFrame()

.
.
.
.

t_ww = 60
t_zapf = 45
t_korr = 45
t_kw = 10
cp = 4.18 # kJ/kg/K
roh = 995.757297 # kg/m^3

# T_KW_lin - interpolierte T_Cold_min- Daten -> neuer Name für T_Cold_min ist T_KW_lin

start = 16
end = 13.5
lin_temp = np.linspace(start, end, len(df))
print(lin_temp)
# Normierung auf T_KW bei angenommener Zapftemperatur t_korr an der Zapfstelle

df['T_KW_lin'] = lin_temp # t_cold min hiermit ersetzen; hier: kw_lin mit T_KW_lin ersetzt
df['q_korr'] = df['Q_Flow_Tap_in_kW']*((t_korr-t_kw)/(t_ww-t_kw)/(t_korr-df['T_KW_lin'])/(t_ww-df['T_KW_lin'])) # Hier: T_Cold_min mit T_KW_lin ersetzt

# Berechnung des normierten Zapfvolumenstroms bei t_zapf

df['V_korr'] = df['q_korr'] * 1000 * 1000/(roh*cp*(t_zapf-t_kw)) # Einheit l/s
df['V_korr_5s'] = df['V_korr'] * 5 # Einheit l/5*s

repeated_column = np.tile(df['V_korr_5s'].values, 13)
repeated_column = np.concatenate([repeated_column, df['V_korr_5s'][:17280].values])
# df['V_korr'].to_csv("volumenstrom_jke.csv", decimal=",", sep=";")

print(len(df))
print(len(repeated_column))

# Ferienzeiten

# Weihnachtsferien 2022/23
repeated_column[17281:103680] = 0
# Winterferien 2023
repeated_column[518400:535680] = 0
# Osterferien 2023
repeated_column[1486080:1745280] = 0
# Himmelfahrt 2023
repeated_column[2384640:2401920] = 0
# Pfingsten 2023
repeated_column[2574720:2592000] = 0
# Sommerferien 2023
repeated_column[3231360:3939840] = 0
# Tag der Arbeit 2023 + Brückentag
repeated_column[4752000:4769280] = 0
# Herbstferien 2023
repeated_column[4993920:5253120] = 0
# Weihnachtsferien 2023/24
repeated_column[6203520:6272640] = 0
np.savetxt("Volumenstrom_LMS.csv", repeated_column, delimiter=',')
repeated_column = repeated_column*5

Ich kann leider nicht alles aus dem Code zeigen, aber vielleicht reicht das für die Lösung. Ich danke für jede Hilfe und wünsche allen eine gute Zeit. :)
Sirius3
User
Beiträge: 18054
Registriert: Sonntag 21. Oktober 2012, 17:20

Gut Variablennamen sind wichtig, um den Code verstehen zu können. Konstanten schreibt man zudem GROSS, so dass man sie als solche erkennen kann, also TEMPERATUR_WARMWASSER statt t_ww.
Wenn Q_Flow_Tap in Kilowatt angegeben sind, dann ist die Einheit von q_korr kW/K² und damit die Einheit von V_korr 1000l / s / K², statt der behaupteten l/s.
Ich habe zwar keine Ahnung, was da wirklich gerechnet wird, aber allein von den Einheiten stimmt da was nicht.

Die ganzen magischen Zahlenwerte, wo Du dann irgendwelche Bereiche auf 0 setzt, solltest Du durch eine ordentliche Rechnung ersetzen, wo man das Datum der Ferien angibt und dann daraus die Zeiten bestimmt.

Da Du nicht verrätst, welche Dimensionen der Input hat, kann man zu Deinem eigentlichen Problem nur sagen, dass da wohl eine Zeile pro Monat fehlt.
Schorsch90
User
Beiträge: 3
Registriert: Donnerstag 8. Februar 2024, 13:31

Hallo Sirius, danke schon mal für den Hinweis, dass ich im Nenner K^2 mit meiner Gleichung bekomme! Das war ein toller Hinweis. Die restlichen Zeilen wollte ich nicht veröffentlichen, weil die interne Pfade und Bezeichnungen beinhalten, die auf unsere Kunden schließen lassen. Weil ich da nicht gegen Datenschutz verstoßen wollte, habe ich die weg gelassen. Die fehlenden Zeilen im Code beziehen sich eigentlich nur darauf, woher die Parameter entnommen werden sollen für die Berechnung- also eher trivial für mein Problem. (denke ich :D)
Ich habe die Gleichung auf jeden Fall korrigiert und komme jetzt auf l/s.

Genau um diese eine Zeile im Monat geht es. Es ist an sich nur eine Formalie und ich könnte auch einfach davon ausgehen, dass die Werte zu dem Zeitpunkt (der wahrscheinlich gegen Mitternacht ist) eh Null ist, aber irgendwas muss ja im Code stehen, dass eben immer diese eine Zeile nicht berücksichtigt wird und das würde ich gerne korrigieren. Ist dir denn etwas im Code aufgefallen, was ausschlaggebend für die Nichtberücksichtigung der jeweiligen Zeilen ist?

Ich denke der Fehler liegt hier drin:

for month in months:
for day in days:
try:
temp = pd.read_csv(fr"C:................\Dataframe_2023-{month}-{day}.csv", sep=";", decimal=",", index_col="Date_Time")
df = pd.concat([df, temp])
df = df[:-1]
except:
pass
Sirius3
User
Beiträge: 18054
Registriert: Sonntag 21. Oktober 2012, 17:20

Man benutzt keine nackten except. Wenn ein Fehler auftritt, muß man den auch behandeln. Im Moment ignorierst Du das einfahch, und der Fehler tritt später auf.
Und was soll das `df[:-1]`? Könnte das vielleicht der Grund sein, warum da eine Zeile fehlt?
Schorsch90
User
Beiträge: 3
Registriert: Donnerstag 8. Februar 2024, 13:31

In meinem Auswerte- Tool habe ich festgelegt, dass aus meinen Daten immer fünf sekündliche Werte bestimmt werden. Das Programm nimmt also die Werte von fünf Sekunden und gibt mir das dann in der Excel als gemittelten Wert aus. Jeder Tag fängt bei 00:00:00 an und geht bis 23:59:55, aber dann ist immer noch eine Zeile in dem Tag der Folgetag mit der Uhrzeit 00:00:00 mit drin und in der nächsten Tabelle fängt es dann wieder bei 00:00:00 an. Meine Messung hat am 01.11.2023 angefangen und die Messung geht für den 01.11. bis 23:59:55 und dann wurde der 02.11.23 00:00:00 auch in der selben Datei angegeben. In der Datei für den 02.11.23 startet die Messung auch bei 00:00:00 und geht dann ebenfalls bis 23:59:55 usw. Das 'df[:-1]' dient also dafür, dass der Folgetag, welcher ja bei 00:00:00 startet nicht doppelt erfasst wird. Ich habe auch schon vermutet, dass es daran liegt, aber dem ist nicht so. Kannst du mir das mit dem nackten except genauer erklären?
Benutzeravatar
__blackjack__
User
Beiträge: 13565
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Schorsch90: Zwischen dem ``except`` und dem Doppelpunkt steht nix, also werden da *alle* Ausnahmen behandelt, was selten sinnvoll möglich ist. In der Regel nur wenn man die Ausnahme samt Traceback protokolliert und/oder wenn man sie erneut auslöst, damit die Information nicht verloren geht.

Selbst wenn man Ausnahmen ignorieren will, dann in der Regel ja nicht *alle*. Du weisst ja gar nicht was da alles schief laufen kann in dem Code. Zum Beispiel macht es wohl keinen Sinn bei einem MemoryError Daten die da sind einfach zu ignorieren, nur weil sie nicht in den Speicher passen. Oder man möchte ja eigentlich wissen das Daten zwar da sind, aber nicht gelesen werden können, weil da etwas in der Datei ist was nicht erwartet wurde. Oder weil die Daten eine andere Spaltenanzahl haben, weil es zusätzliche Spalten gibt, oder welche fehlen in einer der Dateien.

Falls die Ausnahmebehandlung da nur ist um nicht existierende Dateien wie den 31.02. zu ignorieren, wäre es sinnvoller statt den Dateinamen zu generieren über die tatsächlich vorhandenen Dateien zu iterieren, oder zumindest die Datumsangaben auf real existierende Daten zu beschränken. `dateutil.relativedelta` kann da hilfreich sein.

Es ist ungünstig erst die neuen Daten an die vorhandenen anzuhängen und von den *vielen* Daten dann wieder die letzte Zeile zu entfernen. Da DataFrames nicht in der Form verändert werden können, müssen so viel mehr Daten unnötig im Speicher kopiert werden. Alleine schon das wiederholte zusammenfügen von immer mehr Daten sollte man so nicht machen. Effizienter ist es erst alle DataFrames in einer Liste zu sammeln und dann *einmal* `concat()` aufzurufen.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Antworten