Source code for pyVHR.utils.errors

import numpy as np
import plotly.graph_objects as go
from pyVHR.plot.visualize import VisualizeParams


[docs]def getErrors(bpmES, bpmGT, timesES, timesGT): if type(bpmES) == list: bpmES = np.expand_dims(bpmES, axis=0) if type(bpmES) == np.ndarray: if len(bpmES.shape) == 1: bpmES = np.expand_dims(bpmES, axis=0) RMSE = RMSEerror(bpmES, bpmGT, timesES, timesGT) MAE = MAEerror(bpmES, bpmGT, timesES, timesGT) MAX = MAXError(bpmES, bpmGT, timesES, timesGT) PCC = PearsonCorr(bpmES, bpmGT, timesES, timesGT) CCC = LinCorr(bpmES, bpmGT, timesES, timesGT) return RMSE, MAE, MAX, PCC, CCC
[docs]def RMSEerror(bpmES, bpmGT, timesES=None, timesGT=None): """ RMSE: """ diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length df = np.zeros(n) for j in range(m): for c in range(n): df[c] += np.power(diff[c, j], 2) # -- final RMSE RMSE = np.sqrt(df/m) return RMSE
[docs]def MAEerror(bpmES, bpmGT, timesES=None, timesGT=None): """ MAE: """ diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length df = np.sum(np.abs(diff), axis=1) # -- final MAE MAE = df/m return MAE
[docs]def MAXError(bpmES, bpmGT, timesES=None, timesGT=None): """ MAE: """ diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length df = np.max(np.abs(diff), axis=1) # -- final MAE MAX = df return MAX
[docs]def PearsonCorr(bpmES, bpmGT, timesES=None, timesGT=None): from scipy import stats diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length CC = np.zeros(n) for c in range(n): # -- corr r, p = stats.pearsonr(diff[c, :]+bpmES[c, :], bpmES[c, :]) CC[c] = r return CC
[docs]def LinCorr(bpmES, bpmGT, timesES=None, timesGT=None): diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length CCC = np.zeros(n) for c in range(n): # -- Lin's Concordance Correlation Coefficient ccc = concordance_correlation_coefficient(bpmES[c, :], diff[c, :]+bpmES[c, :]) CCC[c] = ccc return CCC
[docs]def printErrors(RMSE, MAE, MAX, PCC, CCC): print("\n * Errors: RMSE = %.2f, MAE = %.2f, MAX = %.2f, PCC = %.2f, CCC = %.2f" % (RMSE, MAE, MAX, PCC, CCC))
[docs]def displayErrors(bpmES, bpmGT, timesES=None, timesGT=None): if type(bpmES) == list: bpmES = np.expand_dims(bpmES, axis=0) if type(bpmES) == np.ndarray: if len(bpmES.shape) == 1: bpmES = np.expand_dims(bpmES, axis=0) if (timesES is None) or (timesGT is None): timesES = np.arange(m) timesGT = timesES diff = bpm_diff(bpmES, bpmGT, timesES, timesGT) n, m = diff.shape # n = num channels, m = bpm length df = np.abs(diff) dfMean = np.around(np.mean(df, axis=1), 1) # -- plot errors fig = go.Figure() name = 'Ch 1 (µ = ' + str(dfMean[0]) + ' )' fig.add_trace(go.Scatter( x=timesES, y=df[0, :], name=name, mode='lines+markers')) if n > 1: name = 'Ch 2 (µ = ' + str(dfMean[1]) + ' )' fig.add_trace(go.Scatter( x=timesES, y=df[1, :], name=name, mode='lines+markers')) name = 'Ch 3 (µ = ' + str(dfMean[2]) + ' )' fig.add_trace(go.Scatter( x=timesES, y=df[2, :], name=name, mode='lines+markers')) fig.update_layout(xaxis_title='Times (sec)', yaxis_title='MAE', showlegend=True) fig.show(renderer=VisualizeParams.renderer) # -- plot bpm Gt and ES fig = go.Figure() GTmean = np.around(np.mean(bpmGT), 1) name = 'GT (µ = ' + str(GTmean) + ' )' fig.add_trace(go.Scatter(x=timesGT, y=bpmGT, name=name, mode='lines+markers')) ESmean = np.around(np.mean(bpmES[0, :]), 1) name = 'ES1 (µ = ' + str(ESmean) + ' )' fig.add_trace(go.Scatter( x=timesES, y=bpmES[0, :], name=name, mode='lines+markers')) if n > 1: ESmean = np.around(np.mean(bpmES[1, :]), 1) name = 'ES2 (µ = ' + str(ESmean) + ' )' fig.add_trace(go.Scatter( x=timesES, y=bpmES[1, :], name=name, mode='lines+markers')) ESmean = np.around(np.mean(bpmES[2, :]), 1) name = 'E3 (µ = ' + str(ESmean) + ' )' fig.add_trace(go.Scatter( x=timesES, y=bpmES[2, :], name=name, mode='lines+markers')) fig.update_layout(xaxis_title='Times (sec)', yaxis_title='BPM', showlegend=True) fig.show(renderer=VisualizeParams.renderer)
[docs]def bpm_diff(bpmES, bpmGT, timesES=None, timesGT=None): n, m = bpmES.shape # n = num channels, m = bpm length if (timesES is None) or (timesGT is None): timesES = np.arange(m) timesGT = timesES diff = np.zeros((n, m)) for j in range(m): t = timesES[j] i = np.argmin(np.abs(t-timesGT)) for c in range(n): diff[c, j] = bpmGT[i]-bpmES[c, j] return diff
[docs]def concordance_correlation_coefficient(bpm_true, bpm_pred): cor=np.corrcoef(bpm_true, bpm_pred)[0][1] mean_true = np.mean(bpm_true) mean_pred = np.mean(bpm_pred) var_true = np.var(bpm_true) var_pred = np.var(bpm_pred) sd_true = np.std(bpm_true) sd_pred = np.std(bpm_pred) numerator = 2*cor*sd_true*sd_pred denominator = var_true + var_pred + (mean_true - mean_pred)**2 return numerator/denominator