# -*- coding: utf-8 -*-
"""
Analyse the rsidual loads from different countries statistically
with respect to the correlation of periods with positive and negative residual loads.
sum: integral (Energy)
mean: measure for Power
count: period (in h)
and further values are also calculated like the 25%, 75% etc.
Context: SPP2403 Cooperation Atakan / Bertsch
Created on Thu Dec 5 10:00:37 2024
@author: atakan
"""
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sbn
from scipy import signal
from rws_py import DATA_DIR, RESULTS_DIR
plt.close("all")
# Beispiel-Daten (ersetze durch deine eigene Datenserie)
# data_0 = pd.DataFrame(
# {'Residuallast': [5, 1, 2, -2, -1, -3, 5, 2, -4, -6, 8, 1, 6, 7, 8]})
test = False
dir_name = RESULTS_DIR
f_name_base = dir_name/"res_store"
[docs]
def analyze_residual(data, column, verbose=False):
"""
Analyze Residual load data for periods of negative residuals followed by positive
with respect to time (length), integral(sum)=energy and the mean values
of each period.
Parameters
----------
data : pd.DataFrame
to be analyzed.
column : string
the column with the data to be analyzed.
verbose : Boolean, optional
if you want some printing. The default is False.
Raises
------
KeyError
DESCRIPTION.
Returns
-------
results : dictionary with three entries, as follows
-""
df_period : pd.DataFrame
all periods ith the folowing one of opposite sign .
df_pos_neg : pd.DataFrame
positive residual load periods with the folowing one of opposite sign .
df_neg_pos : pd.DataFrame
negative residual load periods with the folowing one of opposite sign .
"""
# Vorzeichenserien erstellen
data['sign'] = np.sign(data[column])
# Finden Sie die Perioden positiver und negativer Zahlen
data['block'] = (data['sign'].diff() != 0).cumsum()
# Statistik für jede Periode erstellen
df_period = data.groupby('block')[column].agg(
['count', 'mean', 'std', 'sum', 'min', 'max']).reset_index()
df_period['25%'] = data.groupby('block')[column].quantile(0.25).values
df_period['50%'] = data.groupby('block')[column].quantile(0.5).values
df_period['75%'] = data.groupby('block')[column].quantile(0.75).values
df_period['positive'] = df_period['sum'] > 0
# Listen für Positive-Negative und Negative-Positive Kombinationen
pos_neg_list = []
neg_pos_list = []
# Iteriere durch die Perioden und kombiniere sie
for i in range(len(df_period)):
current_row = df_period.iloc[i]
if current_row['positive']:
# Positive-Negative Kombination
if i + 1 < len(df_period) and not df_period.iloc[i + 1]['positive']:
next_row = df_period.iloc[i + 1]
combined = pd.concat([current_row.add_suffix(
'_pos'), next_row.add_suffix('_neg')])
else:
zero_row = pd.Series(
0, index=current_row.index).add_suffix('_neg')
combined = pd.concat(
[current_row.add_suffix('_pos'), zero_row])
pos_neg_list.append(combined)
else:
# Negative-Positive Kombination
if i + 1 < len(df_period) and df_period.iloc[i + 1]['positive']:
next_row = df_period.iloc[i + 1]
combined = pd.concat([current_row.add_suffix(
'_neg'), next_row.add_suffix('_pos')])
else:
zero_row = pd.Series(
0, index=current_row.index).add_suffix('_pos')
combined = pd.concat(
[current_row.add_suffix('_neg'), zero_row])
neg_pos_list.append(combined)
# DataFrames erstellen
df_pos_neg = pd.DataFrame(pos_neg_list).reset_index(drop=True)
df_neg_pos = pd.DataFrame(neg_pos_list).reset_index(drop=True)
# Ergebnisse anzeigen
if verbose:
print("Positive-Negative Perioden (fehlende negative Werte mit Nullen aufgefüllt):")
print(df_pos_neg)
print(
"\nNegative-Positive Perioden (fehlende positive Werte mit Nullen aufgefüllt):")
print(df_neg_pos)
return df_period, df_pos_neg, df_neg_pos
[docs]
def storage(power, actual_capacity, full_capacity, efficiency=1, time_step=1,
sp_names=None):
"""
Simple storage model without power restriction but max. capacity.
Parameters
----------
power : Float
power entering the storage (=positive) or wanted(=negative), if possible
with the actual state of charge.
actual_capacity : Float
what is the actual charge (energy).
full_capacity : Float
what is the full capacity.
efficiency : Float, optional
discharging efficiency. The default is 1.
time_step : Float, optional
time step relative to the next value in hours. The default is 1.
sp_names : list of strings, optional
the names of the three values calculated. The default is None.
Returns
-------
result_dict : Dictionary
- "act_st_cap" actual loading/energy after the time step
- "power_st_in": the real power entering/exiting the storage
- "SOC": state of charge.
"""
if power >= 0: # Laden
if actual_capacity < full_capacity - power*time_step:
pass
elif actual_capacity < full_capacity:
power = (full_capacity - actual_capacity)/time_step
else:
power = 0
actual_capacity += time_step*power
else: # Entladen
power_with_efficiency = power / efficiency # Berücksichtige Effizienz bei der Entladeleistung
if actual_capacity > np.abs(time_step*power_with_efficiency):
pass
elif actual_capacity > 0:
power = -actual_capacity*efficiency/time_step # Anpassen der Leistung basierend auf verfügbarer Kapazität
else:
power = 0
actual_capacity += time_step * power_with_efficiency
# Sicherheitscheck für numerische Ungenauigkeiten
actual_capacity = max(0, min(actual_capacity, full_capacity))
soc = actual_capacity/full_capacity
if not sp_names:
sp_names = ["act_st_cap", "power_st_in", "SOC"]
result_dict = dict(zip(sp_names, [actual_capacity, power, soc]))
return result_dict
[docs]
def create_filenames(value, base=None):
exponent = int(np.floor(np.log10(value))) # Berechne den Exponenten
base_value = value / (10 ** exponent) # Basiswert berechnen
# Runden die Basis auf 3 signifikante Stellen und ohne Dezimalstellen
# Multiplizieren und umwandeln in Ganze Zahl zur Eliminierung der Dezimalstellen
rounded_value = round(base_value, 3)
# Entferne Punkte durch Umwandlung in integer und formatiere den Namen
filename = f"{int(rounded_value * 1000)}E{exponent - 3}"
return base+filename
[docs]
def eval_df_pos_neg(df, col, time=1, verbose=False):
positive_residuals = df[df[col] > 0][col]
positive_mean = positive_residuals.mean()
positive_sum = positive_residuals.sum()
positive_count = positive_residuals.count()
# Berechnung für negative Residualwerte
negative_residuals = df[df[col] < 0][col]
negative_mean = negative_residuals.mean()
negative_sum = negative_residuals.sum()
negative_count = negative_residuals.count()
if verbose:
# Ausgabe der Ergebnisse
print(f"""Positive Residuals: Mittelwert: {
positive_mean:.2e}, Summe: {positive_sum:.2e}""")
print(f"""Negative Residuals: Mittelwert: {
negative_mean:.2e}, Summe: {negative_sum:.2e}""")
print(f"""summe Residuals: Mittelwert: {
positive_mean+negative_mean:.2e},
Summe: {positive_sum+negative_sum:.2e}""")
return np.array([positive_mean, positive_sum, positive_count, negative_mean,
negative_sum, negative_count])
[docs]
def calc_capacity_dependence(in_ser, m_cap, EFF_STOR=0.75,
make_df=False,
verbose = False,
file_name = 'cap_res-',
title = None):
"""
Calculate a storage (dis-)charging as a function of residual loads
Parameters
----------
in_ser : pd.Series
hourly Residual loads (neg->entering).
m_cap : array of floats
storage capacities for which the behaviour is calculated.
EFF_STOR : Float, optional
discharging efficiency of the storage. The default is 0.75.
make_df : Boolean, optional
shall all results be returned as pd.DataFrame or as some numpy.arrays.
The default is False.
verbose : Boolean, optional
if printing is wanted. The default is False.
file_name : string, optional
place to store the results, the name will be extended. The default
is 'cap_res-'.
Returns
-------
Dataframe
assessment as function of the residual loads time series.
or numpy arrays
if make_df=False, cap_dep_res, st_state, la, cap_change.
"""
cap_dep_res = []
st_state = []
cap_change = []
la = []
in_df = pd.DataFrame(in_ser)
in_df.columns = ["residual"]
for mca in m_cap:
cap = 0 # Initiale Speicherkapazität
fn_act = create_filenames(mca, file_name)
results = []
for po in in_df["residual"]:
st_res = storage(-po, cap, mca, efficiency=EFF_STOR)
results.append(st_res)
cap = st_res["act_st_cap"]
results = pd.DataFrame(results)
#results.set_index('row_num', inplace=True)
in_df.set_index(results.index, inplace=True)
actual_df = pd.concat([in_df, results], axis=1)
actual_df["row_num"] = actual_df.index
actual_df["pow_rest"] = actual_df["residual"] + actual_df["power_st_in"]
# Berechne die Differenzen und weitere Statistiken
actual_df['change_act_st_cap'] = actual_df['act_st_cap'].diff()
fi_, ax_ = plt.subplots(3)
sbn.lineplot(data=actual_df, x="row_num", y="SOC",
ax=ax_[0], color='b')
sbn.lineplot(data=actual_df, x="row_num", y="pow_rest",
ax=ax_[1], color='b')
sbn.lineplot(data=actual_df, x="row_num", y="residual",
ax=ax_[2], color='k')
ax_[0].set_title(title+f", Cap: {mca:2.2e}")
fi_.savefig(fn_act+".jpg")
soc_counts = actual_df['SOC'].value_counts()
zero_count = soc_counts.get(0, 0) # Anzahl der 0en
one_count = soc_counts.get(1, 0) # Anzahl der 1en
# Berechnung der Differenzen zwischen aufeinanderfolgenden Werten
actual_df['previous_SOC'] = actual_df['SOC'].shift(
1) # Vorheriger Wert
# Bedingung für Wechsel von 0 auf einen höheren Wert
from_0_to_higher = ((actual_df['previous_SOC'] == 0) & (
actual_df['SOC'] > 0)).sum()
# Bedingung für Wechsel von 1 auf einen niedrigeren Wert
from_1_to_lower = ((actual_df['previous_SOC'] == 1) & (
actual_df['SOC'] < 1)).sum()
# Ausgabe der Ergebnisse
if verbose:
print(f"Max. storage capacity: {mca}")
print(f"""Anzahl der Werte 0 in 'SOC': {
zero_count} und 1 in 'SOC': {one_count}""")
print(f"""Anzahl der Wechsel von 0 auf einen höheren Wert: {
from_0_to_higher}; von 1 auf einen niedrigeren Wert: {
from_1_to_lower}""")
st_state.append(np.array([zero_count,
one_count,
from_0_to_higher,
from_1_to_lower]))
# Zugrunde liegende Werte zur LA Auswertung
time_pos_res_remain = actual_df[actual_df['pow_rest'] > 0].count()['pow_rest']
time_neg_res_remain = actual_df[actual_df['pow_rest'] < 0].count()['pow_rest']
time_no_res_remain = actual_df[actual_df['pow_rest'] == 0].count()['pow_rest']
la_pos = 1 - (time_pos_res_remain / actual_df["pow_rest"].count())
la_neg = 1 - (time_neg_res_remain / actual_df["pow_rest"].count())
la_eq = (time_no_res_remain / actual_df["pow_rest"].count())
la.append(np.array([la_pos, la_neg, la_eq]))
cap_change.append(eval_df_pos_neg(actual_df, "change_act_st_cap"))
# Ergebnisse sammeln
pos_neg_stat = eval_df_pos_neg(actual_df, "pow_rest")
cap_dep_res.append(np.array([*pos_neg_stat, actual_df["act_st_cap"].iloc[-1]]))
actual_df.to_csv(fn_act+".csv", sep=";")
cap_dep_res = np.array(cap_dep_res)
st_state = np.array(st_state)
la = np.array(la)
cap_change= np.array(cap_change)
# Rückgabe je nach Bedarf
if make_df:
cd_names=['load_pos_mean', 'load_pos_sum', 'load_pos_count', 'load_neg_mean', 'load_neg_sum', 'load_neg_count', "final_storedCharge"]
st_names =["empty", "full", "0->up", "1->down"]
la_names= ["LA+", "LA-", "eq_ratio"]
cap_change_names=['load_diff_pos_mean', 'load_diff_pos_sum', 'load_diff_pos_count', 'load_diff_neg_mean', 'load_diff_neg_sum', 'load_diff_neg_count']
col_names = [ *cd_names, *st_names, *la_names, *cap_change_names]
combined_df = pd.DataFrame(np.hstack((cap_dep_res, st_state, la, cap_change)), columns=col_names)
combined_df["storage capacity"] = m_cap
combined_df["Eff_dis"] = EFF_STOR
combined_df.to_csv(file_name+"_cap_dependence.csv",sep=";")
return combined_df
else:
return cap_dep_res, st_state, la, cap_change
[docs]
def esm_residual_to_df(country=None, file_in=None,
col_name="residual-no-storage", first_day=None,
save_csv=True, verbose=False,
get_countries=False,
normalize=True):
"""
Reads ESM residual load data from a CSV or Excel file, extracts the data for a specific country,
sets the date as the index, and optionally normalizes the data.
Parameters:
-----------
country : str, optional
The country for which the residual load data should be extracted.
Defaults to "DE0 Tot" if not specified.
file_in : str, optional
The filename (without extension) containing the residual load data.
If None, defaults to '2024_Bertsch_residual_Load'.
col_name : str, optional
The name of the column to store the extracted residual load data.
Default is "residual-no-storage".
first_day : str, optional
Not used in the current function.
save_csv : bool, optional
If True, saves the extracted and transposed data to a CSV file for future use. Default is True.
verbose : bool, optional
If True, prints the first few rows of the dataset and the index for debugging purposes. Default is False.
get_countries : bool, optional
If True, returns a list of available country names from the dataset instead of extracting data. Default is False.
normalize : bool, optional
If True, normalizes the extracted residual load data by computing
the absolute mean of the negative values (=> positive!).
The original values are then divided by this value. Default is True.
Returns:
--------
pd.DataFrame or list
- If `get_countries` is True: Returns a list of available country names.
- Otherwise: Returns a DataFrame with extracted residual load data for the specified country.
Raises:
-------
ValueError
If the specified file cannot be loaded.
FileNotFoundError
If neither the CSV nor the Excel file is found.
Notes:
------
- The function first attempts to read data from a CSV file. If the CSV is missing, it tries to read from an Excel file.
- If an Excel file is used, the dataset is transposed, and a datetime index is generated starting from '2050-01-01 00:00:00' with hourly frequency.
- Normalization is performed only if the normalization factor (difference between mean positive and mean negative values) is nonzero.
"""
COL_N_ORIGINAL = "residual-original"
if file_in is None:
file_in = '2024_Bertsch_residual_Load'
# **Pfad zum data-Ordner setzen**
base_dir = os.path.dirname(os.path.abspath(__file__)) # Ordner von residual_analyse.py
data_dir = os.path.join(base_dir, "data") # Wechselt eine Ebene hoch und geht in "data"
file_csv = os.path.join(data_dir, file_in + ".csv")
file_xlsx = os.path.join(data_dir, file_in + ".xlsx")
df_transponiert = None # Initialisierung
try:
df_transponiert = pd.read_csv(file_csv, index_col=0)
except:
try:
df = pd.read_excel(file_xlsx)
df_transponiert = df.set_index('node').T
start_date = '2050-01-01 00:00:00'
date_range = pd.date_range(start=start_date, periods=8760, freq='h')
df_transponiert.index = date_range
if save_csv:
df_transponiert.to_csv(file_csv)
except FileNotFoundError:
print(f"Fehler: Datei '{file_csv}' oder '{file_xlsx}' nicht gefunden.")
except Exception as e:
print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")
if df_transponiert is None:
raise ValueError(f"Konnte Datei '{file_csv}' oder '{file_xlsx}' nicht laden!")
if verbose:
print(df_transponiert.head())
print(df_transponiert.index)
if get_countries:
return list(df_transponiert.columns)
if country is None:
country = "DE0 Tot"
actual_values = df_transponiert[country].values
actual_country_df = pd.DataFrame(actual_values, columns=[col_name])
actual_country_df[COL_N_ORIGINAL] = actual_country_df[col_name]
actual_country_df.index = pd.to_datetime(df_transponiert.index)
if normalize:
actual_values = actual_country_df[COL_N_ORIGINAL].values
hours = (actual_country_df.index[-1] - actual_country_df.index[0]).total_seconds() / 3600
# Compute mean of the negative values separately
# this is, what could be stored on average per year
norm_factor = abs(actual_values[actual_values < 0].sum()) \
/ hours
actual_country_df.loc[:, 'residual-not-normalized'] = actual_country_df[col_name]
if norm_factor != 0: # Avoid division by zero
actual_country_df[col_name] = actual_country_df[col_name]/ norm_factor
else:
pass # Keep original if no variation
return actual_country_df
if __name__ == "__main__":
test_countries = esm_residual_to_df(get_countries =True)
test_df = esm_residual_to_df()
EFF_STOR = .75
m_cap = np.linspace(1e6, 20e6, 15)
if test:
verbose = False
df = pd.read_excel('2024_Bertsch_residual_Load.xlsx')
# Lade die Excel-Datei mit pandas
# output_folder = create_output_folder()
# Transponiere die Tabelle
df_transponiert = df.set_index('node').T
df_transponiert['time_diff_seconds'] = np.zeros(
len(df_transponiert)) + 3600
df_transponiert['time'] = np.arange(0, len(df_transponiert) * 3600., 3600)
countries = ["DE0 Tot", "IT0 0", "GB5 0", "ES0 0", "IE4 0"]
spalten = ["act_st_cap", "power_st_in", "SOC"]
actual_df = df_transponiert["DE0 Tot"].values
actual_df = pd.DataFrame(actual_df, columns=["residual"])
# Beispielaufruf der neuen Funktion
results_df = calc_capacity_dependence(actual_df,
m_cap,
EFF_STOR,
make_df=True,
file_name=f_name_base)
# Wenn du die NumPy-Arrays willtest
cap_dep_res, st_state, la, cap_change = calc_capacity_dependence(actual_df,
m_cap,
EFF_STOR,
make_df=False,
file_name=f_name_base)
fi_n, (ax_n, ax_s)= plt.subplots(2)
fi_n2, (ax_c, ax_e)= plt.subplots(2)
# Energy integral
ax_n.plot(m_cap, cap_dep_res[:, 1], "k", label="pos res")
# integral of remaining negative residuals
ax_n.plot(m_cap, -cap_dep_res[:, 4], "b:", label="neg res")
ax_n.plot(m_cap, cap_dep_res[:, -1], "bv",
label = "stored finally") # am Ende im Speicher
ax_n.plot(m_cap, cap_dep_res[:, 1] + \
cap_dep_res[:, 4], "kv-", label="sum res")
ax_n.plot(m_cap, cap_dep_res[:, 1]+cap_dep_res[:,
4]+cap_dep_res[:, -1], "ro", label="sum")
ax_n.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_n.set_xlabel("storage capacity")
ax_n.set_ylabel("integral energy")
# Storage loads
ax_s.plot(m_cap, st_state[:, 0], "k", label="empty")
ax_s.plot(m_cap, st_state[:, 1]/20, "b", label="full/20")
ax_s.plot(m_cap, st_state[:, 2], "k", label="0->up")
ax_s.plot(m_cap, st_state[:, 3], "k", label="1->down")
ax_s.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_s.set_xlabel("storage capacity")
ax_s.set_ylabel("number of states")
# Raum für die Legende schaffen
fi_n.tight_layout(rect=[0, 0, 0.85, 1])
fi_n.savefig(f_name_base+"-number_cap-plot.png")
# Storage capacity change
ax_c.plot(m_cap, cap_change[:, 1], "k", label="charging")
ax_c.plot(m_cap, -cap_change[:, 4], "b", label="discharging")
ax_e.plot(m_cap, cap_change[:, 2], "k", label="number chg")
ax_e.plot(m_cap, cap_change[:, 5], "b:", label="number disc")
ax_c.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_e.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_c.set_xlabel("storage capacity")
ax_c.set_ylabel("integral charging")
# Raum für die Legende schaffen
fi_n2.tight_layout(rect=[0, 0, 0.85, 1])
fi_n2.savefig(f_name_base+"-integral-charge_cap-plot.png")
# Number of full charging equivalents
fi_n3, (ax_g, ax_h)= plt.subplots(2)
equiv_no_charging = cap_change[:, 1] / m_cap
equiv_no_discharging = cap_change[:, 4] / m_cap
ax_g.plot(m_cap, equiv_no_charging, "k", label="charging")
ax_g.plot(m_cap, equiv_no_discharging, "b:", label="discharging")
ax_g.set_xlabel("storage capacity")
ax_g.set_ylabel("no eq. full cyc. / y")
ax_g.legend(loc='upper left', bbox_to_anchor=(1, 1))
e2p_mean_charge = m_cap/cap_change[:, 0]
e2p_mean_discharge = m_cap/cap_change[:, 3]
ax_h.plot(m_cap, e2p_mean_charge, "k", label="charging")
ax_h.plot(m_cap, e2p_mean_discharge, "b:", label="discharging")
ax_h.set_xlabel("storage capacity")
ax_h.set_ylabel("E2P / h")
ax_h.legend(loc='upper left', bbox_to_anchor=(1, 1))
# Raum für die Legende schaffen
fi_n3.tight_layout(rect=[0, 0, 0.85, 1])
fi_n3.savefig(f_name_base+"-charge_discharge-plot.png")
fig_e, ax_p =plt.subplots(1)
ax_p.plot(m_cap, la[:,0], "k", label="LA_pos")
ax_p.plot(m_cap, la[:,1], "b", label="LA_neg")
ax_p.plot(m_cap, la[:,2], "r:", label="ratio_eq")
ax_p.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_p.set_title("Level of Autononomy (LA)")
ax_p.set_xlabel("storage capacity")
ax_p.set_ylabel("LA")
# Raum für die Legende schaffen
fig_e.tight_layout(rect=[0, 0, 0.85, 1])
fig_e.savefig(f_name_base+"-la-plot.png")
#-----------------------
#-----------------------
aa =storage(-1, 2 , 5, .5,.1666,)
print (aa)
pd.set_option('display.max_columns', None)
# a, b, c = analyze_residual(data_0, 'Residuallast')
df = pd.read_excel(DATA_DIR/'2024_Bertsch_residual_Load.xlsx')
# Lade die Excel-Datei mit pandas
# output_folder = create_output_folder()
# Transponiere die Tabelle
df_transponiert = df.set_index('node').T
df_transponiert['time_diff_seconds'] = np.zeros(
len(df_transponiert)) + 3600
df_transponiert['time']= np.arange(0, len(df_transponiert) * 3600., 3600)
countries= ["DE0 Tot"]# , "IT0 0", "GB5 0", "ES0 0", "IE4 0"]
sum_units= 1/1000
EFF_STOR = .75
m_cap = np.linspace(1e6, 20e6, 15)
for what in countries:
fnam =f_name_base+what[:3]
res_max = df_transponiert[what].max()
m_cap = np.linspace(res_max/20, res_max*20, 7)
results_df = calc_capacity_dependence(df_transponiert[what],
m_cap,
EFF_STOR,
make_df=True,
file_name=f_name_base+"-"+what[:3]+"-",
title = what[:3])
fig_e, ax_p = plt.subplots()
line_labels = ['LA+', 'LA-', 'eq_ratio']
colors = ['black', 'blue', 'green'] # Beispiel Farben können angepasst werden
for label, color in zip(line_labels, colors):
sbn.lineplot(data=results_df, x='storage capacity', y=label, ax=ax_p, label=label, color=color)
# Anpassen der Legende
ax_p.legend(loc='upper left', bbox_to_anchor=(1, 1))
ax_p.set_title("Level of Autonomy (LA), "+what[:3])
ax_p.set_xlabel("Storage Capacity")
ax_p.set_ylabel("LA")
# Raum für die Legende schaffen
fig_e.tight_layout(rect=[0, 0, 0.85, 1])
# Speichern des Plots
fig_e.savefig("la-plot.png")
plt.show()
all_periods, pos_neg, neg_pos = analyze_residual(df_transponiert, what)
neg_pos[['sum_pos', 'sum_neg']] = neg_pos[[
'sum_pos', 'sum_neg']] * sum_units
sbn.scatterplot(data=neg_pos, x='count_neg', y='count_pos',
size = 'sum_pos', hue = 'sum_neg') # , style='mean_pos')
plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
# Optional: Ändere die Größe des Plots, um Platz für die Legende zu schaffen
plt.tight_layout()
plt.title(what)
plt.savefig(fnam+"sum_count.jpg")
plt.figure()
sbn.scatterplot(data=neg_pos, x='sum_neg', y='sum_pos',
size = 'count_pos', hue = 'count_neg') # , style='mean_pos')
plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
# Optional: Ändere die Größe des Plots, um Platz für die Legende zu schaffen
plt.tight_layout()
plt.title(what)
plt.savefig(fnam+"_count_sum.jpg")
fi, ax= plt.subplots(2)
print(
f"country:{what}, No.-periods: {pos_neg['count_pos'].count()}")
act_corr= signal.correlate(
df_transponiert[what], df_transponiert[what])
# f, Pxx_den = signal.periodogram(data[dat_act[1][2]], fs =1/600)
# ax4.semilogy(f, Pxx_den)
ax[0].plot(act_corr)
# positive_values = df_transponiert[what][df_transponiert[what] > 0]
# Falls die Indizes wichtig sind, erstelle einen Array nur mit den positiven Werten
# Setze negative Werte auf 0
df_transponiert[what+"mod"] = np.where(
df_transponiert[what] < 0, 0, df_transponiert[what])
# Erstelle ein NumPy-Array aus der Spalte
modified_array = df_transponiert[what+"mod"].to_numpy()
# Berechne die Kreuzkorrelation der modifizierten Werte
# , mode='full')
corr = signal.correlate(modified_array, modified_array)
# Optional: Wenn du auch die Lag-Werte berechnen möchtest
lags = signal.correlation_lags(
len(modified_array), len(modified_array), mode ='full')
# Ausgabe der Korrelation und der Lags
lc = len(corr)
corr_n = corr[int((lc-1)/2):]
ax[1].plot(corr_n[:200]/np.abs(corr_n).max())
ax[0].set_title("Autocorrelation, "+what[:3])
fi.savefig(fnam+"_correl.jpg")
neg_pos.to_csv(fnam+"neg_pos.csv",sep=';')
pos_neg.to_csv(fnam+"pos_neg.csv",sep=';')
all_periods.to_csv(fnam+"all_periods.csv",sep=';')
neg_sum = np.where(
df_transponiert[what] > 0, 0, df_transponiert[what]).sum()
pos_sum = np.where(
df_transponiert[what] < 0, 0, df_transponiert[what]).sum()
print(f"{what}, pos/neg residuals: {-pos_sum/neg_sum:.2f}")