2024-10-16 20:48:05 +02:00
import pandas as pd
2024-10-16 21:15:23 +02:00
import matplotlib . pyplot as plt
import numpy as np
from datetime import datetime
2024-10-17 20:42:54 +02:00
import os
2024-10-16 21:15:23 +02:00
2024-10-17 20:42:54 +02:00
# 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
2024-10-16 21:15:23 +02:00
# Manuelle Zuordnung der Monatsnamen von Deutsch auf Englisch
month_translation = {
2024-10-17 20:42:54 +02:00
' Jan ' : ' Jan ' , ' Feb ' : ' Feb ' , ' Mär ' : ' Mar ' , ' Mrz ' : ' Mar ' , ' Apr ' : ' Apr ' , ' Mai ' : ' May ' , ' Jun ' : ' Jun ' ,
2024-10-16 21:15:23 +02:00
' Jul ' : ' Jul ' , ' Aug ' : ' Aug ' , ' Sep ' : ' Sep ' , ' Okt ' : ' Oct ' , ' Nov ' : ' Nov ' , ' Dez ' : ' Dec '
}
2024-10-17 20:52:26 +02:00
# Funktion, um Datumsbereiche wie 'Mrz 29-Apr 4', 'Dez 29, 2023-Jan 4, 2024', 'Dez 22-28 2023' oder 'Dez 28' in Kalenderwoche und Startdatum zu konvertieren
2024-10-17 20:42:54 +02:00
def convert_to_week_number_and_start_date ( date_range_str ) :
2024-10-17 20:47:31 +02:00
# Entferne zusätzliche Leerzeichen um den Bindestrich herum und entferne Kommas
2024-10-17 20:42:54 +02:00
date_range_str = date_range_str . replace ( " - " , " - " ) . replace ( " , " , " " )
2024-10-17 20:52:26 +02:00
# Prüfen, ob das Format nur einen Tag und Monat enthält (z.B. 'Dez 28')
if " - " not in date_range_str and len ( date_range_str . split ( " " ) ) == 2 :
# Nur ein Datum (Monat und Tag)
month_str , day_str = date_range_str . split ( " " )
day = int ( day_str . strip ( ) )
year_str = str ( datetime . now ( ) . year ) # Verwende das aktuelle Jahr
# Konvertiere den deutschen Monatsnamen in den englischen
if month_str in month_translation :
month_str = month_translation [ month_str ]
# Konvertiere das Datum
start_date = datetime . strptime ( f " { month_str } { day } { year_str } " , " % b %d % Y " )
# Berechne die Kalenderwoche
week_number = start_date . isocalendar ( ) [ 1 ]
return week_number , start_date . strftime ( ' % Y- % m- %d ' )
2024-10-17 20:50:23 +02:00
# Prüfen, ob das Jahr am Ende steht (z.B. 'Dez 22-28 2023')
if date_range_str [ - 4 : ] . isdigit ( ) :
# Jahr am Ende des Datums
year_str = date_range_str [ - 4 : ]
date_range_str = date_range_str [ : - 5 ] # Entferne das Jahr aus der Datumsangabe
else :
# Kein Jahr am Ende -> nutze das aktuelle Jahr
year_str = str ( datetime . now ( ) . year )
2024-10-17 20:42:54 +02:00
# 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 ( " " )
2024-10-17 20:50:23 +02:00
# Verarbeite das Enddatum, basierend darauf, ob der Endteil das Jahr enthält
if len ( end_parts ) == 2 : # Fall: 'Apr 4'
2024-10-17 20:47:31 +02:00
end_month_str = end_parts [ 0 ]
end_day = int ( end_parts [ 1 ] . strip ( ) )
2024-10-17 20:42:54 +02:00
else :
2024-10-17 20:50:23 +02:00
# Fall: kein Monat -> nur Tag (z.B. '28' im Format 'Dez 22-28 2023')
2024-10-17 20:47:31 +02:00
end_month_str = start_month_str
2024-10-17 20:42:54 +02:00
end_day = int ( end_parts [ 0 ] . 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 ]
try :
# Konvertiere das Startdatum in ein Datum
2024-10-17 20:50:23 +02:00
start_date = datetime . strptime ( f " { start_month_str } { start_day } { year_str } " , " % b %d % Y " )
2024-10-17 20:42:54 +02:00
except ValueError :
2024-10-17 20:50:23 +02:00
raise ValueError ( f " Ungültiges Startdatum: { start_month_str } { start_day } { year_str } " )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
try :
# Konvertiere das Enddatum in ein Datum
2024-10-17 20:50:23 +02:00
end_date = datetime . strptime ( f " { end_month_str } { end_day } { year_str } " , " % b %d % Y " )
2024-10-17 20:42:54 +02:00
except ValueError :
2024-10-17 20:50:23 +02:00
raise ValueError ( f " Ungültiges Enddatum: { end_month_str } { end_day } { year_str } " )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
# Berechne die Kalenderwoche basierend auf dem Startdatum
week_number = start_date . isocalendar ( ) [ 1 ]
2024-10-16 20:58:01 +02:00
2024-10-17 20:42:54 +02:00
return week_number , start_date . strftime ( ' % Y- % m- %d ' ) # Gib KW und das Startdatum zurück
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
# 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 )
2024-10-16 20:58:01 +02:00
2024-10-17 20:42:54 +02:00
# 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 ) ) )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
# Berechne den Durchschnitt der Herzfrequenzdaten (In Ruhe und Hoch)
hr_data [ ' avg_hr ' ] = hr_data [ [ ' In Ruhe ' , ' Hoch ' ] ] . mean ( axis = 1 )
2024-10-16 20:58:01 +02:00
2024-10-17 20:42:54 +02:00
# 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 ) ) )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
# Speichere die bereinigten Daten in 'sandbox'
if not os . path . exists ( output_dir ) :
os . makedirs ( output_dir )
2024-10-16 21:15:23 +02:00
2024-10-17 20:42:54 +02:00
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 ' )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
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 ' )
2024-10-16 20:48:05 +02:00
2024-10-16 20:58:01 +02:00
# Zeige die kombinierten Daten
2024-10-16 20:48:05 +02:00
print ( " \n Kombinierte Daten: " )
2024-10-16 21:15:23 +02:00
print ( combined_data )
2024-10-17 20:42:54 +02:00
# Schritt 4: Entferne alle Zeilen mit fehlenden Daten
2024-10-16 21:15:23 +02:00
combined_data = combined_data . dropna ( )
2024-10-16 20:48:05 +02:00
2024-10-17 20:42:54 +02:00
# Schritt 5: Berechne die Korrelation zwischen 'avg_hr' und 'Durchschnittliche Dauer'
2024-10-16 20:48:05 +02:00
correlation = combined_data [ ' avg_hr ' ] . corr ( combined_data [ ' Durchschnittliche Dauer ' ] )
print ( f " \n Die Korrelation zwischen der durchschnittlichen Herzfrequenz und der Schlafdauer ist: { correlation } " )
2024-10-16 21:15:23 +02:00
2024-10-17 20:42:54 +02:00
# Schritt 6: Visualisiere den Zusammenhang zwischen Herzfrequenz und Schlafdauer
2024-10-16 21:15:23 +02:00
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 ( )