import datetime import warnings from pathlib import Path from typing import Collection import pandas as pd from pyprojroot import here import participants.query_db from features import esm from machine_learning import QUESTIONNAIRE_IDS, QUESTIONNAIRE_IDS_RENAME from machine_learning.helper import read_csv_with_settings, to_csv_with_settings WARNING_PARTICIPANTS_LABEL = ( "Before aggregating labels, please set participants label using self.set_participants_label() " "to be used as a filename prefix when exporting data. " "The filename will be of the form: %participants_label_%grouping_variable_%data_type.csv" ) class Labels: def __init__( self, grouping_variable: str, labels: dict, participants_usernames: Collection = None, ) -> None: self.grouping_variable_name = grouping_variable self.grouping_variable = [grouping_variable] self.questionnaires = labels.keys() self.participants_label: str = "" if participants_usernames is None: participants_usernames = participants.query_db.get_usernames( collection_start=datetime.date.fromisoformat("2020-08-01") ) self.participants_label = "all" self.participants_usernames = participants_usernames self.df_esm = pd.DataFrame() self.df_esm_preprocessed = pd.DataFrame() self.df_esm_interest = pd.DataFrame() self.df_esm_clean = pd.DataFrame() self.df_esm_means = pd.DataFrame() self.folder: Path = Path() self.filename_prefix = "" self.construct_export_path() print("Labels initialized.") def set_labels(self) -> None: print("Querying database ...") self.df_esm = esm.get_esm_data(self.participants_usernames) print("Got ESM data from the DB.") self.df_esm_preprocessed = esm.preprocess_esm(self.df_esm) print("ESM data preprocessed.") if "PANAS" in self.questionnaires: self.df_esm_interest = self.df_esm_preprocessed[ ( self.df_esm_preprocessed["questionnaire_id"] == QUESTIONNAIRE_IDS.get("PANAS").get("PA") ) | ( self.df_esm_preprocessed["questionnaire_id"] == QUESTIONNAIRE_IDS.get("PANAS").get("NA") ) ] self.df_esm_clean = esm.clean_up_esm(self.df_esm_interest) print("ESM data cleaned.") def get_labels(self, questionnaire: str) -> pd.DataFrame: if questionnaire == "PANAS": return self.df_esm_clean else: raise KeyError("This questionnaire has not been implemented as a label.") def aggregate_labels(self, cached=True) -> None: print("Aggregating labels ...") if not self.participants_label: raise ValueError(WARNING_PARTICIPANTS_LABEL) try: if not cached: # Do not use the file, even if it exists. raise FileNotFoundError self.df_esm_means = read_csv_with_settings( self.folder, self.filename_prefix, data_type="_".join(self.questionnaires), grouping_variable=self.grouping_variable, ) print("Read labels from the file.") except FileNotFoundError: # We need to recalculate the features in this case. self.df_esm_means = ( self.df_esm_clean.groupby( ["participant_id", "questionnaire_id"] + self.grouping_variable ) .esm_user_answer_numeric.agg("mean") .reset_index() .rename(columns={"esm_user_answer_numeric": "esm_numeric_mean"}) ) self.df_esm_means = ( self.df_esm_means.pivot( index=["participant_id"] + self.grouping_variable, columns="questionnaire_id", values="esm_numeric_mean", ) .reset_index(col_level=1) .rename(columns=QUESTIONNAIRE_IDS_RENAME) .set_index(["participant_id"] + self.grouping_variable) ) print("Labels aggregated.") to_csv_with_settings( self.df_esm_means, self.folder, self.filename_prefix, data_type="_".join(self.questionnaires), ) def get_aggregated_labels(self) -> pd.DataFrame: return self.df_esm_means def construct_export_path(self) -> None: if not self.participants_label: warnings.warn(WARNING_PARTICIPANTS_LABEL, UserWarning) self.folder = here("machine_learning/intermediate_results/labels", warn=True) self.filename_prefix = ( self.participants_label + "_" + self.grouping_variable_name ) def set_participants_label(self, label: str) -> None: self.participants_label = label self.construct_export_path()