cds_introduction_data_scien.../code/corelation.py

248 lines
11 KiB
Python

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', 'Dez 29, 2023-Jan 4, 2024' oder 'Dez 22-28 2023' in Kalenderwoche und 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(",", "")
# 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)
# 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 der Endteil das Jahr enthält
if len(end_parts) == 2: # Fall: 'Apr 4'
end_month_str = end_parts[0]
end_day = int(end_parts[1].strip())
else:
# Fall: kein Monat -> nur Tag (z.B. '28' im Format 'Dez 22-28 2023')
end_month_str = start_month_str
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
start_date = datetime.strptime(f"{start_month_str} {start_day} {year_str}", "%b %d %Y")
except ValueError:
raise ValueError(f"Ungültiges Startdatum: {start_month_str} {start_day} {year_str}")
try:
# Konvertiere das Enddatum in ein Datum
end_date = datetime.strptime(f"{end_month_str} {end_day} {year_str}", "%b %d %Y")
except ValueError:
raise ValueError(f"Ungültiges Enddatum: {end_month_str} {end_day} {year_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
# 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()