Georg Willer
commited on
Commit
·
800538f
1
Parent(s):
354dfd6
Extend calculated features to support time, frequency and non_linear domain
Browse files- rpeaks2hrv.py +56 -8
- rpeaks_2_hrv_pipeline.py +5 -3
rpeaks2hrv.py
CHANGED
@@ -7,24 +7,59 @@ class WindowingMethod(Enum):
|
|
7 |
FIRST_INTERVAL = 'first_interval'
|
8 |
LAST_INTERVAL = 'last_interval'
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
class RPeak2HRV():
|
12 |
|
13 |
-
def get_hrv_features(self, input, windowing_method:str = None, time_header = "SystemTime", rri_header = "interbeat_interval", window_size = "60s", sampling_rate = 1000):
|
14 |
data = self._load_data(input)
|
15 |
refined_data = self._refine_dataframe(input=data, sampling_rate=sampling_rate, time_header=time_header, rri_header=rri_header)
|
16 |
if (windowing_method != None):
|
17 |
windows = self._apply_windowing(data=refined_data, method=windowing_method, window_size= window_size)
|
18 |
-
|
19 |
-
hrv_values = pd.DataFrame(columns=['window_start', 'window_end', 'HRV_MeanNN', 'HRV_SDNN', 'HRV_SDANN1', 'HRV_SDNNI1', 'HRV_SDANN2', 'HRV_SDNNI2', 'HRV_SDANN5', 'HRV_SDNNI5', 'HRV_RMSSD', 'HRV_SDSD', 'HRV_CVNN', 'HRV_CVSD', 'HRV_MedianNN', 'HRV_MadNN', 'HRV_MCVNN', 'HRV_IQRNN', 'HRV_SDRMSSD', 'HRV_Prc20NN', 'HRV_Prc80NN', 'HRV_pNN50', 'HRV_pNN20', 'HRV_MinNN', 'HRV_MaxNN', 'HRV_HTI', 'HRV_TINN'])
|
20 |
for window in windows:
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
hrv_values = pd.concat([hrv_values,
|
25 |
return hrv_values
|
26 |
else:
|
27 |
-
return
|
28 |
|
29 |
def _load_data(self, input):
|
30 |
if isinstance(input, str):
|
@@ -129,5 +164,18 @@ class RPeak2HRV():
|
|
129 |
}
|
130 |
return data_for_pipeline
|
131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
|
|
|
7 |
FIRST_INTERVAL = 'first_interval'
|
8 |
LAST_INTERVAL = 'last_interval'
|
9 |
|
10 |
+
class FeatureDomain(Enum):
|
11 |
+
TIME = 'time'
|
12 |
+
FREQUENCY = 'freq'
|
13 |
+
NON_LINEAR = 'non_lin'
|
14 |
+
|
15 |
+
|
16 |
+
FEATURE_COLS = {
|
17 |
+
FeatureDomain.TIME: [
|
18 |
+
'HRV_MeanNN', 'HRV_SDNN', 'HRV_SDANN1', 'HRV_SDNNI1',
|
19 |
+
'HRV_SDANN2', 'HRV_SDNNI2', 'HRV_SDANN5', 'HRV_SDNNI5',
|
20 |
+
'HRV_RMSSD', 'HRV_SDSD', 'HRV_CVNN', 'HRV_CVSD', 'HRV_MedianNN',
|
21 |
+
'HRV_MadNN', 'HRV_MCVNN', 'HRV_IQRNN', 'HRV_SDRMSSD', 'HRV_Prc20NN', 'HRV_Prc80NN',
|
22 |
+
'HRV_pNN50', 'HRV_pNN20', 'HRV_MinNN', 'HRV_MaxNN', 'HRV_HTI', 'HRV_TINN'],
|
23 |
+
FeatureDomain.FREQUENCY: [
|
24 |
+
'HRV_ULF', 'HRV_VLF', 'HRV_LF', 'HRV_HF', 'HRV_VHF', 'HRV_TP',
|
25 |
+
'HRV_LFHF', 'HRV_LFn', 'HRV_HFn', 'HRV_LnHF'
|
26 |
+
],
|
27 |
+
FeatureDomain.NON_LINEAR: [
|
28 |
+
'HRV_SD1', 'HRV_SD2', 'HRV_SD1SD2', 'HRV_S', 'HRV_CSI', 'HRV_CVI',
|
29 |
+
'HRV_CSI_Modified', 'HRV_PIP', 'HRV_IALS', 'HRV_PSS', 'HRV_PAS',
|
30 |
+
'HRV_GI', 'HRV_SI', 'HRV_AI', 'HRV_PI', 'HRV_C1d', 'HRV_C1a',
|
31 |
+
'HRV_SD1d', 'HRV_SD1a', 'HRV_C2d', 'HRV_C2a', 'HRV_SD2d', 'HRV_SD2a',
|
32 |
+
'HRV_Cd', 'HRV_Ca', 'HRV_SDNNd', 'HRV_SDNNa', 'HRV_DFA_alpha1',
|
33 |
+
'HRV_MFDFA_alpha1_Width', 'HRV_MFDFA_alpha1_Peak',
|
34 |
+
'HRV_MFDFA_alpha1_Mean', 'HRV_MFDFA_alpha1_Max',
|
35 |
+
'HRV_MFDFA_alpha1_Delta', 'HRV_MFDFA_alpha1_Asymmetry',
|
36 |
+
'HRV_MFDFA_alpha1_Fluctuation', 'HRV_MFDFA_alpha1_Increment',
|
37 |
+
'HRV_DFA_alpha2', 'HRV_MFDFA_alpha2_Width', 'HRV_MFDFA_alpha2_Peak',
|
38 |
+
'HRV_MFDFA_alpha2_Mean', 'HRV_MFDFA_alpha2_Max',
|
39 |
+
'HRV_MFDFA_alpha2_Delta', 'HRV_MFDFA_alpha2_Asymmetry',
|
40 |
+
'HRV_MFDFA_alpha2_Fluctuation', 'HRV_MFDFA_alpha2_Increment',
|
41 |
+
'HRV_ApEn', 'HRV_SampEn', 'HRV_ShanEn', 'HRV_FuzzyEn', 'HRV_MSEn',
|
42 |
+
'HRV_CMSEn', 'HRV_RCMSEn', 'HRV_CD', 'HRV_HFD', 'HRV_KFD', 'HRV_LZC'
|
43 |
+
]
|
44 |
+
}
|
45 |
+
|
46 |
|
47 |
class RPeak2HRV():
|
48 |
|
49 |
+
def get_hrv_features(self, input, windowing_method:str = None, time_header = "SystemTime", rri_header = "interbeat_interval", window_size = "60s", feature_domains = [FeatureDomain.TIME, FeatureDomain.FREQUENCY, FeatureDomain.NON_LINEAR], sampling_rate = 1000):
|
50 |
data = self._load_data(input)
|
51 |
refined_data = self._refine_dataframe(input=data, sampling_rate=sampling_rate, time_header=time_header, rri_header=rri_header)
|
52 |
if (windowing_method != None):
|
53 |
windows = self._apply_windowing(data=refined_data, method=windowing_method, window_size= window_size)
|
54 |
+
hrv_values = pd.DataFrame()
|
|
|
55 |
for window in windows:
|
56 |
+
hrv_feature_values = self._calculate_features(window,feature_domains,sampling_rate)
|
57 |
+
hrv_feature_values['window_start'] = window.index[0]
|
58 |
+
hrv_feature_values['window_end'] = window.index[-1]
|
59 |
+
hrv_values = pd.concat([hrv_values, hrv_feature_values], ignore_index=True)
|
60 |
return hrv_values
|
61 |
else:
|
62 |
+
return self._calculate_features(refined_data, feature_domains, sampling_rate)
|
63 |
|
64 |
def _load_data(self, input):
|
65 |
if isinstance(input, str):
|
|
|
164 |
}
|
165 |
return data_for_pipeline
|
166 |
|
167 |
+
def _calculate_features(self, data, feature_domains, sampling_rate):
|
168 |
+
# Calculate all possible features, then only keep needed
|
169 |
+
hrv_features = []
|
170 |
+
for feature in feature_domains:
|
171 |
+
try:
|
172 |
+
hrv_features.extend(FEATURE_COLS[feature])
|
173 |
+
except KeyError:
|
174 |
+
raise KeyError(f"{feature} is not a supported feature domain. feature_domains may only include 'time', 'freq' and 'non_lin'.")
|
175 |
+
result = nk.hrv(self._convert_format(data), sampling_rate)
|
176 |
+
return result[hrv_features]
|
177 |
+
|
178 |
+
|
179 |
+
|
180 |
|
181 |
|
rpeaks_2_hrv_pipeline.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
from transformers import Pipeline
|
2 |
-
from .rpeaks2hrv import RPeak2HRV
|
3 |
|
4 |
class RPeak2HRVPipeline(Pipeline):
|
5 |
rpeak2HRVExtractor = RPeak2HRV()
|
@@ -16,10 +16,12 @@ class RPeak2HRVPipeline(Pipeline):
|
|
16 |
preprocess_kwargs["rri_header"] = kwargs["rri_header"]
|
17 |
if "window_size" in kwargs:
|
18 |
preprocess_kwargs["window_size"] = kwargs["window_size"]
|
|
|
|
|
19 |
return preprocess_kwargs, {}, {}
|
20 |
|
21 |
-
def preprocess(self, inputs, windowing_method:str = None, time_header = "SystemTime", rri_header = "interbeat_interval", window_size = "60s", sampling_rate = 1000):
|
22 |
-
return self.rpeak2HRVExtractor.get_hrv_features(inputs, windowing_method=windowing_method, time_header=time_header, rri_header=rri_header, window_size=window_size, sampling_rate=sampling_rate)
|
23 |
|
24 |
def _forward(self, model_inputs):
|
25 |
# currently empty as all preprocessing steps are performed by preprocess function
|
|
|
1 |
from transformers import Pipeline
|
2 |
+
from .rpeaks2hrv import RPeak2HRV, FeatureDomain
|
3 |
|
4 |
class RPeak2HRVPipeline(Pipeline):
|
5 |
rpeak2HRVExtractor = RPeak2HRV()
|
|
|
16 |
preprocess_kwargs["rri_header"] = kwargs["rri_header"]
|
17 |
if "window_size" in kwargs:
|
18 |
preprocess_kwargs["window_size"] = kwargs["window_size"]
|
19 |
+
if "feature_domains" in kwargs:
|
20 |
+
preprocess_kwargs["feature_domains"] = kwargs["feature_domains"]
|
21 |
return preprocess_kwargs, {}, {}
|
22 |
|
23 |
+
def preprocess(self, inputs, windowing_method:str = None, time_header = "SystemTime", rri_header = "interbeat_interval", window_size = "60s", feature_domains = [FeatureDomain.TIME, FeatureDomain.FREQUENCY, FeatureDomain.NON_LINEAR], sampling_rate = 1000):
|
24 |
+
return self.rpeak2HRVExtractor.get_hrv_features(inputs, windowing_method=windowing_method, time_header=time_header, rri_header=rri_header, window_size=window_size, feature_domains=feature_domains, sampling_rate=sampling_rate)
|
25 |
|
26 |
def _forward(self, model_inputs):
|
27 |
# currently empty as all preprocessing steps are performed by preprocess function
|