<jupyter_start><jupyter_text>Prediction on anonymous by our classifier___This notebook aims to try on our dataset, without including the anonymous subject, and then to see what is the classification accuracy.The recording that was randomly selected is `SC4441EC-Hypnogram.edf`. It corresponds to an 74 year old woman, and the subject index is then 44.<jupyter_code>%matplotlib inline

import numpy as np
import json

from datetime import datetime, timedelta

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.ensemble import (RandomForestClassifier,
                              VotingClassifier)
from sklearn.metrics import (confusion_matrix,
                             classification_report,
                             cohen_kappa_score)
from hmmlearn.hmm import MultinomialHMM

from models.model_utils import (train_test_split_according_to_age)
from constants import (SLEEP_STAGES_VALUES, EPOCH_DURATION,N_STAGES)
from models.model_utils import (print_hypnogram)<jupyter_output><empty_output><jupyter_text>Generate trained pipeline____<jupyter_code>SUBJECT_IDX = 0 
NIGHT_IDX = 1
USE_CONTINUOUS_AGE = False
DOWNSIZE_SET = False
TEST_SET_SUBJECTS = [44]
MODELS_DIR = "trained_model"

NIGHT = [1]
def load_features():
    if USE_CONTINUOUS_AGE:
        X_file_name = "data/x_features-age-continuous.npy"
        y_file_name = "data/y_observations-age-continuous.npy"
    else:
        X_file_name = "data/x_features.npy"
        y_file_name = "data/y_observations.npy"

    X_init = np.load(X_file_name, allow_pickle=True)
    y_init = np.load(y_file_name, allow_pickle=True)

    X_init = np.vstack(X_init)
    y_init = np.hstack(y_init)

    print(X_init.shape)
    print(y_init.shape)
    print("Number of subjects: ", np.unique(X_init[:,SUBJECT_IDX]).shape[0]) # Some subject indexes are skipped, thus total number is below 83 (as we can see in https://physionet.org/content/sleep-edfx/1.0.0/)
    print("Number of nights: ", len(np.unique([f"{int(x[0])}-{int(x[1])}" for x in X_init[:,SUBJECT_IDX:NIGHT_IDX+1]])))
    print("Subjects available: ", np.unique(X_init[:,SUBJECT_IDX]))
    
    return X_init, y_init

def split_data(X_init, y_init):
    X_test, X_train_valid, y_test, y_train_valid = train_test_split_according_to_age(
        X_init,
        y_init,
        use_continuous_age=USE_CONTINUOUS_AGE,
        subjects_test=TEST_SET_SUBJECTS)
    
    print(X_test.shape, X_train_valid.shape, y_test.shape, y_train_valid.shape)
    
    return X_test, X_train_valid, y_test, y_train_valid

X_init, y_init = load_features()
X_test, X_train_valid, y_test, y_train_valid = split_data(X_init, y_init)
hmm_model = MultinomialHMM(n_components=N_STAGES)


hmm_model.emissionprob_ = np.load(f"{MODELS_DIR}/HMM_emissionprob.npy", allow_pickle=True)
hmm_model.startprob_ = np.load(f"{MODELS_DIR}/HMM_startprob.npy", allow_pickle=True)
hmm_model.transmat_ = np.load(f"{MODELS_DIR}/HMM_transmat.npy", allow_pickle=True)
def get_voting_classifier_pipeline():
    NB_CATEGORICAL_FEATURES = 2
    NB_FEATURES = 48

    estimator_list = [
        ('random_forest', RandomForestClassifier(
            random_state=42, # enables deterministic behaviour
            n_jobs=-1
        )),
        ('knn', Pipeline([
            ('knn_dim_red', LinearDiscriminantAnalysis()),
            ('knn_clf', KNeighborsClassifier(
                weights='uniform',
                n_neighbors=300,
                leaf_size=100,
                metric='chebyshev',
                n_jobs=-1
            ))
        ])),
    ]
        
    return Pipeline([
        ('scaling', ColumnTransformer([
            ('pass-through-categorical', 'passthrough', list(range(NB_CATEGORICAL_FEATURES))),
            ('scaling-continuous', StandardScaler(copy=False), list(range(NB_CATEGORICAL_FEATURES,NB_FEATURES)))
        ])),
        ('voting_clf', VotingClassifier(
            estimators=estimator_list,
            voting='soft',
            weights=np.array([0.83756205, 0.16243795]),
            flatten_transform=False,
            n_jobs=-1,
        ))
    ])

vtg_testing_pipeline = get_voting_classifier_pipeline()
vtg_testing_pipeline.fit(X_train_valid[:, 2:], y_train_valid)
X_test_selected_night = X_test[X_test[:,1] == NIGHT[0]]
y_test_selected_night = y_test[X_test[:,1] == NIGHT[0]]

voting_y_test_pred = vtg_testing_pipeline.predict(X_test_selected_night[:,2:])
voting_y_test_pred = hmm_model.predict(voting_y_test_pred.reshape(-1, 1))

print(confusion_matrix(y_test_selected_night, voting_y_test_pred))
print(classification_report(y_test_selected_night, voting_y_test_pred, target_names=SLEEP_STAGES_VALUES.keys()))
print("Agreement score (Cohen Kappa): ", cohen_kappa_score(y_test_selected_night, voting_y_test_pred))<jupyter_output>[[394  11   2   0   2]
 [ 37  66  52   0  28]
 [  5  24 321   1  54]
 [  0   0  52  39   0]
 [  0   0   0   0 100]]
              precision    recall  f1-score   support

           W       0.90      0.96      0.93       409
          N1       0.65      0.36      0.46       183
          N2       0.75      0.79      0.77       405
          N3       0.97      0.43      0.60        91
         REM       0.54      1.00      0.70       100

    accuracy                           0.77      1188
   macro avg       0.77      0.71      0.69      1188
weighted avg       0.79      0.77      0.76      1188

Agreement score (Cohen Kappa):  0.687724728854155<jupyter_text>Generate RF trained pipeline___<jupyter_code>%%time

def get_random_forest_model():
    NB_CATEGORICAL_FEATURES = 2
    NB_FEATURES = 48
    
    return Pipeline([
        ('scaling', ColumnTransformer([
            ('pass-through-categorical', 'passthrough', list(range(NB_CATEGORICAL_FEATURES))),
            ('scaling-continuous', StandardScaler(copy=False), list(range(NB_CATEGORICAL_FEATURES,NB_FEATURES)))
        ])),
        ('classifier', RandomForestClassifier(
            n_estimators=100,
            max_depth=24,
            random_state=42, # enables deterministic behaviour
            n_jobs=-1
        ))
    ])

rf_testing_pipeline = get_random_forest_model()
rf_testing_pipeline.fit(X_train_valid[:, 2:], y_train_valid)
X_test_selected_night = X_test[X_test[:,1] == NIGHT[0]]
y_test_selected_night = y_test[X_test[:,1] == NIGHT[0]]

rf_y_test_pred = rf_testing_pipeline.predict(X_test_selected_night[:,2:])
rf_y_test_pred = hmm_model.predict(rf_y_test_pred.reshape(-1, 1))

print(confusion_matrix(y_test_selected_night, rf_y_test_pred))
print(classification_report(y_test_selected_night, rf_y_test_pred, target_names=SLEEP_STAGES_VALUES.keys()))
print("Agreement score (Cohen Kappa): ", cohen_kappa_score(y_test_selected_night, rf_y_test_pred))<jupyter_output>[[398   8   1   0   2]
 [ 48  64  45   0  26]
 [  4  26 313   0  62]
 [  0   1  59  31   0]
 [  0   0   0   0 100]]
              precision    recall  f1-score   support

           W       0.88      0.97      0.93       409
          N1       0.65      0.35      0.45       183
          N2       0.75      0.77      0.76       405
          N3       1.00      0.34      0.51        91
         REM       0.53      1.00      0.69       100

    accuracy                           0.76      1188
   macro avg       0.76      0.69      0.67      1188
weighted avg       0.78      0.76      0.75      1188

Agreement score (Cohen Kappa):  0.6709289967448082<jupyter_text>Saving to display in performance page___She went to bed at 1989-07-04 00:18:00, so in UTC its 615514680.<jupyter_code>rf_hypnogram = {
    'timestamps': [
        int((datetime.fromtimestamp(615514680) + timedelta(seconds=index*EPOCH_DURATION)).timestamp())
        for index, stage in enumerate(rf_y_test_pred)
    ],
    'stages': [
        str(list(SLEEP_STAGES_VALUES.keys())[list(SLEEP_STAGES_VALUES.values()).index(stage)])
        for index, stage in enumerate(rf_y_test_pred)
    ]
}

with open('data/predicted_woman78yo_sleepedf.json', 'w') as fp:
    json.dump(dict(epochs=rf_hypnogram), fp)
voting_hypnogram = {
    'timestamps': [int((datetime.fromtimestamp(615514680) + timedelta(seconds=index*EPOCH_DURATION)).timestamp()) for index, stage in enumerate(voting_y_test_pred)],
    'stages': [str(list(SLEEP_STAGES_VALUES.keys())[list(SLEEP_STAGES_VALUES.values()).index(stage)]) for index, stage in enumerate(voting_y_test_pred)]
}<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10010537407797682, 'fraction_numerical': 0.050111228193419975, 'mean_word_length': 2.9934548854604954, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '388106', 'license': 'MIT', 'n_tokens_mistral': 3272, 'n_tokens_neox': 3014, 'n_words': 551, 'path': 'ai/prediction_anonymous_classifier.ipynb', 'repo_name': 'PolyCortex/polydodo', 'size': '8541'}