Georg Willer commited on
Commit
800538f
·
1 Parent(s): 354dfd6

Extend calculated features to support time, frequency and non_linear domain

Browse files
Files changed (2) hide show
  1. rpeaks2hrv.py +56 -8
  2. 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
- # TODO: Implement hrv_time on windows
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
- hrv_time = nk.hrv(self._convert_format(window), sampling_rate)
22
- hrv_time['window_start'] = window.index[0]
23
- hrv_time['window_end'] = window.index[-1]
24
- hrv_values = pd.concat([hrv_values, hrv_time], ignore_index=True)
25
  return hrv_values
26
  else:
27
- return nk.hrv_time(self._convert_format(refined_data), sampling_rate)
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