SleePyPhases 0.1.6__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/PKG-INFO +11 -2
  2. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/DataManipulation.py +9 -0
  3. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/Plugin.py +3 -0
  4. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/RecordFeatureExtraction.py +61 -20
  5. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/SignalPreprocessing.py +1 -1
  6. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/SleepMetaData.py +5 -1
  7. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/__init__.py +2 -1
  8. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/BuildDataset.py +1 -1
  9. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/Extract.py +3 -4
  10. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/Setup.py +6 -1
  11. sleepyphases-0.2.0/SleePyPhases/phases/TestRun.py +147 -0
  12. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases.egg-info/PKG-INFO +11 -2
  13. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases.egg-info/SOURCES.txt +1 -0
  14. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/setup.py +1 -1
  15. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_DataManipulation.py +27 -1
  16. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/LICENSE +0 -0
  17. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/README.md +0 -0
  18. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/EventScorer.py +0 -0
  19. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/FeatureExtraction copy.py +0 -0
  20. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/FeatureExtraction.py +0 -0
  21. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/MultiScorer.py +0 -0
  22. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/PSGEventManager.py +0 -0
  23. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/Plot.py +0 -0
  24. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/PreManipulation.py +0 -0
  25. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/Reporter.py +0 -0
  26. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/DataAnalysis.py +0 -0
  27. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/DataReport.py +0 -0
  28. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/Eval.py +0 -0
  29. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/EvalPlotExamples.py +0 -0
  30. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/EvalReport.py +0 -0
  31. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/ExportMetadataToMeticalDB.py +0 -0
  32. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/ExtractEvents.py +0 -0
  33. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/ExtractFeatures.py +0 -0
  34. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/ExtractRecordFeatures.py +0 -0
  35. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/GatherMetadata.py +0 -0
  36. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/ThresholdOptimisation.py +0 -0
  37. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/Training.py +0 -0
  38. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/Validation.py +0 -0
  39. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/VisualizeConfig.py +0 -0
  40. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/phases/__init__.py +0 -0
  41. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/recordloaders/MedicalDB.py +0 -0
  42. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/recordloaders/RecordLoaderTSM.py +0 -0
  43. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases/recordloaders/__init__.py +0 -0
  44. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases.egg-info/dependency_links.txt +0 -0
  45. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases.egg-info/requires.txt +0 -0
  46. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/SleePyPhases.egg-info/top_level.txt +0 -0
  47. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/pyproject.toml +0 -0
  48. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/setup.cfg +0 -0
  49. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/__init__.py +0 -0
  50. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/conftest.py +0 -0
  51. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/__init__.py +0 -0
  52. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_BuildDataset.py +0 -0
  53. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_BuildDatasetFolded.py +0 -0
  54. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_BuildDatasetSegments.py +0 -0
  55. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_Eval.py +0 -0
  56. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_EventScorer.py +0 -0
  57. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_Extract.py +0 -0
  58. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_PreManipulation.py +0 -0
  59. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_RecordFeatureExtraction.py +0 -0
  60. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_RecordProcessor.py +0 -0
  61. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_Setup.py +0 -0
  62. {sleepyphases-0.1.6 → sleepyphases-0.2.0}/tests/unit/test_SignalPreprocessing.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: SleePyPhases
3
- Version: 0.1.6
3
+ Version: 0.2.0
4
4
  Summary: A framwork for creating deep learning pipelines for sleep data
5
5
  Home-page: https://gitlab.com/sleep-is-all-you-need/sleepyphases
6
6
  Author: Franz Ehrlich
@@ -14,6 +14,15 @@ License-File: LICENSE
14
14
  Requires-Dist: SleepHarmonizer
15
15
  Requires-Dist: pyPhasesML
16
16
  Requires-Dist: phases
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
17
26
 
18
27
  # Arousal Detector
19
28
 
@@ -880,4 +880,13 @@ class DataManipulation(pyPhasesDataManipulation, Swappable):
880
880
  # Update the channel in Y
881
881
  Y[:, :, channel] = y_channel
882
882
 
883
+ return X, Y
884
+
885
+
886
+ def combineY(self, X, Y, values, channel=0):
887
+ """" Combine multiple Y values into one. """
888
+ smallest = min(values)
889
+ Y[:, :, channel] = np.where(np.isin(Y[:, :, channel], values), values[-1], Y[:, :, channel])
890
+ Y[:, :, channel][Y[:, :, channel] > smallest] -= len(values) - 1
891
+
883
892
  return X, Y
@@ -11,6 +11,8 @@ from SleePyPhases.phases.Validation import Validation
11
11
  from SleePyPhases.phases.Eval import Eval
12
12
  from SleePyPhases.phases.EvalReport import EvalReport
13
13
  from SleePyPhases.phases.ThresholdOptimisation import ThresholdOptimisation
14
+ from SleePyPhases.phases.TestRun import TestRun
15
+
14
16
 
15
17
  from pyPhases.exporter.PickleExporter import PickleExporter
16
18
  from pyPhases.exporter.PandasExporter import PandasExporter
@@ -31,6 +33,7 @@ class Plugin(PluginAdapter):
31
33
  "ThresholdOptimisation": (ThresholdOptimisation, ["threshold", "validationResult"]),
32
34
  "Eval": (Eval, ["evalResults", "eventResults"]),
33
35
  "EvalReport": (EvalReport, []),
36
+ "TestRun": (TestRun, [])
34
37
 
35
38
  }
36
39
  dataMap = {
@@ -56,7 +56,7 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
56
56
  rem_starts = [rem[i].start for i in range(1, len(rem)) if rem[i].start - rem[i-1].end() > 1]
57
57
  rem_ends = [rem[i-1].end() for i in range(1, len(rem)) if rem[i].start - rem[i-1].end() > 1]
58
58
 
59
- if len(rem_ends) == 0:
59
+ if len(rem_ends) == 0 or len(nrem) == 0:
60
60
  return cycles
61
61
 
62
62
  # Set cycle start and stop times
@@ -123,12 +123,35 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
123
123
 
124
124
  return offsetStart, offsetEnd
125
125
 
126
+ def _updateEvents(self, eventlist, offsetStart, offsetEnd):
127
+
128
+ # update events
129
+ newEvents = []
130
+ for event in eventlist:
131
+ if offsetStart > 0:
132
+ if event.end() <= offsetStart:
133
+ continue
134
+ if event.start < offsetStart:
135
+ event.duration -= offsetStart - event.start
136
+ event.start = 0
137
+ else:
138
+ event.start -= offsetStart
139
+ if offsetEnd is not None:
140
+ if event.start >= offsetEnd - offsetStart:
141
+ continue
142
+ if event.end() > offsetEnd - offsetStart:
143
+ event.duration -= event.end() - offsetEnd + offsetStart
144
+ newEvents.append(event)
145
+ return newEvents
126
146
 
127
147
  # TODO: outsource to PSGEventManager
128
148
  def _tailorToSleepScoring(self, segmentSignal: RecordSignal, eventlist):
129
149
 
130
150
  sleepEventNames = ["R", "N1", "N2", "N3", "W"]
131
151
  sleepEvents = [e for e in eventlist if e.name in sleepEventNames]
152
+
153
+ if len(sleepEvents) == 0:
154
+ return segmentSignal, []
132
155
 
133
156
  # fix if the last sleep stage has no duration (should be fixed in Recordloader (Alice))
134
157
  if sleepEvents[-1].duration == 0:
@@ -145,23 +168,7 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
145
168
 
146
169
  segmentSignal.signalOffset(offsetStart, offsetEnd)
147
170
 
148
- # update events
149
- newEvents = []
150
- for event in eventlist:
151
- if offsetStart > 0:
152
- if event.end() <= offsetStart:
153
- continue
154
- if event.start < offsetStart:
155
- event.duration -= offsetStart - event.start
156
- event.start = 0
157
- else:
158
- event.start -= offsetStart
159
- if offsetEnd is not None:
160
- if event.start >= offsetEnd - offsetStart:
161
- continue
162
- if event.end() > offsetEnd - offsetStart:
163
- event.duration -= event.end() - offsetEnd + offsetStart
164
- newEvents.append(event)
171
+ newEvents = self._updateEvents(eventlist, offsetStart, offsetEnd)
165
172
 
166
173
  return segmentSignal, newEvents
167
174
 
@@ -173,6 +180,17 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
173
180
 
174
181
  signal = segmentSignal.getSignalByName(channel)
175
182
 
183
+ # check if the scoring is longer than the actual signal
184
+ sleepEventNames = ["R", "N1", "N2", "N3", "W"]
185
+ sleepEvents = [e for e in eventlist if e.name in sleepEventNames]
186
+ scoringLength = sleepEvents[-1].end() - sleepEvents[0].start
187
+ signalLength = signal.signal.shape[0] / signal.frequency
188
+ if scoringLength > signalLength:
189
+ newLength = (len(signal.signal)/signal.frequency//30)*30
190
+ newLength = min(newLength, signalLength)
191
+ eventlist = self._updateEvents(eventlist, 0, newLength)
192
+ signal.signal = signal.signal[:int(newLength*signal.frequency)]
193
+
176
194
 
177
195
  labelSignal = PSGEventManager().getEventSignalFromList(
178
196
  eventlist,
@@ -190,7 +208,6 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
190
208
  stage_mask[stage_mask == 0] = np.nan
191
209
 
192
210
  power_epoch_mean = self._swa(signal)
193
-
194
211
  assert len(power_epoch_mean) == len(labelSignal)
195
212
 
196
213
  signal_masked = stage_mask * power_epoch_mean
@@ -208,6 +225,8 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
208
225
  def SWA3(self, segmentSignal: RecordSignal, eventlist: List[Event], channel: str):
209
226
 
210
227
  segmentSignal, eventlist = self._tailorToSleepScoring(segmentSignal, eventlist)
228
+ if len(eventlist) == 0:
229
+ return {}
211
230
 
212
231
  swa_cycles_all, swa_cycles_n2n3, cycles = self._SWAandCycles(segmentSignal, eventlist, channel)
213
232
 
@@ -222,4 +241,26 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
222
241
  "deltapower_0.5_n2n3_first": swa_cycles_n2n3.iloc[0].to_list()[0],
223
242
  "deltapower_0.5_n2n3_max": swa_cycles_n2n3.max().to_list()[0],
224
243
  "deltapower_0.5_n2n3_last": swa_cycles_n2n3.iloc[-1].to_list()[0],
225
- }
244
+ }
245
+
246
+ def REMCycleLength(self, segmentSignal: RecordSignal, eventlist: List[Event], channel: str):
247
+ cycles = self._SleepCycles(segmentSignal, eventlist)
248
+
249
+ lastStop = 0
250
+ remEvents = [e for e in eventlist if e.name == "R"]
251
+
252
+ ret = {
253
+ "cycle-count": len(cycles["start"]),
254
+ }
255
+
256
+ for cycleNumber, (start, stop) in enumerate(zip(cycles["start"], cycles["end"])):
257
+ if lastStop > 0:
258
+ remTime = sum([e.duration for e in remEvents if e.start >= lastStop and e.start < start])
259
+ ret[f"cycle-{cycleNumber}-rem-duration"] = remTime
260
+
261
+ lastStop = stop
262
+
263
+ return {
264
+ "cycle-count": len(cycles["start"]),
265
+ }
266
+
@@ -244,7 +244,7 @@ class SignalPreprocessing(pyPhaseSignalPreprocessing, Swappable):
244
244
  return np.concatenate(signal)
245
245
 
246
246
  def fir(self, signal: Signal, recordSignal: RecordSignal, nFir, cutoff, pass_zero=False):
247
- from scipy import signal
247
+ from scipy import signal as scipySignal
248
248
 
249
249
  fs = signal.frequency
250
250
  nyq = fs/2
@@ -68,16 +68,20 @@ class SleepMetaData:
68
68
  self.fromArousalSignal(signal)
69
69
  case 'ApneaBin':
70
70
  self.fromApneaSignal(signal, ["None", "respEvent"])
71
+ case 'Apnea4':
72
+ self.fromApneaSignal(signal, ["None", "obstructive/mixed", "central", "hypopnea"])
71
73
  case 'LMBin':
72
74
  self.fromLegMovementSignal(signal)
73
75
  case 'SleepBin':
74
76
  self.fromSleepSignalBin(signal, frequency=frequency)
77
+ case 'Sleep4':
78
+ self.fromSleepSignalBin(signal, frequency=frequency)
75
79
 
76
80
  def fromSleepSignalBin(self, signal, frequency = 1):
77
81
  # all time values in seconds
78
82
  trt = len(signal) / (frequency)
79
83
  tst = sum(signal) / (frequency)
80
- whereSleep = np.where(signal == 1)[0]
84
+ whereSleep = np.where(signal > 0)[0]
81
85
  if len(whereSleep) == 0:
82
86
  sLatency = 0
83
87
  else:
@@ -1,4 +1,5 @@
1
1
 
2
2
  from .DataManipulation import DataManipulation
3
3
  from .SignalPreprocessing import SignalPreprocessing
4
- from .FeatureExtraction import FeatureExtraction
4
+ from .FeatureExtraction import FeatureExtraction
5
+ from .PreManipulation import PreManipulation
@@ -30,7 +30,7 @@ class BuildDataset(Phase):
30
30
 
31
31
  self.project.updateConfig(overwriteConfig)
32
32
  memmapOptions = {
33
- "dtype": self.getConfig("preprocessing.dtype"),
33
+ "dtype": self.getConfig("preprocessing.dtype", "float32"),
34
34
  }
35
35
  dataExporterSignals = self.project.getData("data-processed", np.memmap, options=memmapOptions)
36
36
  dataExporterFeatures = self.project.getData("data-features", np.memmap, options=memmapOptions)
@@ -1,13 +1,12 @@
1
1
  import numpy as np
2
2
  from pyPhases import Phase
3
3
  from pyPhases.util import BatchProgress
4
- from pyPhasesML import DataversionManager
5
- from pyPhasesRecordloader import AnnotationNotFound, ChannelsNotPresent, RecordLoader, ParseError
4
+ from pyPhasesRecordloader import AnnotationNotFound, ChannelsNotPresent, ParseError, RecordLoader
6
5
 
6
+ from SleePyPhases.FeatureExtraction import FeatureExtraction
7
7
  from SleePyPhases.PreManipulation import PreManipulation
8
8
  from SleePyPhases.PSGEventManager import PSGEventManager
9
9
  from SleePyPhases.SignalPreprocessing import SignalPreprocessing
10
- from SleePyPhases.FeatureExtraction import FeatureExtraction
11
10
 
12
11
 
13
12
  class RecordProcessor:
@@ -207,7 +206,7 @@ class Extract(Phase):
207
206
  processRecord = RecordProcessor(
208
207
  recordLoader=RecordLoader.get(),
209
208
  preProcessingConfig=preprocessingConfig,
210
- signalProcessing=SignalPreprocessing(preprocessingConfig),
209
+ signalProcessing=SignalPreprocessing.getInstance(preprocessingConfig),
211
210
  eventManager=PSGEventManager(),
212
211
  labelChannels=self.getConfig("labelChannels"),
213
212
  project=self.project,
@@ -97,7 +97,12 @@ class Setup(Phase):
97
97
 
98
98
  # add training folding splits
99
99
  if "trainval" in splits:
100
- dm.addSplitsByFold("training", "validation", splits["trainval"], self.getConfig("dataversion.folds", 0), self.getConfig("fold", 0))
100
+ foldcount = self.getConfig("dataversion.folds", 0)
101
+ if foldcount > 0:
102
+ dm.addSplitsByFold("training", "validation", splits["trainval"], self.getConfig("dataversion.folds", 0), self.getConfig("fold", 0))
103
+ else:
104
+ dm.addSplitByRemaining("validation", valSplit) # , remainingSplit=trainingSlice
105
+ dm.addSplitByRemaining("training", 1)
101
106
 
102
107
  if "training" in splits or "validation" in splits:
103
108
  raise Exception("trainval and training/validation split are mutually exclusive. Please remove one of them from the config. This can be caused by loading multiple configs with different splits.")
@@ -0,0 +1,147 @@
1
+ from pathlib import Path
2
+
3
+
4
+ from SleePyPhases import SignalPreprocessing as SP, PreManipulation as PM, FeatureExtraction as FE, DataManipulation as DM
5
+ from SleePyPhases.phases.Extract import Extract
6
+ from SleePyPhases.phases.BuildDataset import BuildDataset
7
+ from pyPhases import Phase
8
+ from pyPhasesRecordloader import RecordLoader
9
+ import os
10
+ from pyPhasesML import ModelManager, TrainingSetLoader
11
+
12
+ class TestRun(Phase):
13
+ useMultiThreading = False
14
+ def main(self):
15
+ import numpy as np
16
+ import pandas as pd
17
+
18
+ debugConfig = self.getConfig("debugConfig", {})
19
+ print(f"Overwrite Config with debug values in debugConfig: {debugConfig}")
20
+
21
+ with self.project:
22
+ self.project.updateConfig(debugConfig)
23
+ loader = self.getConfig("useLoader")
24
+ rl = RecordLoader.get()
25
+ # rl.debug = True
26
+
27
+ if not self.useMultiThreading:
28
+ self.log("Disable multi threading for better error messages. To test multi threading, set TestRun.useMultiThreading to True")
29
+ Extract.useMultiThreading = False
30
+ BuildDataset.useMultiThreading = False
31
+
32
+ self.log("Testing pyPhases settings")
33
+ dataPath = Path(self.getConfig("data-path"))
34
+ if dataPath.exists():
35
+ self.logSuccess(f"Path {dataPath} exists: {dataPath.exists()}")
36
+
37
+ # Test if directory is writable
38
+ if os.access(dataPath, os.W_OK):
39
+ self.logSuccess(f"Data Path ({dataPath}) is writable")
40
+ else:
41
+ self.logError(f"Data Path ({dataPath}) is not writable. Make sure to set the correct path (Config: data-path) and permissions.")
42
+ exit(1)
43
+ else:
44
+ self.logError(f"Data Path ({dataPath}) does not exist. Please set the correct path (Config: data-path)")
45
+ exit(1)
46
+
47
+ testRunData = dataPath / "testrun"
48
+ self.log(f"Creating a new Data Folder ({testRunData.as_posix()}) for the testrun")
49
+ if not testRunData.exists():
50
+ testRunData.mkdir()
51
+ # else:
52
+ # # remove all files from the testrun folder
53
+ # for f in testRunData.iterdir():
54
+ # f.unlink()
55
+
56
+ self.log("Creating a new Data Folder for the testrun")
57
+
58
+ self.log(f"Test specified RecordLoader: {loader} ({type(rl)})")
59
+ datasetPath = Path(rl.filePath)
60
+ if datasetPath.exists():
61
+ self.logSuccess(f"RL Path ({rl.filePath}) exists: {Path(rl.filePath).exists()}")
62
+ else:
63
+ self.logError(f"RL Path ({rl.filePath}) does not exist. Make sure to download the dataset and set the correct path (Config: {loader}-path)")
64
+ exit(1)
65
+
66
+ self.setConfig("testrun", True)
67
+
68
+ self.log("Test generating dataset metadata, for first records")
69
+ df = self.getData("metadata", pd.DataFrame)
70
+ self.log(f"Metadata: {df.head()} / {df.shape}")
71
+
72
+ if len(df) > 0:
73
+ self.logSuccess("Dataset records loaded")
74
+ else:
75
+ self.logError("Dataset records not loaded")
76
+ # metadata-channels, dataIsFinal
77
+
78
+ self.log("Test data version and split")
79
+ dm = self.getData("dataversionmanager")
80
+ self.log(f"Splits (assuming all records exist): {dm.splits}")
81
+
82
+ self.log("For debugging purpose, we will reduce the split using the same 2 records for all splits")
83
+ dm.splits["training"][0] = slice(0, 2)
84
+ dm.splits["validation"][0] = slice(0, 2)
85
+ dm.splits["test"][0] = slice(0, 2)
86
+
87
+ self.log("Test extracting data with preprocessing defined in (Config: preprocessing)")
88
+ self.log(f"Preprocessing Config: {self.getConfig('preprocessing')}")
89
+ self.log(f"Preprocessing target frequency: {self.getConfig('preprocessing.targetFrequency')}")
90
+ self.log(f"Preprocessing target labelFrequency: {self.getConfig('preprocessing.labelFrequency')}")
91
+ self.log(f"Preprocessing target channels: {self.getConfig('preprocessing.targetChannels')}")
92
+ # check that resample is in each target signal related preprocessing
93
+
94
+ self.log(f"Current SignalPreprocessing Class: {type(SP.getInstance(self.getConfig('preprocessing')))}")
95
+ self.log(f"Current PreManipulation Class: {type(PM.getInstance(self.getConfig('preprocessing')))}")
96
+ # self.log(f"Current FeatureExtraction: {type(FE.getInstance(self.getConfig('preprocessing')))}")
97
+ self.log(f"Current SignalPreprocessing: {self.getConfig('preprocessing.stepsPerType')}")
98
+ self.log(f"Current PreManipulation: {self.getConfig('preprocessing.manipulationSteps')}")
99
+ # self.log(f"Current FeatureExtraction: {type(FE.getInstance(self.getConfig('preprocessing')))}")
100
+
101
+ memmapOptions = {
102
+ "dtype": self.getConfig("preprocessing.dtype", "float32"),
103
+ }
104
+ dataExporterSignals = self.getData("data-processed", np.memmap, options=memmapOptions)
105
+ dataExporterFeatures = self.getData("data-features", np.memmap, options=memmapOptions)
106
+
107
+ self.logSuccess(f"Extract finished: len X: {len(dataExporterSignals)} / len Y: {len(dataExporterFeatures)}")
108
+
109
+ self.log("Test data manipulation")
110
+ manipulationSteps = self.getConfig("segmentManipulation")
111
+ self.log(f"Current segmentManipulation: {manipulationSteps}")
112
+ segmentManipulation = DM.getInstance(manipulationSteps, "training", self.project.config)
113
+ self.log(f"Current DataManipulation Class: {type(segmentManipulation)}")
114
+ # segmentManipulation = DM.getInstance(manipulationSteps, "training", self.project.config, recordMetadata=recordMetaData)
115
+
116
+ X, Y = dataExporterSignals[0], dataExporterFeatures[0]
117
+ X, Y = segmentManipulation((X, Y), None, 0)
118
+
119
+ self.logSuccess(f"Segment Manipulation finished: X: {X.shape} / Y: {Y.shape}")
120
+
121
+ self.log(f"Test Model: {self.getConfig('modelName')}")
122
+
123
+ model = ModelManager.getModel()
124
+ self.log(f"Current Model: {type(model)}")
125
+ self.log(model.summary())
126
+ train = self.project.generateData("dataset-training")
127
+ val = self.project.generateData("dataset-validation")
128
+ trainingsSet = TrainingSetLoader(trainingData=train, validationData=val)
129
+ model.debug = True
130
+ trainedModel = model.train(trainingsSet)
131
+
132
+ self.logSuccess("Debug Model trained")
133
+
134
+
135
+
136
+
137
+ # allDBRecordIds
138
+ # self.getData("allRecordIds")
139
+ # extract data
140
+ # build data
141
+ # data manipulation
142
+ # load model
143
+ # training
144
+ # validation
145
+ # threshold optimization
146
+ # segment evaluation
147
+ # event evaluation
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: SleePyPhases
3
- Version: 0.1.6
3
+ Version: 0.2.0
4
4
  Summary: A framwork for creating deep learning pipelines for sleep data
5
5
  Home-page: https://gitlab.com/sleep-is-all-you-need/sleepyphases
6
6
  Author: Franz Ehrlich
@@ -14,6 +14,15 @@ License-File: LICENSE
14
14
  Requires-Dist: SleepHarmonizer
15
15
  Requires-Dist: pyPhasesML
16
16
  Requires-Dist: phases
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
17
26
 
18
27
  # Arousal Detector
19
28
 
@@ -34,6 +34,7 @@ SleePyPhases/phases/ExtractFeatures.py
34
34
  SleePyPhases/phases/ExtractRecordFeatures.py
35
35
  SleePyPhases/phases/GatherMetadata.py
36
36
  SleePyPhases/phases/Setup.py
37
+ SleePyPhases/phases/TestRun.py
37
38
  SleePyPhases/phases/ThresholdOptimisation.py
38
39
  SleePyPhases/phases/Training.py
39
40
  SleePyPhases/phases/Validation.py
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="SleePyPhases",
8
- version="v0.1.6"[1:],
8
+ version="v0.2.0"[1:],
9
9
  author="Franz Ehrlich",
10
10
  author_email="fehrlichd@gmail.com",
11
11
  description="A framwork for creating deep learning pipelines for sleep data",
@@ -268,4 +268,30 @@ class TestDataManipulation(unittest.TestCase):
268
268
 
269
269
  npt.assert_equal(Y_new.shape, expected.shape)
270
270
  npt.assert_equal(Y_new[0, :, 0], expected[0, :, 0])
271
- npt.assert_equal(X_new, X) # X should remain unchanged
271
+ npt.assert_equal(X_new, X) # X should remain unchanged
272
+
273
+ def test_combineY(self):
274
+ da = self.getDA()
275
+
276
+ X = np.zeros((2, 10, 2))
277
+ Y = np.array([
278
+ [[0], [1], [2], [3], [4], [0], [1], [2], [3], [4]],
279
+ [[4], [3], [2], [1], [0], [4], [3], [2], [1], [0]]
280
+ ])
281
+
282
+ # Test combining values 2,1 into 0
283
+ _, Y_out = da.combineY(X, Y.copy(), values=[2, 1, 0])
284
+ expected = np.array([
285
+ [[0], [0], [0], [1], [2], [0], [0], [0], [1], [2]],
286
+ [[2], [1], [0], [0], [0], [2], [1], [0], [0], [0]]
287
+ ])
288
+
289
+ np.testing.assert_array_equal(Y_out, expected)
290
+
291
+ # Test combining values 4,3,2 into 1
292
+ _, Y_out = da.combineY(X, Y.copy(), values=[1, 2])
293
+ expected = np.array([
294
+ [[0], [1], [1], [2], [3], [0], [1], [1], [2], [3]],
295
+ [[3], [2], [1], [1], [0], [3], [2], [1], [1], [0]]
296
+ ])
297
+ np.testing.assert_array_equal(Y_out, expected)
File without changes
File without changes
File without changes