import pandas as pd import matplotlib.pyplot as plt import numpy as np from datetime import datetime import os # Manuelle Zuordnung der Monatsnamen von Deutsch auf Englisch # month_translation = { # 'Jan': 'Jan', 'Feb': 'Feb', 'Mär': 'Mar', 'Apr': 'Apr', 'Mai': 'May', 'Jun': 'Jun', # 'Jul': 'Jul', 'Aug': 'Aug', 'Sep': 'Sep', 'Okt': 'Oct', 'Nov': 'Nov', 'Dez': 'Dec', 'Mrz': 'Mar' # } # Funktion, um 'Okt 10-16' in eine Kalenderwoche zu konvertieren und das Startdatum zurückzugeben # def convert_to_week_number_and_start_date(date_range_str): # # Splitte den Datumsbereich in Monat und Tage # start_part, end_part = date_range_str.split(" - ") # start_month_str, start_day = start_part.split(" ") # start_day = int(start_day) # Nimm den Starttag # # # Konvertiere den deutschen Monatsnamen in den englischen # if start_month_str in month_translation: # start_month_str = month_translation[start_month_str] # # # Erstelle das Datum basierend auf dem Starttag und dem aktuellen Jahr # current_year = datetime.now().year # date_str = f"{start_month_str} {start_day} {current_year}" # # try: # start_date = datetime.strptime(date_str, "%b %d %Y") # Konvertiere in ein Datum # except ValueError: # raise ValueError(f"Ungültiges Datum: {date_str}") # # week_number = start_date.isocalendar()[1] # Kalenderwoche ermitteln # # return week_number, start_date.strftime('%Y-%m-%d') # Gib KW und das Startdatum zurück # Funktion, um 'Okt 10-16' oder 'Okt 10 - 16' in eine Kalenderwoche zu konvertieren und das Startdatum zurückzugeben # def convert_to_week_number_and_start_date(date_range_str): # # Entferne zusätzliche Leerzeichen um den Bindestrich herum # date_range_str = date_range_str.replace(" - ", "-") # # # Splitte den Datumsbereich in Start- und Endbereich # start_part, end_part = date_range_str.split("-") # start_month_str, start_day = start_part.split(" ") # start_day = int(start_day.strip()) # Nimm den Starttag und entferne etwaige Leerzeichen # # # Konvertiere den deutschen Monatsnamen in den englischen # if start_month_str in month_translation: # start_month_str = month_translation[start_month_str] # # # Erstelle das Datum basierend auf dem Starttag und dem aktuellen Jahr # current_year = datetime.now().year # date_str = f"{start_month_str} {start_day} {current_year}" # # try: # start_date = datetime.strptime(date_str, "%b %d %Y") # Konvertiere in ein Datum # except ValueError: # raise ValueError(f"Ungültiges Datum: {date_str}") # # week_number = start_date.isocalendar()[1] # Kalenderwoche ermitteln # # return week_number, start_date.strftime('%Y-%m-%d') # Gib KW und das Startdatum zurück # Funktion, um Datumsbereiche wie 'Mrz 29-Apr 4' oder 'Okt 10-16' in die Kalenderwoche zu konvertieren # und das Startdatum zurückzugeben # Funktion, um Datumsbereiche wie 'Mrz 29-Apr 4' oder 'Okt 10-16' in die Kalenderwoche zu konvertieren # und das Startdatum zurückzugeben # def convert_to_week_number_and_start_date(date_range_str): # # Entferne zusätzliche Leerzeichen um den Bindestrich herum # date_range_str = date_range_str.replace(" - ", "-") # # # Splitte den Datumsbereich in Start- und Endteil # start_part, end_part = date_range_str.split("-") # # # Verarbeite den Startteil # start_month_str, start_day = start_part.split(" ") # start_day = int(start_day.strip()) # Nimm den Starttag und entferne etwaige Leerzeichen # # # Wenn der Endteil einen Monat enthält, verarbeite ihn ebenfalls # if " " in end_part: # end_month_str, end_day = end_part.split(" ") # end_day = int(end_day.strip()) # Nimm den Endtag # else: # # Wenn der Endteil keinen Monat enthält, verwenden wir denselben Monat wie im Startteil # end_month_str = start_month_str # end_day = int(end_part.strip()) # # # Konvertiere den deutschen Monatsnamen in den englischen für beide Monate # if start_month_str in month_translation: # start_month_str = month_translation[start_month_str] # if end_month_str in month_translation: # end_month_str = month_translation[end_month_str] # # # Erstelle das Datum basierend auf dem Starttag und dem aktuellen Jahr # current_year = datetime.now().year # start_date_str = f"{start_month_str} {start_day} {current_year}" # # try: # # Konvertiere in ein Datum # start_date = datetime.strptime(start_date_str, "%b %d %Y") # except ValueError: # raise ValueError(f"Ungültiges Startdatum: {start_date_str}") # # # Berechne die Kalenderwoche basierend auf dem Startdatum # week_number = start_date.isocalendar()[1] # # return week_number, start_date.strftime('%Y-%m-%d') # Gib KW und das Startdatum zurück # Manuelle Zuordnung der Monatsnamen von Deutsch auf Englisch month_translation = { 'Jan': 'Jan', 'Feb': 'Feb', 'Mär': 'Mar', 'Mrz': 'Mar', 'Apr': 'Apr', 'Mai': 'May', 'Jun': 'Jun', 'Jul': 'Jul', 'Aug': 'Aug', 'Sep': 'Sep', 'Okt': 'Oct', 'Nov': 'Nov', 'Dez': 'Dec' } # Funktion, um Datumsbereiche wie 'Mrz 29-Apr 4' oder 'Dez 29, 2023-Jan 4, 2024' in die Kalenderwoche und das Startdatum zu konvertieren def convert_to_week_number_and_start_date(date_range_str): # Entferne zusätzliche Leerzeichen um den Bindestrich herum und entferne Kommas date_range_str = date_range_str.replace(" - ", "-").replace(",", "") # Splitte den Datumsbereich in Start- und Endteil start_part, end_part = date_range_str.split("-") # Verarbeite den Startteil start_parts = start_part.split(" ") start_month_str = start_parts[0] start_day = int(start_parts[1].strip()) # Nimm den Starttag und entferne etwaige Leerzeichen # Verarbeite den Endteil end_parts = end_part.split(" ") # Verarbeite das Enddatum, basierend darauf, ob ein Jahr enthalten ist oder nicht if len(end_parts) == 3: # Fall: 'Jan 4 2024' end_month_str = end_parts[0] end_day = int(end_parts[1].strip()) end_year = int(end_parts[2].strip()) # Nimm das Jahr aus dem Endteil elif len(end_parts) == 2: # Fall: 'Jan 4' ohne Jahr end_month_str = end_parts[0] end_day = int(end_parts[1].strip()) end_year = datetime.now().year # Nutze das aktuelle Jahr, wenn kein Jahr angegeben ist else: # Falls kein Monat angegeben, setze den Startmonat für den Endteil end_month_str = start_month_str end_day = int(end_parts[0].strip()) end_year = datetime.now().year # Nutze das aktuelle Jahr # Konvertiere den deutschen Monatsnamen in den englischen für beide Monate if start_month_str in month_translation: start_month_str = month_translation[start_month_str] if end_month_str in month_translation: end_month_str = month_translation[end_month_str] # Wenn der Startteil ein Jahr enthält, nutze dieses if len(start_parts) == 3: start_year = int(start_parts[2]) else: start_year = datetime.now().year # Falls der Datumsbereich über den Dezember hinausgeht, endet das Enddatum im nächsten Jahr if start_month_str == 'Dec' and end_month_str == 'Jan': end_year = start_year + 1 try: # Konvertiere das Startdatum in ein Datum start_date = datetime.strptime(f"{start_month_str} {start_day} {start_year}", "%b %d %Y") except ValueError: raise ValueError(f"Ungültiges Startdatum: {start_month_str} {start_day} {start_year}") try: # Konvertiere das Enddatum in ein Datum end_date = datetime.strptime(f"{end_month_str} {end_day} {end_year}", "%b %d %Y") except ValueError: raise ValueError(f"Ungültiges Enddatum: {end_month_str} {end_day} {end_year}") # Berechne die Kalenderwoche basierend auf dem Startdatum week_number = start_date.isocalendar()[1] return week_number, start_date.strftime('%Y-%m-%d') # Gib KW und das Startdatum zurück # Funktion zum Bereinigen und Zwischenspeichern der Daten def clean_and_save_data(hr_data, sleep_data, output_dir='sandbox'): # Entferne 'bpm' und konvertiere die Werte in numerische Daten hr_data['In Ruhe'] = hr_data['In Ruhe'].str.replace(' bpm', '').astype(float) hr_data['Hoch'] = hr_data['Hoch'].str.replace(' bpm', '').astype(float) # Konvertiere die Spalte 'Datum' in Kalenderwoche (KW) und Startdatum hr_data[['week', 'start_date']] = hr_data['Datum'].apply( lambda x: pd.Series(convert_to_week_number_and_start_date(x))) # Berechne den Durchschnitt der Herzfrequenzdaten (In Ruhe und Hoch) hr_data['avg_hr'] = hr_data[['In Ruhe', 'Hoch']].mean(axis=1) # Konvertiere auch das 'Datum' der Schlafdaten in Kalenderwoche (KW) und Startdatum sleep_data[['week', 'start_date']] = sleep_data['Datum'].apply( lambda x: pd.Series(convert_to_week_number_and_start_date(x))) # Speichere die bereinigten Daten in 'sandbox' if not os.path.exists(output_dir): os.makedirs(output_dir) hr_data_clean_path = os.path.join(output_dir, 'hr_data_clean.csv') sleep_data_clean_path = os.path.join(output_dir, 'sleep_data_clean.csv') hr_data.to_csv(hr_data_clean_path, sep=';', index=False) sleep_data.to_csv(sleep_data_clean_path, sep=',', index=False) print(f"HR-Daten wurden bereinigt und in {hr_data_clean_path} gespeichert.") print(f"Schlafdaten wurden bereinigt und in {sleep_data_clean_path} gespeichert.") return hr_data, sleep_data # Schritt 1: Lade die HR- und Schlafdaten hr_data = pd.read_csv('/home/gra/PycharmProjects/cds_introduction_data_science_assignment/data/raw/hr_gramic.csv', sep=';') sleep_data = pd.read_csv('/home/gra/PycharmProjects/cds_introduction_data_science_assignment/data/raw/sleep_gramic.csv', sep=',') # Bereinige und speichere die Daten hr_data, sleep_data = clean_and_save_data(hr_data, sleep_data) # Schritt 2: Sortiere beide Datensätze nach 'week' und 'start_date' hr_data = hr_data.sort_values(by=['week', 'start_date']) sleep_data = sleep_data.sort_values(by=['week', 'start_date']) # Schritt 3: Kombiniere die beiden Datensätze anhand der 'week' und 'start_date' Spalten mit einem äußeren Join combined_data = pd.merge(hr_data, sleep_data, on=['week', 'start_date'], how='outer') # Zeige die kombinierten Daten print("\nKombinierte Daten:") print(combined_data) # Schritt 4: Entferne alle Zeilen mit fehlenden Daten combined_data = combined_data.dropna() # Schritt 5: Berechne die Korrelation zwischen 'avg_hr' und 'Durchschnittliche Dauer' correlation = combined_data['avg_hr'].corr(combined_data['Durchschnittliche Dauer']) print(f"\nDie Korrelation zwischen der durchschnittlichen Herzfrequenz und der Schlafdauer ist: {correlation}") # Schritt 6: Visualisiere den Zusammenhang zwischen Herzfrequenz und Schlafdauer plt.figure(figsize=(10, 6)) plt.scatter(combined_data['avg_hr'], combined_data['Durchschnittliche Dauer'], color='blue', label='Datenpunkte') plt.title('Zusammenhang zwischen Herzfrequenz (Durchschnitt) und Schlafdauer') plt.xlabel('Durchschnittliche Herzfrequenz (bpm)') plt.ylabel('Schlafdauer (Stunden)') plt.grid(True) # Linie zur Visualisierung des Trends hinzufügen m, b = np.polyfit(combined_data['avg_hr'], combined_data['Durchschnittliche Dauer'], 1) plt.plot(combined_data['avg_hr'], m * combined_data['avg_hr'] + b, color='red', label=f'Trendlinie (Kor = {correlation:.2f})') plt.legend() plt.show()