actinet 0.0.dev4__tar.gz → 0.0.dev5__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 (26) hide show
  1. {actinet-0.0.dev4 → actinet-0.0.dev5}/PKG-INFO +35 -13
  2. {actinet-0.0.dev4 → actinet-0.0.dev5}/README.md +34 -12
  3. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/__init__.py +2 -2
  4. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/_version.py +3 -3
  5. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/actinet.py +65 -47
  6. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/models.py +17 -11
  7. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/summarisation.py +12 -25
  8. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/PKG-INFO +35 -13
  9. {actinet-0.0.dev4 → actinet-0.0.dev5}/LICENSE.md +0 -0
  10. {actinet-0.0.dev4 → actinet-0.0.dev5}/pyproject.toml +0 -0
  11. {actinet-0.0.dev4 → actinet-0.0.dev5}/setup.cfg +0 -0
  12. {actinet-0.0.dev4 → actinet-0.0.dev5}/setup.py +0 -0
  13. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/accPlot.py +0 -0
  14. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/circadian.py +0 -0
  15. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/hmm.py +0 -0
  16. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/sslmodel.py +0 -0
  17. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/utils/__init__.py +0 -0
  18. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/utils/collate_outputs.py +0 -0
  19. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/utils/generate_commands.py +0 -0
  20. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet/utils/utils.py +0 -0
  21. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/SOURCES.txt +0 -0
  22. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/dependency_links.txt +0 -0
  23. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/entry_points.txt +0 -0
  24. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/requires.txt +0 -0
  25. {actinet-0.0.dev4 → actinet-0.0.dev5}/src/actinet.egg-info/top_level.txt +0 -0
  26. {actinet-0.0.dev4 → actinet-0.0.dev5}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: actinet
3
- Version: 0.0.dev4
3
+ Version: 0.0.dev5
4
4
  Summary: Activity detection algorithm compatible with the UK Biobank Accelerometer Dataset
5
5
  Home-page: https://github.com/OxWearables/actinet
6
6
  Download-URL: https://github.com/OxWearables/actinet
@@ -60,16 +60,16 @@ You are all set! The next time that you want to use `actinet`, open the Anaconda
60
60
 
61
61
  ```bash
62
62
  # Process an AX3 file
63
- $ actinet sample.cwa
63
+ $ actinet -f sample.cwa
64
64
 
65
65
  # Or an ActiGraph file
66
- $ actinet sample.gt3x
66
+ $ actinet -f sample.gt3x
67
67
 
68
68
  # Or a GENEActiv file
69
- $ actinet sample.bin
69
+ $ actinet -f sample.bin
70
70
 
71
71
  # Or a CSV file (see data format below)
72
- $ actinet sample.csv
72
+ $ actinet -f sample.csv
73
73
  ```
74
74
 
75
75
  ### Troubleshooting
@@ -80,12 +80,34 @@ Some systems may face issues with Java when running the script. If this is your
80
80
  conda install -n actinet openjdk=8
81
81
  ```
82
82
 
83
+ ### Offline usage
84
+
85
+ To use this package offline, one must first download and install the relevant classifier file and model modules.
86
+ This repository offers two ways of doing this.
87
+
88
+ Run the following code when you have internet access:
89
+ ```console
90
+ actinet --cache-classifier
91
+ ```
92
+
93
+ Following this, the actinet classifier can be used as standard without internet access, without needing to specify the flags relating to the model repository.
94
+
95
+ Alternatively, you can download or git clone the ssl modules from the [ssl-wearables repository](https://github.com/OxWearables/ssl-wearables).
96
+
97
+ In addition, you can donwload/prepare a custom classifier file.
98
+
99
+ Once this is downloaded to an appopriate location, you can run the actinet model using:
100
+
101
+ ```console
102
+ actinet -f sample.cwa -c /path/to/classifier.joblib.lzma -m /path/to/ssl-wearables
103
+ ```
104
+
83
105
  ### Output files
84
106
 
85
107
  By default, output files will be stored in a folder named after the input file, `outputs/{filename}/`, created in the current working directory. You can change the output path with the `-o` flag:
86
108
 
87
109
  ```console
88
- $ actinet sample.cwa -o /path/to/some/folder/
110
+ $ actinet -f sample.cwa -o /path/to/some/folder/
89
111
 
90
112
  <Output summary written to: /path/to/some/folder/sample-outputSummary.json>
91
113
  <Time series output written to: /path/to/some/folder/sample-timeSeries.csv.gz>
@@ -103,7 +125,7 @@ See [Data Dictionary](https://biobankaccanalysis.readthedocs.io/en/latest/datadi
103
125
  To plot the activity profiles, you can use the -p flag:
104
126
 
105
127
  ```console
106
- $ actinet sample.cwa -p
128
+ $ actinet -f sample.cwa -p
107
129
  <Output plot written to: data/sample-timeSeries-plot.png>
108
130
  ```
109
131
 
@@ -138,9 +160,9 @@ To process multiple files you can create a text file in Notepad which includes o
138
160
  Example text file *commands.txt*:
139
161
 
140
162
  ```console
141
- actinet file1.cwa &
142
- actinet file2.cwa &
143
- actinet file3.cwa
163
+ actinet -f file1.cwa &
164
+ actinet -f file2.cwa &
165
+ actinet -f file3.cwa
144
166
  :END
145
167
  ````
146
168
 
@@ -151,9 +173,9 @@ Once this file is created, run `cmd < commands.txt` from the terminal.
151
173
  Create a file *command.sh* with:
152
174
 
153
175
  ```console
154
- actinet file1.cwa
155
- actinet file2.cwa
156
- actinet file3.cwa
176
+ actinet -f file1.cwa
177
+ actinet -f file2.cwa
178
+ actinet -f file3.cwa
157
179
  ```
158
180
 
159
181
  Then, run `bash command.sh` from the terminal.
@@ -38,16 +38,16 @@ You are all set! The next time that you want to use `actinet`, open the Anaconda
38
38
 
39
39
  ```bash
40
40
  # Process an AX3 file
41
- $ actinet sample.cwa
41
+ $ actinet -f sample.cwa
42
42
 
43
43
  # Or an ActiGraph file
44
- $ actinet sample.gt3x
44
+ $ actinet -f sample.gt3x
45
45
 
46
46
  # Or a GENEActiv file
47
- $ actinet sample.bin
47
+ $ actinet -f sample.bin
48
48
 
49
49
  # Or a CSV file (see data format below)
50
- $ actinet sample.csv
50
+ $ actinet -f sample.csv
51
51
  ```
52
52
 
53
53
  ### Troubleshooting
@@ -58,12 +58,34 @@ Some systems may face issues with Java when running the script. If this is your
58
58
  conda install -n actinet openjdk=8
59
59
  ```
60
60
 
61
+ ### Offline usage
62
+
63
+ To use this package offline, one must first download and install the relevant classifier file and model modules.
64
+ This repository offers two ways of doing this.
65
+
66
+ Run the following code when you have internet access:
67
+ ```console
68
+ actinet --cache-classifier
69
+ ```
70
+
71
+ Following this, the actinet classifier can be used as standard without internet access, without needing to specify the flags relating to the model repository.
72
+
73
+ Alternatively, you can download or git clone the ssl modules from the [ssl-wearables repository](https://github.com/OxWearables/ssl-wearables).
74
+
75
+ In addition, you can donwload/prepare a custom classifier file.
76
+
77
+ Once this is downloaded to an appopriate location, you can run the actinet model using:
78
+
79
+ ```console
80
+ actinet -f sample.cwa -c /path/to/classifier.joblib.lzma -m /path/to/ssl-wearables
81
+ ```
82
+
61
83
  ### Output files
62
84
 
63
85
  By default, output files will be stored in a folder named after the input file, `outputs/{filename}/`, created in the current working directory. You can change the output path with the `-o` flag:
64
86
 
65
87
  ```console
66
- $ actinet sample.cwa -o /path/to/some/folder/
88
+ $ actinet -f sample.cwa -o /path/to/some/folder/
67
89
 
68
90
  <Output summary written to: /path/to/some/folder/sample-outputSummary.json>
69
91
  <Time series output written to: /path/to/some/folder/sample-timeSeries.csv.gz>
@@ -81,7 +103,7 @@ See [Data Dictionary](https://biobankaccanalysis.readthedocs.io/en/latest/datadi
81
103
  To plot the activity profiles, you can use the -p flag:
82
104
 
83
105
  ```console
84
- $ actinet sample.cwa -p
106
+ $ actinet -f sample.cwa -p
85
107
  <Output plot written to: data/sample-timeSeries-plot.png>
86
108
  ```
87
109
 
@@ -116,9 +138,9 @@ To process multiple files you can create a text file in Notepad which includes o
116
138
  Example text file *commands.txt*:
117
139
 
118
140
  ```console
119
- actinet file1.cwa &
120
- actinet file2.cwa &
121
- actinet file3.cwa
141
+ actinet -f file1.cwa &
142
+ actinet -f file2.cwa &
143
+ actinet -f file3.cwa
122
144
  :END
123
145
  ````
124
146
 
@@ -129,9 +151,9 @@ Once this file is created, run `cmd < commands.txt` from the terminal.
129
151
  Create a file *command.sh* with:
130
152
 
131
153
  ```console
132
- actinet file1.cwa
133
- actinet file2.cwa
134
- actinet file3.cwa
154
+ actinet -f file1.cwa
155
+ actinet -f file2.cwa
156
+ actinet -f file3.cwa
135
157
  ```
136
158
 
137
159
  Then, run `bash command.sh` from the terminal.
@@ -4,8 +4,8 @@ __maintainer__ = "Shing Chan"
4
4
  __maintainer_email__ = "shing.chan@ndph.ox.ac.uk"
5
5
  __license__ = "See LICENSE file."
6
6
 
7
- __model_version__ = "ssl_ukb_c24_rw_20240204"
8
- __model_md5__ = "84f3d5bb73de5c4da057918c45400da4"
7
+ __classifier_version__ = "ssl_ukb_c24_rw_20240204"
8
+ __classifier_md5__ = "11c3f36348dae37da4f99bd6d810bbb2"
9
9
 
10
10
  from . import _version
11
11
 
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-02-05T14:38:16+0000",
11
+ "date": "2024-02-06T18:32:30+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "5857a41418deef2d09568018e05ecae250c54d14",
15
- "version": "0.0.dev4"
14
+ "full-revisionid": "ae03389ab9965e52140c46a6c43e39799ad1c61b",
15
+ "version": "0.0.dev5"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -12,16 +12,15 @@ import joblib
12
12
 
13
13
  import actipy
14
14
 
15
- from actinet import __model_version__
16
- from actinet import __model_md5__
15
+ from actinet import __classifier_version__
16
+ from actinet import __classifier_md5__
17
17
  from actinet.accPlot import plotTimeSeries
18
18
  from actinet.models import ActivityClassifier
19
19
  from actinet.sslmodel import SAMPLE_RATE
20
- from actinet.summarisation import getActivitySummary, ACTIVITY_LABELS
20
+ from actinet.summarisation import getActivitySummary
21
21
  from actinet.utils.utils import infer_freq
22
22
 
23
- BASE_URL = "https://zenodo.org/records/10619096/files/"
24
-
23
+ BASE_URL = "https://zenodo.org/records/10625542/files/"
25
24
 
26
25
  def main():
27
26
 
@@ -37,10 +36,15 @@ def main():
37
36
  default="outputs/",
38
37
  )
39
38
  parser.add_argument(
40
- "--model-path", "-m", help="Enter custom model file to use", default=None
39
+ "--classifier-path",
40
+ "-c",
41
+ help="Enter custom acitivty classifier file to use",
42
+ default=None,
41
43
  )
42
44
  parser.add_argument(
43
- "--force-download", action="store_true", help="Force download of model file"
45
+ "--force-download",
46
+ action="store_true",
47
+ help="Force download of classifier file",
44
48
  )
45
49
  parser.add_argument(
46
50
  "--pytorch-device",
@@ -63,12 +67,12 @@ def main():
63
67
  help="Plot the predicted activity labels",
64
68
  )
65
69
  parser.add_argument(
66
- "--cache-ssl",
70
+ "--cache-classifier",
67
71
  action="store_true",
68
- help="Download and cache ssl module for offline usage",
72
+ help="Download and cache classifier file and model modules for offline usage",
69
73
  )
70
74
  parser.add_argument(
71
- "--ssl-repo-path", "-s", help="Enter repository of ssl model", default=None
75
+ "--model-repo-path", "-m", help="Enter repository of ssl model", default=None
72
76
  )
73
77
  parser.add_argument("--quiet", "-q", action="store_true", help="Suppress output")
74
78
  args = parser.parse_args()
@@ -77,8 +81,18 @@ def main():
77
81
 
78
82
  verbose = not args.quiet
79
83
 
80
- if args.cache_ssl:
81
- model = ActivityClassifier(weights_path=None, ssl_repo=None, verbose=verbose, labels=ACTIVITY_LABELS)
84
+ classifier_path = (
85
+ pathlib.Path(__file__).parent / f"{__classifier_version__}.joblib.lzma"
86
+ )
87
+
88
+ if args.cache_classifier:
89
+ load_classifier(
90
+ classifier_path=classifier_path,
91
+ model_repo_path=None,
92
+ check_md5=True,
93
+ force_download=True,
94
+ verbose=verbose,
95
+ )
82
96
 
83
97
  after = time.time()
84
98
  print(f"Done! ({round(after - before,2)}s)")
@@ -98,21 +112,21 @@ def main():
98
112
  outdir = os.path.join(args.outdir, basename)
99
113
  os.makedirs(outdir, exist_ok=True)
100
114
 
101
- # Run model
115
+ # Run classifier
102
116
  if verbose:
103
- print("Loading model...")
104
- model_path = pathlib.Path(__file__).parent / f"{__model_version__}.joblib.lzma"
105
- check_md5 = args.model_path is None
106
- model: ActivityClassifier = load_model(
107
- args.model_path or model_path, check_md5, args.force_download, verbose
117
+ print("Loading classifier...")
118
+
119
+ check_md5 = args.classifier_path is None
120
+ classifier: ActivityClassifier = load_classifier(
121
+ args.classifier_path or classifier_path, args.model_repo_path, check_md5, args.force_download, verbose
108
122
  )
109
123
 
110
- model.verbose = verbose
111
- model.device = args.pytorch_device
124
+ classifier.verbose = verbose
125
+ classifier.device = args.pytorch_device
112
126
 
113
127
  if verbose:
114
128
  print("Running activity classifier...")
115
- Y = model.predict_from_frame(data)
129
+ Y = classifier.predict_from_frame(data)
116
130
 
117
131
  # Save predicted activities
118
132
  timeSeriesFile = f"{outdir}/{basename}-timeSeries.csv.gz"
@@ -121,8 +135,17 @@ def main():
121
135
  if verbose:
122
136
  print("Time series output written to:", timeSeriesFile)
123
137
 
138
+ # Plot activity profile
139
+ if args.plot_activity:
140
+ plotFile = f"{outdir}/{basename}-timeSeries-plot.png"
141
+ fig = plotTimeSeries(Y)
142
+ fig.savefig(plotFile, dpi=200, bbox_inches="tight")
143
+
144
+ if verbose:
145
+ print("Output plot written to:", plotFile)
146
+
124
147
  # Summary
125
- summary = getActivitySummary(Y, True, True, verbose)
148
+ summary = getActivitySummary(Y, classifier.labels, True, True, verbose)
126
149
 
127
150
  # Join the actipy processing info, with acitivity summary data
128
151
  outputSummary = {**summary, **info}
@@ -139,7 +162,7 @@ def main():
139
162
  if verbose:
140
163
  print("\nSummary Stats\n---------------------")
141
164
  print(
142
- {
165
+ json.dumps({
143
166
  key: outputSummary[key]
144
167
  for key in [
145
168
  "Filename",
@@ -147,21 +170,11 @@ def main():
147
170
  "WearTime(days)",
148
171
  "NonwearTime(days)",
149
172
  "ReadOK",
150
- "acc-overall-avg(mg)",
151
173
  ]
152
- + [f"{label}-week-avg" for label in ACTIVITY_LABELS]
153
- }
174
+ + [f"{label}-overall-avg" for label in ["acc"] + classifier.labels]
175
+ }, indent=4, cls=NpEncoder)
154
176
  )
155
177
 
156
- # Plot activity profile
157
- if args.plot_activity:
158
- plotFile = f"{outdir}/{basename}-timeSeries-plot.png"
159
- fig = plotTimeSeries(Y)
160
- fig.savefig(plotFile, dpi=200, bbox_inches="tight")
161
-
162
- if verbose:
163
- print("Output plot written to:", plotFile)
164
-
165
178
  after = time.time()
166
179
  print(f"Done! ({round(after - before,2)}s)")
167
180
 
@@ -240,14 +253,20 @@ def resolve_path(path):
240
253
  return dirname, filename, extension
241
254
 
242
255
 
243
- def load_model(model_path, ssl_repo_path=None, check_md5=True, force_download=False, verbose=True):
244
- """Load trained model. Download if not exists."""
256
+ def load_classifier(
257
+ classifier_path,
258
+ model_repo_path=None,
259
+ check_md5=True,
260
+ force_download=False,
261
+ verbose=True,
262
+ ):
263
+ """Load trained classifier. Download if not exists."""
245
264
 
246
- pth = pathlib.Path(model_path)
265
+ pth = pathlib.Path(classifier_path)
247
266
 
248
267
  if force_download or not pth.exists():
249
268
 
250
- url = f"{BASE_URL}{__model_version__}.joblib.lzma"
269
+ url = f"{BASE_URL}{__classifier_version__}.joblib.lzma"
251
270
 
252
271
  if verbose:
253
272
  print(f"Downloading {url}...")
@@ -256,20 +275,19 @@ def load_model(model_path, ssl_repo_path=None, check_md5=True, force_download=Fa
256
275
  shutil.copyfileobj(f_src, f_dst)
257
276
 
258
277
  if check_md5:
259
- assert md5(pth) == __model_md5__, (
260
- "Model file is corrupted. Please run with --force-download "
278
+ assert md5(pth) == __classifier_md5__, (
279
+ "Classifier file is corrupted. Please run with --force-download "
261
280
  "to download the model file again."
262
281
  )
263
282
 
264
- model: ActivityClassifier = joblib.load(pth)
283
+ classifier: ActivityClassifier = joblib.load(pth)
265
284
 
266
- if ssl_repo_path and pathlib.Path(ssl_repo_path).exists():
267
- if verbose:
268
- print(f"Loading ssl repository from {ssl_repo_path}.")
285
+ if model_repo_path and pathlib.Path(model_repo_path).exists() and verbose:
286
+ print(f"Loading model repository from {model_repo_path}.")
269
287
 
270
- model = model.load_ssl(ssl_repo_path)
288
+ classifier.load_model(model_repo_path)
271
289
 
272
- return model
290
+ return classifier
273
291
 
274
292
 
275
293
  def md5(fname):
@@ -1,5 +1,6 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
+ import joblib
3
4
  from tqdm.auto import tqdm
4
5
  from torch.utils.data import DataLoader
5
6
 
@@ -15,7 +16,6 @@ class ActivityClassifier:
15
16
  window_sec=30,
16
17
  weights_path=None,
17
18
  labels=[],
18
- ssl_repo=None,
19
19
  repo_tag="v1.0.0",
20
20
  hmm_params=None,
21
21
  verbose=False,
@@ -27,9 +27,11 @@ class ActivityClassifier:
27
27
  self.labels = labels
28
28
  self.window_len = int(np.ceil(self.window_sec * sslmodel.SAMPLE_RATE))
29
29
  self.verbose = verbose
30
-
31
- self.model_weights = sslmodel.get_model_dict(weights_path, device) if weights_path else None
32
- self.model = self.load_ssl(ssl_repo)
30
+
31
+ self.model_weights = (
32
+ sslmodel.get_model_dict(weights_path, device) if weights_path else None
33
+ )
34
+ self.model = None
33
35
 
34
36
  hmm_params = hmm_params or dict()
35
37
  self.hmms = hmm.HMM(**hmm_params)
@@ -42,7 +44,7 @@ class ActivityClassifier:
42
44
  "batch_size: {self.batch_size}\n"
43
45
  "device: {self.device}\n"
44
46
  "hmm: {self.hmms}\n"
45
- "model: {self.model}".format(self=self)
47
+ "model: {model}".format(self=self, model=self.model or "Model has not been loaded.")
46
48
  )
47
49
 
48
50
  def predict_from_frame(self, data):
@@ -71,6 +73,9 @@ class ActivityClassifier:
71
73
  return Y
72
74
 
73
75
  def _predict(self, X):
76
+ if self.model is None:
77
+ raise Exception("Model has not been loaded for ActivityClassifier.")
78
+
74
79
  sslmodel.verbose = self.verbose
75
80
 
76
81
  dataset = sslmodel.NormalDataset(X)
@@ -89,17 +94,18 @@ class ActivityClassifier:
89
94
 
90
95
  return y_pred
91
96
 
92
- def load_ssl(self, ssl_repo):
93
- model = sslmodel.get_sslnet(
97
+ def load_model(self, model_repo=None):
98
+ self.model = sslmodel.get_sslnet(
94
99
  tag=self.repo_tag,
95
- local_repo_path=ssl_repo,
96
- pretrained_weights = self.model_weights or True,
100
+ local_repo_path=model_repo,
101
+ pretrained_weights=self.model_weights or True,
97
102
  window_sec=self.window_sec,
98
103
  num_labels=len(self.labels),
99
104
  )
100
- model.to(self.device)
105
+ self.model.to(self.device)
101
106
 
102
- return model
107
+ def save(self, output_path):
108
+ joblib.dump(self, output_path, compress=("lzma", 3))
103
109
 
104
110
 
105
111
  def make_windows(data, window_sec, fn=None, return_index=False, verbose=True):
@@ -7,11 +7,10 @@ from pandas.tseries.frequencies import to_offset
7
7
  from actinet.utils.utils import date_parser, toScreen
8
8
  from actinet import circadian
9
9
 
10
- ACTIVITY_LABELS = ["light", "moderate-vigorous", "sedentary", "sleep"]
11
-
12
10
 
13
11
  def getActivitySummary(
14
12
  data,
13
+ labels,
15
14
  intensityDistribution=False,
16
15
  circadianMetrics=False,
17
16
  verbose=True,
@@ -19,12 +18,12 @@ def getActivitySummary(
19
18
  """
20
19
  Calculate overall activity summary from predicted activity label data.
21
20
  This is achieved by:
22
- 1) check if data occurs at a daylight savings crossover
23
- 2) calculate imputation values to replace nan PA metric values
24
- 3) calculate empirical cumulative distribution function of vector magnitudes
25
- 4) derive main movement summaries (overall, weekday/weekend, and hour)
21
+ 1) calculate imputation values to replace nan PA metric values
22
+ 2) calculate empirical cumulative distribution function of vector magnitudes
23
+ 3) derive main movement summaries (overall, weekday/weekend, and hour)
26
24
 
27
25
  :param str data: Input csv.gz file or pandas dataframe of processed epoch data
26
+ :param list(str) labels: Activity state labels
28
27
  :param bool intensityDistribution: Add intensity outputs to dict <summary>
29
28
  :param bool circadianMetrics: Add circadian rhythm metrics to dict <summary>
30
29
  :param bool verbose: Print verbose output
@@ -46,7 +45,7 @@ def getActivitySummary(
46
45
 
47
46
  # Main movement summaries
48
47
  summary = _summarise(
49
- data, ACTIVITY_LABELS, intensityDistribution, circadianMetrics, verbose, summary
48
+ data, labels, intensityDistribution, circadianMetrics, verbose,
50
49
  )
51
50
 
52
51
  # Return physical activity summary
@@ -84,9 +83,6 @@ def _summarise(
84
83
  startTime = data.index[0]
85
84
  summary["FirstDay(0=mon,6=sun)"] = startTime.weekday()
86
85
 
87
- # Check daylight savings crossings
88
- summary = checkDST(data, summary)
89
-
90
86
  # Hours of activity for each recorded day
91
87
  epochPeriod = int(pd.Timedelta(freq).total_seconds())
92
88
  cols = labels
@@ -171,31 +167,22 @@ def _summarise(
171
167
  if circadianMetrics:
172
168
  toScreen("=== Calculating circadian metrics ===", verbose)
173
169
  summary = circadian.calculatePSD(
174
- data, epochPeriod, False, ACTIVITY_LABELS, summary
170
+ data, epochPeriod, False, labels, summary
175
171
  )
176
172
  summary = circadian.calculatePSD(
177
- data, epochPeriod, True, ACTIVITY_LABELS, summary
173
+ data, epochPeriod, True, labels, summary
178
174
  )
179
175
  summary = circadian.calculateFourierFreq(
180
- data, epochPeriod, False, ACTIVITY_LABELS, summary
176
+ data, epochPeriod, False, labels, summary
181
177
  )
182
178
  summary = circadian.calculateFourierFreq(
183
- data, epochPeriod, False, ACTIVITY_LABELS, summary
179
+ data, epochPeriod, False, labels, summary
184
180
  )
185
181
  summary = circadian.calculateM10L5(data, epochPeriod, summary)
186
182
 
187
183
  return summary
188
184
 
189
185
 
190
- def checkDST(data, summary={}):
191
- if data.index[0].dst() < data.index[-1].dst():
192
- summary["quality-daylightSavingsCrossover"] = 1
193
- elif data.index[0].dst() > data.index[-1].dst():
194
- summary["quality-daylightSavingsCrossover"] = -1
195
- else:
196
- summary["quality-daylightSavingsCrossover"] = 0
197
-
198
- return summary
199
186
 
200
187
 
201
188
  def imputeMissing(data, extrapolate=True):
@@ -223,7 +210,7 @@ def imputeMissing(data, extrapolate=True):
223
210
  data.index[0].floor("D"),
224
211
  data.index[-1].ceil("D"),
225
212
  freq=to_offset(pd.infer_freq(data.index)),
226
- closed="left",
213
+ inclusive="left",
227
214
  name="time",
228
215
  ),
229
216
  method="nearest",
@@ -303,7 +290,7 @@ def calculateECDF(x, summary):
303
290
  )
304
291
 
305
292
  # Write to summary
306
- for level, val in ecdf.iteritems():
293
+ for level, val in ecdf.items():
307
294
  summary[f"{x.name}-ecdf-{level}mg"] = val
308
295
 
309
296
  return summary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: actinet
3
- Version: 0.0.dev4
3
+ Version: 0.0.dev5
4
4
  Summary: Activity detection algorithm compatible with the UK Biobank Accelerometer Dataset
5
5
  Home-page: https://github.com/OxWearables/actinet
6
6
  Download-URL: https://github.com/OxWearables/actinet
@@ -60,16 +60,16 @@ You are all set! The next time that you want to use `actinet`, open the Anaconda
60
60
 
61
61
  ```bash
62
62
  # Process an AX3 file
63
- $ actinet sample.cwa
63
+ $ actinet -f sample.cwa
64
64
 
65
65
  # Or an ActiGraph file
66
- $ actinet sample.gt3x
66
+ $ actinet -f sample.gt3x
67
67
 
68
68
  # Or a GENEActiv file
69
- $ actinet sample.bin
69
+ $ actinet -f sample.bin
70
70
 
71
71
  # Or a CSV file (see data format below)
72
- $ actinet sample.csv
72
+ $ actinet -f sample.csv
73
73
  ```
74
74
 
75
75
  ### Troubleshooting
@@ -80,12 +80,34 @@ Some systems may face issues with Java when running the script. If this is your
80
80
  conda install -n actinet openjdk=8
81
81
  ```
82
82
 
83
+ ### Offline usage
84
+
85
+ To use this package offline, one must first download and install the relevant classifier file and model modules.
86
+ This repository offers two ways of doing this.
87
+
88
+ Run the following code when you have internet access:
89
+ ```console
90
+ actinet --cache-classifier
91
+ ```
92
+
93
+ Following this, the actinet classifier can be used as standard without internet access, without needing to specify the flags relating to the model repository.
94
+
95
+ Alternatively, you can download or git clone the ssl modules from the [ssl-wearables repository](https://github.com/OxWearables/ssl-wearables).
96
+
97
+ In addition, you can donwload/prepare a custom classifier file.
98
+
99
+ Once this is downloaded to an appopriate location, you can run the actinet model using:
100
+
101
+ ```console
102
+ actinet -f sample.cwa -c /path/to/classifier.joblib.lzma -m /path/to/ssl-wearables
103
+ ```
104
+
83
105
  ### Output files
84
106
 
85
107
  By default, output files will be stored in a folder named after the input file, `outputs/{filename}/`, created in the current working directory. You can change the output path with the `-o` flag:
86
108
 
87
109
  ```console
88
- $ actinet sample.cwa -o /path/to/some/folder/
110
+ $ actinet -f sample.cwa -o /path/to/some/folder/
89
111
 
90
112
  <Output summary written to: /path/to/some/folder/sample-outputSummary.json>
91
113
  <Time series output written to: /path/to/some/folder/sample-timeSeries.csv.gz>
@@ -103,7 +125,7 @@ See [Data Dictionary](https://biobankaccanalysis.readthedocs.io/en/latest/datadi
103
125
  To plot the activity profiles, you can use the -p flag:
104
126
 
105
127
  ```console
106
- $ actinet sample.cwa -p
128
+ $ actinet -f sample.cwa -p
107
129
  <Output plot written to: data/sample-timeSeries-plot.png>
108
130
  ```
109
131
 
@@ -138,9 +160,9 @@ To process multiple files you can create a text file in Notepad which includes o
138
160
  Example text file *commands.txt*:
139
161
 
140
162
  ```console
141
- actinet file1.cwa &
142
- actinet file2.cwa &
143
- actinet file3.cwa
163
+ actinet -f file1.cwa &
164
+ actinet -f file2.cwa &
165
+ actinet -f file3.cwa
144
166
  :END
145
167
  ````
146
168
 
@@ -151,9 +173,9 @@ Once this file is created, run `cmd < commands.txt` from the terminal.
151
173
  Create a file *command.sh* with:
152
174
 
153
175
  ```console
154
- actinet file1.cwa
155
- actinet file2.cwa
156
- actinet file3.cwa
176
+ actinet -f file1.cwa
177
+ actinet -f file2.cwa
178
+ actinet -f file3.cwa
157
179
  ```
158
180
 
159
181
  Then, run `bash command.sh` from the terminal.
File without changes
File without changes
File without changes
File without changes
File without changes