data_processor.py aktualisiert

This commit is contained in:
2025-08-04 13:32:19 +00:00
parent 90de1a8e60
commit b2e69d509b

View File

@@ -5504,8 +5504,7 @@ class DataProcessor:
'Techniker_Mittel (50-249)', 'Techniker_Mittel (50-249)',
'Techniker_Gross (250+)'] 'Techniker_Gross (250+)']
df_filtered.loc[:, df_filtered.loc[:, 'Techniker_Bucket'] = pd.cut(df_filtered['Anzahl_Servicetechniker_Numeric'],
'Techniker_Bucket'] = pd.cut(df_filtered['Anzahl_Servicetechniker_Numeric'],
bins=bins_new, bins=bins_new,
labels=labels_new, labels=labels_new,
right=True, right=True,
@@ -5514,7 +5513,7 @@ class DataProcessor:
f"Verteilung der neuen Techniker-Buckets:\n{df_filtered['Techniker_Bucket'].value_counts(normalize=True, dropna=False).sort_index().round(3)}") f"Verteilung der neuen Techniker-Buckets:\n{df_filtered['Techniker_Bucket'].value_counts(normalize=True, dropna=False).sort_index().round(3)}")
# --- Kategoriale Features vorbereiten (Branchen-Gruppen) --- # --- Kategoriale Features vorbereiten (Branchen-Gruppen) ---
# Dies ist die Spalte mit den Detail-Branchen # Wir verwenden konsistent die KI-generierte Spalte 'branche_ki' als Basis für die Gruppierung.
branche_col_internal = "branche_ki" branche_col_internal = "branche_ki"
self.logger.info(f"Verarbeite kategoriales Feature '{branche_col_internal}' und mappe es zu 'Branchen_Gruppe'...") self.logger.info(f"Verarbeite kategoriales Feature '{branche_col_internal}' und mappe es zu 'Branchen_Gruppe'...")
@@ -5522,84 +5521,52 @@ class DataProcessor:
self.logger.critical(f"FEHLER: Die für das Mapping benötigte Spalte '{branche_col_internal}' wurde nicht im DataFrame gefunden. Breche ab.") self.logger.critical(f"FEHLER: Die für das Mapping benötigte Spalte '{branche_col_internal}' wurde nicht im DataFrame gefunden. Breche ab.")
return None return None
# Wende das saubere Mapping aus der Config an. Die Schlüssel sind jetzt lesbar. # Wende das saubere Mapping aus der Config an, um nur den 'gruppe'-String zu extrahieren.
# Wir müssen die Eingabedaten aus dem Sheet NICHT MEHR normalisieren.
branch_group_map = {branch_name: details.get('gruppe', 'Sonstige') for branch_name, details in Config.BRANCH_GROUP_MAPPING.items()} branch_group_map = {branch_name: details.get('gruppe', 'Sonstige') for branch_name, details in Config.BRANCH_GROUP_MAPPING.items()}
df_filtered.loc[:, 'Branchen_Gruppe'] = df_filtered[branche_col_internal].map(branch_group_map).fillna('Sonstige') df_filtered.loc[:, 'Branchen_Gruppe'] = df_filtered[branche_col_internal].map(branch_group_map).fillna('Sonstige')
self.logger.info("Mapping zu 'Branchen_Gruppe' durchgeführt.") self.logger.info("Mapping zu 'Branchen_Gruppe' durchgeführt.")
self.logger.debug( self.logger.debug(
f"Verteilung der Branchen-Gruppen:\n{df_filtered['Branchen_Gruppe'].value_counts(normalize=True).sort_index().round(3)}") f"Verteilung der Branchen-Gruppen:\n{df_filtered['Branchen_Gruppe'].value_counts(normalize=True).sort_index().round(3)}")
# One-Hot Encoding wird jetzt auf der neuen 'Branchen_Gruppe'-Spalte # --- One-Hot Encoding ---
# durchgeführt df_encoded = pd.get_dummies(df_filtered, columns=['Branchen_Gruppe'], prefix='Gruppe', dummy_na=False)
df_encoded = pd.get_dummies( self.logger.info("One-Hot Encoding fuer 'Branchen_Gruppe' durchgefuehrt.")
df_filtered,
columns=['Branchen_Gruppe'],
prefix='Gruppe',
dummy_na=False)
self.logger.info(
f"One-Hot Encoding fuer 'Branchen_Gruppe' durchgefuehrt.")
# --- Finale Auswahl der Features fuer das Modell --- # --- Finale Auswahl der Features fuer das Modell ---
feature_columns_ml = [ feature_columns_ml = [col for col in df_encoded.columns if col.startswith('Gruppe_')]
col for col in df_encoded.columns if col.startswith('Gruppe_')] feature_columns_ml.extend(['Log_Finaler_Umsatz_ML', 'Log_Finaler_Mitarbeiter_ML', 'Umsatz_pro_MA_ML', 'is_part_of_group'])
feature_columns_ml.extend([ self.logger.info(f"Finale Feature-Auswahl für das Training: {feature_columns_ml}")
'Log_Finaler_Umsatz_ML',
'Log_Finaler_Mitarbeiter_ML',
'Umsatz_pro_MA_ML',
'is_part_of_group'
])
self.logger.info(
f"Finale Feature-Auswahl für das Training: {feature_columns_ml}")
target_column_ml = 'Techniker_Bucket' target_column_ml = 'Techniker_Bucket'
identification_cols_ml = ['name', 'Anzahl_Servicetechniker_Numeric'] identification_cols_ml = ['name', 'Anzahl_Servicetechniker_Numeric']
final_cols_for_df_ml = identification_cols_ml + \ final_cols_for_df_ml = identification_cols_ml + feature_columns_ml + [target_column_ml]
feature_columns_ml + [target_column_ml] missing_final_cols_ml = [col for col in final_cols_for_df_ml if col not in df_encoded.columns]
missing_final_cols_ml = [
col for col in final_cols_for_df_ml if col not in df_encoded.columns]
if missing_final_cols_ml: if missing_final_cols_ml:
self.logger.critical( self.logger.critical(f"FEHLER: Finale Spalten fuer Modellierung fehlen im DataFrame: {missing_final_cols_ml}")
f"FEHLER: Finale Spalten fuer Modellierung fehlen im DataFrame: {missing_final_cols_ml}")
return None return None
df_model_ready = df_encoded[final_cols_for_df_ml].copy() df_model_ready = df_encoded[final_cols_for_df_ml].copy()
numeric_features_to_convert = [ numeric_features_to_convert = ['Log_Finaler_Umsatz_ML', 'Log_Finaler_Mitarbeiter_ML', 'Umsatz_pro_MA_ML', 'Anzahl_Servicetechniker_Numeric']
'Log_Finaler_Umsatz_ML',
'Log_Finaler_Mitarbeiter_ML',
'Umsatz_pro_MA_ML',
'Anzahl_Servicetechniker_Numeric']
for col in numeric_features_to_convert: for col in numeric_features_to_convert:
if col in df_model_ready.columns: if col in df_model_ready.columns:
df_model_ready[col] = pd.to_numeric( df_model_ready[col] = pd.to_numeric(df_model_ready[col], errors='coerce')
df_model_ready[col], errors='coerce')
df_model_ready = df_model_ready.reset_index(drop=True) df_model_ready = df_model_ready.reset_index(drop=True)
self.logger.info( self.logger.info("Datenvorbereitung fuer Modellierung (Training) abgeschlossen.")
"Datenvorbereitung fuer Modellierung (Training) abgeschlossen.") self.logger.info(f"Finaler DataFrame fuer Modellierung hat {len(df_model_ready)} Zeilen und {len(df_model_ready.columns)} Spalten.")
self.logger.info(
f"Finaler DataFrame fuer Modellierung hat {len(df_model_ready)} Zeilen und {len(df_model_ready.columns)} Spalten.")
self.logger.info(f"Anzahl Feature-Spalten: {len(feature_columns_ml)}") self.logger.info(f"Anzahl Feature-Spalten: {len(feature_columns_ml)}")
numeric_features_for_imputation_ml = [ numeric_features_for_imputation_ml = ['Log_Finaler_Umsatz_ML', 'Log_Finaler_Mitarbeiter_ML', 'Umsatz_pro_MA_ML']
'Log_Finaler_Umsatz_ML', existing_numeric_features = [col for col in numeric_features_for_imputation_ml if col in df_model_ready.columns]
'Log_Finaler_Mitarbeiter_ML',
'Umsatz_pro_MA_ML'
]
existing_numeric_features = [
col for col in numeric_features_for_imputation_ml if col in df_model_ready.columns]
if existing_numeric_features: if existing_numeric_features:
nan_counts = df_model_ready[existing_numeric_features].isna().sum() nan_counts = df_model_ready[existing_numeric_features].isna().sum()
self.logger.info( self.logger.info(f"Fehlende Werte in numerischen Features vor Imputation:\n{nan_counts}")
f"Fehlende Werte in numerischen Features vor Imputation:\n{nan_counts}") rows_with_nan = df_model_ready[existing_numeric_features].isna().any(axis=1).sum()
rows_with_nan = df_model_ready[existing_numeric_features].isna().any( self.logger.info(f"Anzahl Zeilen mit mindestens einem fehlenden numerischen Feature (vor Imputation): {rows_with_nan}")
axis=1).sum()
self.logger.info(
f"Anzahl Zeilen mit mindestens einem fehlenden numerischen Feature (vor Imputation): {rows_with_nan}")
return df_model_ready return df_model_ready