Source code for systole.hrv

# Author: Nicolas Legrand <nicolas.legrand@cfin.au.dk>

from typing import Dict, List, Optional, Tuple, Union

import numpy as np
import pandas as pd
from numba import jit
from scipy import interpolate
from scipy.signal import welch
from scipy.spatial.distance import cdist

from systole.utils import input_conversion


[docs] def nnX(rr: Union[List, np.ndarray], t: int = 50, input_type: str = "rr_ms") -> int: """Number of difference in successive R-R interval > t ms. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). t : Threshold value: Defaut is set to 50 ms to calculate the nn50 index. input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- nnX : The number of successive differences larger than a value. """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") if len(rr.shape) > 1: raise ValueError("X must be a 1darray") # NN50: number of successive differences larger than t ms nn = np.sum(np.abs(np.diff(rr)) > t).astype(int) return nn
[docs] def pnnX(rr: Union[List, np.ndarray], t: int = 50, input_type: str = "rr_ms") -> float: """Number of successive differences larger than a value (def = 50ms). Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). t : Threshold value: Defaut is set to 50 ms to calculate the nn50 index. input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- nn : The proportion of successive differences larger than a value (%). """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") if len(rr.shape) > 1: raise ValueError("X must be a 1darray") # nnX: number of successive differences larger than t ms nn = nnX(rr, t) # Proportion of successive differences larger than t ms pnnX = 100 * nn / len(np.diff(rr)) return pnnX
[docs] def rmssd(rr: Union[List, np.ndarray], input_type: str = "rr_ms") -> float: """Root Mean Square of Successive Differences. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- y : The Root Mean Square of Successive Differences (RMSSD). Examples -------- >>> rr = [800, 850, 810, 720] >>> rmssd(rr) 63.77042156569664 """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") if len(rr.shape) > 1: raise ValueError("X must be a 1darray") y = np.sqrt(np.mean(np.square(np.diff(rr)))) return y
[docs] def time_domain(rr: Union[List, np.ndarray], input_type: str = "rr_ms") -> pd.DataFrame: """Extract all time domain parameters from R-R intervals. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- stats : Time domain summary statistics. * 'MeanRR' : Mean of R-R intervals (ms). * 'MeanBPM' : Mean of beats per minutes (bpm). * 'MedianRR' : Median of R-R intervals' (ms). * 'MedianBPM' : Median of beats per minutes (bpm). * 'MinRR' : Minimum R-R intervals (ms). * 'MinBPM' : Minimum beats per minutes (bpm). * 'MaxRR' : Maximum R-R intervals (ms). * 'MaxBPM' : Maximum beats per minutes (bpm). * 'SDNN' : Standard deviation of RR intervals (ms). * 'SDSD' : Standard deviation of the Successive difference (ms). * 'RMSSD' : Root Mean Square of the Successive Differences (ms). * 'nn50' : number of successive differences larger than 50ms (count). * 'pnn50' : Proportion of successive difference larger than 50ms (%). See also -------- frequency_domain, nonlinear_domain Notes ----- The dataframe containing the summary statistics is returned in the long format to facilitate the creation of group summary data frame that can easily be transferred to other plotting or statistics library. You can easily convert it into a wide format for a subject-level inline report using the:py:func:`pandas.pivot_table` function: >>> pd.pivot_table(stats, values='Values', columns='Metric') All time-domain results have been tested against Kubios HVR 2.2 (<https://www.kubios.com>). """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") if len(rr.shape) > 1: raise ValueError("X must be a 1darray") # Mean R-R intervals mean_rr = round(np.mean(rr), 6) # type: ignore # Mean BPM mean_bpm = round(np.mean(60000 / rr), 6) # type: ignore # Median BPM median_rr = round(np.median(rr), 6) # Median BPM median_bpm = round(np.median(60000 / rr), 6) # Minimum RR min_rr = round(np.min(rr), 6) # Minimum BPM min_bpm = round(np.min(60000 / rr), 6) # Maximum RR max_rr = round(np.max(rr), 6) # Maximum BPM max_bpm = round(np.max(60000 / rr), 6) # Standard deviation of R-R intervals sdnn = round(rr.std(ddof=1), 6) # type: ignore # Standard deviation of the difference of successive R-R intervals sdsd = round(np.diff(rr).std(ddof=1), 6) # type: ignore # Root Mean Square of Successive Differences (RMSSD) rms = round(rmssd(rr), 6) # NN50: number of successive differences larger than 50ms nn = round(nnX(rr, t=50), 6) # pNN50: Proportion of successive differences larger than 50ms pnn = round(pnnX(rr, t=50), 6) # Create summary dataframe values = [ mean_rr, mean_bpm, median_rr, median_bpm, min_rr, min_bpm, max_rr, max_bpm, sdnn, sdsd, rms, nn, pnn, ] metrics = [ "MeanRR", "MeanBPM", "MedianRR", "MedianBPM", "MinRR", "MinBPM", "MaxRR", "MaxBPM", "SDNN", "SDSD", "RMSSD", "nn50", "pnn50", ] stats = pd.DataFrame({"Values": values, "Metric": metrics}) return stats
[docs] def psd( rr: Union[List, np.ndarray], sfreq: int = 5, method: str = "welch", input_type: str = "rr_ms", ) -> Tuple[np.ndarray, np.ndarray]: """Extract the frequency domain features of heart rate variability. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). sfreq : The sampling frequency (Hz) of the interpolated instantaneous heart rate. method : The method used to extract freauency power. Default is ``'welch'``. input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- freq, power : The frequency and power spectral density of the given signal. See also -------- frequency_domain """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") # Interpolate R-R interval time = np.cumsum(rr) f = interpolate.interp1d(time, rr, kind="cubic") new_time = np.arange(time[0], time[-1], 1000 / sfreq) # sfreq = 5 Hz x = f(new_time) if method == "welch": # Define window length nperseg = 256 * sfreq if nperseg > len(x): nperseg = len(x) # Compute Power Spectral Density freq, power = welch(x=x, fs=sfreq, nperseg=nperseg, nfft=nperseg) power = power / 1000000 return freq, power
[docs] def frequency_domain( rr: Union[List, np.ndarray], sfreq: int = 5, method: str = "welch", fbands: Optional[Dict[str, Tuple[str, Tuple[float, float], str]]] = None, input_type: str = "rr_ms", ) -> pd.DataFrame: """Extract the frequency domain features of heart rate variability. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). sfreq : The sampling frequency (Hz) used to interpolate the instantaneous heart rate for PSD computation. method : The method used to extract the power of the different frequency bands. Default is ``'welch'`` (only one method is implemented for now). fbands : Dictionary containing the names of the frequency bands of interest (str), their range (tuples) and their color in the PSD plot. Default is >>> {'vlf': ('Very low frequency', (0.003, 0.04), 'b'), >>> 'lf': ('Low frequency', (0.04, 0.15), 'g'), >>> 'hf': ('High frequency', (0.15, 0.4), 'r')} input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- stats : Frequency domain summary statistics. * 'vlf_peak' : Very low frequency peak (HZ). * 'vlf_power' : Very low frequency power (ms²). * 'lf_peak' : Low frquency peak (Hz). * 'lf_power' : Low frequency power (ms²). * 'hf_peak' : High frequency peak (Hz). * 'hf_power' : High frequency power (ms²). * 'vlf_power_per' : Very low frequency power (%). * 'lf_power_per' : Low frequency power (%). * 'hf_power_per' : High frequency power (%). * 'lf_power_nu' : Low frequency power (normalized units). * 'hf_power_nu' : High frequency power (normalized units). * 'total_power' : Total frequency power (ms²). * 'lf_hf_ratio' : Low / high frequency ratio (normalized units). See also -------- time_domain, nonlinear Notes ----- The dataframe containing the summary statistics is returned in the long format to facilitate the creation of group summary data frame that can easily be transferred to other plotting or statistics library. You can easily convert it into a wide format for a subject-level inline report using the:py:func:`pandas.pivot_table` function: >>> pd.pivot_table(stats, values='Values', columns='Metric') .. warning:: All frequency-domain results have been tested against Kubios HVR 2.2 (<https://www.kubios.com>). These results can slightly differ due to different parametrization of the PSD estimation. We recommend to always check your results against another software. """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") freq, power = psd(rr=rr, sfreq=sfreq, method=method, input_type="rr_ms") if fbands is None: fbands = { "vlf": ("Very low frequency", (0.003, 0.04), "b"), "lf": ("Low frequency", (0.04, 0.15), "g"), "hf": ("High frequency", (0.15, 0.4), "r"), } # Extract HRV parameters ######################## stats = pd.DataFrame([]) for band in fbands: this_psd = power[(freq >= fbands[band][1][0]) & (freq < fbands[band][1][1])] this_freq = freq[(freq >= fbands[band][1][0]) & (freq < fbands[band][1][1])] # Peaks (Hz) peak = round(this_freq[np.argmax(this_psd)], 6) stats = pd.concat( [ stats, pd.DataFrame({"Values": peak, "Metric": band + "_peak"}, index=[0]), ], ignore_index=True, ) # Power (ms**2) this_power = np.trapz(x=this_freq, y=this_psd) * 1000000 stats = pd.concat( [ stats, pd.DataFrame( {"Values": this_power, "Metric": band + "_power"}, index=[0] ), ], ignore_index=True, ) # Power (ms**2) hf = stats.Values[stats.Metric == "hf_power"].values[0] lf = stats.Values[stats.Metric == "lf_power"].values[0] vlf = stats.Values[stats.Metric == "vlf_power"].values[0] total_power = vlf + lf + hf lf_hf_ratio = lf / hf # Power (%) power_per_vlf = vlf / (vlf + lf + hf) * 100 power_per_lf = lf / (vlf + lf + hf) * 100 power_per_hf = hf / (vlf + lf + hf) * 100 # Power (n.u.) power_nu_hf = hf / (hf + lf) * 100 power_nu_lf = lf / (hf + lf) * 100 values = [ power_per_vlf, power_per_lf, power_per_hf, power_nu_lf, power_nu_hf, total_power, lf_hf_ratio, ] metrics = [ "vlf_power_per", "lf_power_per", "hf_power_per", "lf_power_nu", "hf_power_nu", "total_power", "lf_hf_ratio", ] stats = pd.concat( [stats, pd.DataFrame({"Values": values, "Metric": metrics})], ignore_index=True ) return stats
[docs] def nonlinear_domain( rr: Union[List, np.ndarray], input_type: str = "rr_ms" ) -> pd.DataFrame: """Extract the non-linear features of heart rate variability. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- stats : Nonlinear domain summary statistics. * 'SD1' : SD1, the standard deviation of the poincare plot orthogonal to the identity line (ms). * 'SD2' : SD2, the standard deviation of the poincare plot along the identity line (ms). * 'recurrence_rate' : The recurrence rate in the recurrence plot (%). * 'l_max' : The maximun diagonal length in the recurrence plot (beats). * 'l_mean' : The mean diagonal length in the recurrence plot (beats). * 'determinism_rate' : The determinism rate in the recurrence plot (%). * 'shannon_entropy' : The Shannon entropy. See also -------- time_domain, frequency_domain, poincare, rec Notes ----- The dataframe containing the summary statistics is returned in the long format to facilitate the creation of group summary data frame that can easily be transferred to other plotting or statistics library. You can easily convert it into a wide format for a subject-level inline report using the py:pandas.pivot_table() function: >>> pd.pivot_table(stats, values='Values', columns='Metric') .. warning:: The recurrence plots results does not reproduce what is obtained using Kubios (3.5.0) and should be used with caution for now. References ---------- .. [1] M. Brennan, M. Palaniswami, and P. Kamen. Do existing measures of Poincaré plot geometry reflect nonlinear features of heart rate variability. IEEE Trans Biomed Eng, 48(11):1342–1347, 2001. .. [2] H. Dabire, D. Mestivier, J. Jarnet, M.E. Safar, and N. Phong Chau. Quantification of sympathetic and parasympathetic tones by nonlinear indexes in normotensive rats. amj, 44:H1290–H1297, 1998. """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") # Pointcare plot sd1, sd2 = poincare(rr, input_type="rr_ms") # Recurrence plot recurrence_rate, l_max, l_mean, determinism, shan_entr = recurrence( rr, input_type="rr_ms" ) values = [sd1, sd2, recurrence_rate, l_max, l_mean, determinism, shan_entr] metrics = [ "SD1", "SD2", "recurrence_rate", "l_max", "l_mean", "determinism_rate", "shannon_entropy", ] stats = pd.DataFrame({"Values": values, "Metric": metrics}) return stats
[docs] def poincare( rr: Union[List, np.ndarray], input_type: str = "rr_ms" ) -> Tuple[float, float]: """Compute SD1 and SD2 from the Poincaré nonlinear method for heart rate variability. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- sd1 : The standard deviation of the points perpendicular to the identity line. This metric is thought to be influenced mainly by the respiratory sinus arythmia (RSA) and reflect short-term heart rate variability. sd2 : The standard deviation of the points along the identity line. This metric is thought to reflect the long-term heart rate variability. See also -------- nonlinear_domain, recurrence Notes ----- The Poincare plot is a commonly used nonlinear method that is based on the graphical representation of the correlation between lagged successive RR intervals (the :math:`\\RR_{n}` intervals are plotted as a function of the :math:`\\RR_{n+1}`) intervals. The shape of the resulting plot is then analyzed and two metrics are extracted, representing the standard deviation of the distribution perpendicular to the identity line (SD1) and along the identity line (SD2). SD1, which corresponds to the standard deviation of the points perpendicular to the identity line, reflects short-term variability and is thought to be caused by respiratory sinus arrhythmia (RSA). SD2, on the other side, the standard deviation along the identity line, corresponds to the long-term heart rate variability. References ---------- .. [1] https://en.wikipedia.org/wiki/Poincar%C3%A9_plot .. [2] M. Brennan, M. Palaniswami, and P. Kamen. Do existing measures of Poincaré plot geometry reflect nonlinear features of heart rate variability. IEEE Trans Biomed Eng, 48(11):1342–1347, 2001. """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") sd1, sd2 = _poincare(rr) return sd1, sd2
@jit(nopython=True) def _poincare(rr: np.ndarray) -> Tuple[float, float]: """Compute SD1 and SD2 from the Poincaré nonlinear method for heart rate variability.""" diff_rr = np.diff(rr) sd1 = np.sqrt(np.std(diff_rr) ** 2 * 0.5) sd2 = np.sqrt(2 * np.std(rr) ** 2 - 0.5 * np.std(diff_rr) ** 2) return sd1, sd2
[docs] def recurrence( rr: Union[List, np.ndarray], input_type: str = "rr_ms" ) -> Tuple[float, int, float, float, float]: """Compute quantitative metrics from the recurrence plot for heart rate variability. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- recurrence_rate : The percentage of recurence in the time series. This corresponds to the ratio of ones and zeros in the recurrence plot. l_max : Maximum lenght of the diagonale in the reccurence plot. l_mean : Mean of the diagonals lengths observed in the recurence plot. determinism_rate : The percentage of determinism in the time series. shan_entr : Shannon information entropy. .. warning:: The recurrence plots results does not reproduce what is obtained using Kubios (3.5.0) and should be used with caution for now. See also -------- nonlinear_domain, poincare References ---------- .. [1] H. Dabire, D. Mestivier, J. Jarnet, M.E. Safar, and N. Phong Chau. Quantification of sympathetic and parasympathetic tones by nonlinear indexes in normotensive rats. amj, 44:H1290–H1297, 1998. .. [2] C.L. Webber Jr. and J.P. Zbilut. Dynamical assessment of physiological systems and states using recurrence plot strategies. J Appl Physiol, 76:965–973, 1994. .. [3] Zbilut J. P., Webber C. L., Zak M.Quantification of heart rate variability using methods derived from nonlinear dynamics.Assessment and Analysis of Cardiovascular Function, Drzewiecki G., Li J. K.-J. Springer New York. """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") recurrence_rate, l_max, l_mean, determinism_rate, shan_entr = _recurrence(rr) return recurrence_rate, l_max, l_mean, determinism_rate, shan_entr
def _recurrence( rr: np.ndarray, m: int = 10, l_min: int = 2 ) -> Tuple[float, int, float, float, float]: """Compute recurrence scores""" # Recurrence matrix rc = recurrence_matrix(rr) # Compute the recurrence rate - Exclude the main identity line j = rc.shape[0] recurrence_rate = np.triu(rc).sum() / ((j**2 - j) / 2) * 100 # Find diagonale lines total_lines: List[int] = [] for i in range(1, rc.shape[0] // 2): # All diagonals except the main one diag = np.diagonal(rc, offset=i) # Lenght of each diagonale found with consecutive `True` values d = np.diff( np.where(np.concatenate(([diag[0]], diag[:-1] != diag[1:], [True])))[0] )[::2] # Store the result if any if d.shape[0] > 0: total_lines.extend(d) # Compute scores l_max = np.max(total_lines) # Diagonales from upper and lower triangle l_lines = np.asarray(total_lines).repeat(2) # Exclude small digonales (< l_min, default to 2) l_lines = l_lines[np.where(l_lines > l_min)[0]] # Average length of diagonales l_mean = l_lines.mean() # Determinism - Do not include the main diagonale determinism_rate = (l_lines.sum() / (np.sum(rc) - j)) * 100 # Shannon information entropy _, counts = np.unique(l_lines, return_counts=True) shan_entr = -(np.log(counts / len(l_lines)) * (counts / len(l_lines))).sum() return ( float(recurrence_rate), int(l_max), float(l_mean), float(determinism_rate), float(shan_entr), )
[docs] def recurrence_matrix(rr: np.ndarray, m: int = 10, tau: int = 1) -> np.ndarray: """Compute the recurrence matrix from an array of RR intervals [1]_. Parameters ---------- rr : R-R interval time-series. Can be in seconds or miliseconds. m : The embedding dimension. This corresponds to the length of the subsamples. Defaults to `10`. tau : The embedding lag. This corresponds to the number of datapoints that are skipped when creating the sub-sample. Defaults to `1` (take all values). Returns ------- rc : The recurrence matrix. References ---------- .. [1] H. Dabire, D. Mestivier, J. Jarnet, M.E. Safar, and N. Phong Chau. Quantification of sympathetic and parasympathetic tones by nonlinear indexes in normotensive rats. amj, 44:H1290–H1297, 1998. """ r = np.sqrt(m) * np.std(rr) # Threshold for the Euclidean distance lag = (m - 1) * tau # Lag N = rr.shape[0] # Size of the input signal j = N - lag # Dimension of the recurrence matrix Y = np.zeros((m, j)) # Initialize the time embedding matrix # Create a 2d array with segments of the signal lagged # according to tau and m (the embedding dimension) for i in range(m): k = i * tau Y[i] = rr[k : k + j] embedded = Y.T # Compute Euclidean distance d = cdist(embedded, embedded, metric="euclidean") # Initialize the recurrence matrix filled with 0s rc = np.zeros((j, j)) # If lower or equal to threshold, then 1 rc[d <= r] = 1 return rc
[docs] def all_domain(rr: Union[List, np.ndarray], input_type: str = "rr_ms") -> pd.DataFrame: """Extract all the HRV indices implemented for the time domain, frequency domain and linear domain. Parameters ---------- rr : R-R interval time-series, peaks or peaks index vectors. The default expected vector is R-R intervals in milliseconds. Other data format can be provided by specifying the `"input_type"` (can be `"rr_s"`, `"peaks"` or `"peaks_idx"`). input_type : The type of input provided. Can be `"peaks"`, `"peaks_idx"`, `"rr_ms"` or `"rr_s"`. Defaults to `"rr_ms"`. Returns ------- stats : Summary of the HRV indices extracted. * 'MeanRR' : Mean of R-R intervals (ms). * 'MeanBPM' : Mean of beats per minutes (bpm). * 'MedianRR' : Median of R-R intervals' (ms). * 'MedianBPM' : Median of beats per minutes (bpm). * 'MinRR' : Minimum R-R intervals (ms). * 'MinBPM' : Minimum beats per minutes (bpm). * 'MaxRR' : Maximum R-R intervals (ms). * 'MaxBPM' : Maximum beats per minutes (bpm). * 'SDNN' : Standard deviation of RR intervals (ms). * 'SDSD' : Standard deviation of the Successive difference (ms). * 'RMSSD' : Root Mean Square of the Successive Differences (ms). * 'nn50' : number of successive differences larger than 50ms (count). * 'pnn50' : Proportion of successive difference larger than 50ms (%). * 'vlf_peak' : Very low frequency peak (HZ). * 'vlf_power' : Very low frequency power (ms²). * 'lf_peak' : Low frquency peak (Hz). * 'lf_power' : Low frequency power (ms²). * 'hf_peak' : High frequency peak (Hz). * 'hf_power' : High frequency power (ms²). * 'vlf_power_per' : Very low frequency power (%). * 'lf_power_per' : Low frequency power (%). * 'hf_power_per' : High frequency power (%). * 'lf_power_nu' : Low frequency power (normalized units). * 'hf_power_nu' : High frequency power (normalized units). * 'total_power' : Total frequency power (ms²). * 'lf_hf_ratio' : Low / high frequency ratio (normalized units). * 'SD1' : SD1, the standard deviation of the poincare plot orthogonal to the identity line (ms). * 'SD2' : SD2, the standard deviation of the poincare plot along the identity line (ms). * 'recurrence_rate' : The recurrence rate in the recurrence plot (%). * 'l_max' : The maximun diagonal length in the recurrence plot (beats). * 'l_mean' : The mean diagonal length in the recurrence plot (beats). * 'determinism_rate' : The determinism rate in the recurrence plot (%). * 'shannon_entropy' : The Shannon entropy. See also -------- time_domain, frequency_domain, nonlinear_domain Notes ----- The dataframe containing the summary statistics is returned in the long format to facilitate the creation of group summary data frame that can easily be transferred to other plotting or statistics library. You can easily convert it into a wide format for a subject-level inline report using the py:pandas.pivot_table() function: >>> pd.pivot_table(stats, values='Values', columns='Metric') """ rr = np.asarray(rr) if input_type != "rr_ms": rr = input_conversion(rr, input_type=input_type, output_type="rr_ms") time_df = time_domain(rr, input_type="rr_ms") frequency_df = frequency_domain(rr, input_type="rr_ms") nonlinear_df = nonlinear_domain(rr, input_type="rr_ms") return pd.concat([time_df, frequency_df, nonlinear_df])