diff --git a/.gitignore b/.gitignore index cf0c3054..5905fe54 100644 --- a/.gitignore +++ b/.gitignore @@ -126,4 +126,5 @@ doc/source/savefig/ # Sample files, etc. data/ -accelerometer/activityModels/ \ No newline at end of file +accelerometer/activityModels/ +accelerometer/models/ diff --git a/accelerometer/__init__.py b/accelerometer/__init__.py index 65ad668e..c225150d 100644 --- a/accelerometer/__init__.py +++ b/accelerometer/__init__.py @@ -1,5 +1,5 @@ name = "accelerometer" -__version__ = "5.1.3" +__version__ = "6.2.0" __author__ = "Aiden Doherty, Shing Chan, Rosemary Walmsley, Hang Yuan" __email__ = "aiden.doherty@ndph.ox.ac.uk, shing.chan@ndph.ox.ac.uk, rosemary.walmsley@gtc.ox.ac.uk, hang.yuan@keble.ox.ac.uk" __license__ = "See LICENSE.md" diff --git a/accelerometer/accPlot.py b/accelerometer/accPlot.py index adabba12..a765ec19 100644 --- a/accelerometer/accPlot.py +++ b/accelerometer/accPlot.py @@ -24,7 +24,7 @@ 'vehicle': 'saddlebrown', 'light': 'darkorange', 'mixed': 'seagreen', - 'walking': 'green', + 'walking': 'limegreen', 'moderate-vigorous': 'green', 'bicycling': 'springgreen', 'tasks-light': 'darkorange', diff --git a/accelerometer/classification.py b/accelerometer/classification.py index a68250d0..82b46831 100644 --- a/accelerometer/classification.py +++ b/accelerometer/classification.py @@ -40,6 +40,9 @@ def activityClassification(epoch, activityModel="walmsley"): :rtype: list(str) """ + use_cutpoints = 'chan' in activityModel + smooth_sleep = 'chan' in activityModel + activityModel = resolveModelPath(activityModel) featureCols = joblib.load(getFileFromTar(activityModel, 'featureCols')) @@ -51,8 +54,29 @@ def activityClassification(epoch, activityModel="walmsley"): model = joblib.load(getFileFromTar(activityModel, 'model')) hmmParams = joblib.load(getFileFromTar(activityModel, 'hmmParams')) + labels = joblib.load(getFileFromTar(activityModel, 'labels')).tolist() + Y = viterbi(model.predict(X), hmmParams) + if smooth_sleep: + sleep = pd.Series(Y == 'sleep') + sleep_streak = ( + sleep.ne(sleep.shift()) + .cumsum() + .pipe(lambda x: x.groupby(x).transform('count') * sleep) + ) + # TODO: hardcoded 120 = 1hr + Y[(Y == 'sleep') & (sleep_streak < 120)] = 'sedentary' + + if use_cutpoints: + enmo = epoch['enmoTrunc'].to_numpy() + enmo = enmo[mask] + Y[(Y == 'other') & (enmo < .1)] = 'light' + Y[(Y == 'other') & (enmo >= .1)] = 'moderate-vigorous' + labels.remove('other') + labels.append('light') + labels.append('moderate-vigorous') + # Append predicted activities to epoch dataframe epoch["label"] = np.nan epoch.loc[mask, "label"] = Y @@ -62,8 +86,6 @@ def activityClassification(epoch, activityModel="walmsley"): if METs is not None: epoch["MET"] = epoch["label"].replace(METs) - labels = joblib.load(getFileFromTar(activityModel, 'labels')).tolist() - # One-hot encoding for lab in labels: epoch[lab] = 0 diff --git a/accelerometer/models.py b/accelerometer/models.py index 33c494b7..5278bdf4 100644 --- a/accelerometer/models.py +++ b/accelerometer/models.py @@ -1,36 +1,35 @@ import pathlib -ROOT_DIR = pathlib.Path(__file__).parent -MODEL_VER = "10Feb2022" -MODEL_DIR = ROOT_DIR / "models" -MODEL_URL = "https://wearables-files.ndph.ox.ac.uk/files/models" +MODEL_DIR = pathlib.Path(__file__).parent / "models" +MODEL_ROOT_URL = "https://wearables-files.ndph.ox.ac.uk/files/models/biobankAccelerometerAnalysis" MODELS = { + 'willetts': { - "pth": MODEL_DIR / MODEL_VER / "willetts/model.tar", - "url": f"{MODEL_URL}/{MODEL_VER}/willetts/model.tar", + "pth": MODEL_DIR / "willetts" / "20220210.tar", + "url": f"{MODEL_ROOT_URL}/willetts/20220210.tar", }, + 'doherty': { - "pth": MODEL_DIR / MODEL_VER / "doherty/model.tar", - "url": f"{MODEL_URL}/{MODEL_VER}/doherty/model.tar", + "pth": MODEL_DIR / "doherty" / "20220210.tar", + "url": f"{MODEL_ROOT_URL}/doherty/20220210.tar", }, + 'walmsley': { - "pth": MODEL_DIR / MODEL_VER / "walmsley/model.tar", - "url": f"{MODEL_URL}/{MODEL_VER}/walmsley/model.tar", + "pth": MODEL_DIR / "walmsley" / "20220210.tar", + "url": f"{MODEL_ROOT_URL}/walmsley/20220210.tar", }, - 'willetts-10Feb2022': { - "pth": MODEL_DIR / "10Feb2022" / "willetts/model.tar", - "url": f"{MODEL_URL}/10Feb2022/walmsley/model.tar", - }, - 'doherty-10Feb2022': { - "pth": MODEL_DIR / "10Feb2022" / "doherty/model.tar", - "url": f"{MODEL_URL}/10Feb2022/walmsley/model.tar", + 'chan': { + "pth": MODEL_DIR / "chan" / "20230103.tar", + "url": f"{MODEL_ROOT_URL}/chan/20230103.tar", + }, - 'walmsley-10Feb2022': { - "pth": MODEL_DIR / "10Feb2022" / "walmsley/model.tar", - "url": f"{MODEL_URL}/10Feb2022/walmsley/model.tar", + + 'chanw': { + "pth": MODEL_DIR / "chanw" / "20230106.tar", + "url": f"{MODEL_ROOT_URL}/chanw/20230106.tar" }, } diff --git a/build_scripts/build_clean.sh b/build_scripts/build_clean.sh new file mode 100644 index 00000000..f6187c59 --- /dev/null +++ b/build_scripts/build_clean.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rm -r actipy.egg-info build dist +rm -r conda-recipe diff --git a/build_scripts/build_conda.sh b/build_scripts/build_conda.sh new file mode 100644 index 00000000..3ad0a1ba --- /dev/null +++ b/build_scripts/build_conda.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Note: Be sure package already in PyPI + +conda install anaconda-client && +conda install conda-build && +# TODO: allow user-specified version and append this to next line: --version x.x.x +conda skeleton pypi accelerometer --output-dir conda-recipe && +conda build -c conda-forge conda-recipe/accelerometer + +printf "\nNext steps:\n-----------\n" +printf "Login to Anaconda:\n> anaconda login\n" +printf "\nUpload package (path is printed in previous steps):\n> anaconda upload --user oxwear /path/to/package.tar.bz2\n\n" + +# anaconda login +# anaconda upload --user oxwear /path/to/package.tar.bz2 diff --git a/build_scripts/build_pypi.sh b/build_scripts/build_pypi.sh new file mode 100644 index 00000000..bc4c9ee5 --- /dev/null +++ b/build_scripts/build_pypi.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# You must have Java Development Kit (JDK) 8 (1.8). If higher (>8) then it must +# support --release flag to pin down the version when compiling. +# Always compile with 8 (1.8) to keep backward compatibility. +# In conda, you can get a JDK version that supports --release flag: +# conda install openjdk +javac --version && # java version +javac -cp accelerometer/java/JTransforms-3.1-with-dependencies.jar accelerometer/java/*.java --release 8 && # compile java files (using release 8) +python setup.py sdist bdist_wheel && # setuptools +twine check dist/* && +printf "\nTo upload to Test PyPI:\n> twine upload --repository-url https://test.pypi.org/legacy/ dist/*\n" && +printf "\nTo upload to PyPI:\n> twine upload dist/*\n\n" + +# twine upload --repository-url https://test.pypi.org/legacy/ dist/* +# twine upload dist/* diff --git a/setup.py b/setup.py index efb4f9be..ca9a902a 100644 --- a/setup.py +++ b/setup.py @@ -39,9 +39,25 @@ def get_string(string, rel_path="accelerometer/__init__.py"): 'statsmodels>=0.12.2', 'imbalanced-learn==0.8.1', 'scikit-learn==1.0.1', - 'joblib==1.1.0', + 'joblib==1.2.0', 'tqdm>=4.59.0', ], + extras_require={ + "dev": [ + "flake8", + "autopep8", + "ipython", + "ipdb", + "twine", + ], + "docs": [ + "sphinx>=4.2", + "sphinx_rtd_theme>=1.0", + "readthedocs-sphinx-search>=0.1", + "sphinxcontrib-programoutput>=0.17", + "docutils<0.18", + ], + }, classifiers=[ "Programming Language :: Python :: 3", "Operating System :: MacOS :: MacOS X", diff --git a/utilities/downloadDataModels.sh b/utilities/downloadDataModels.sh deleted file mode 100644 index 9c2cedfc..00000000 --- a/utilities/downloadDataModels.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# ------------------------------------------------------------------ -# [Aiden Doherty] Download sample data and activity models -# ------------------------------------------------------------------ - -downloadDir="http://gas.ndph.ox.ac.uk/aidend/accModels/" -# download sample data file -if ! [ -f "data/sample.cwa.gz" ] -then - wget ${downloadDir}sample.cwa.gz -P data/ -fi - -# delete and newly download activity model files -rm activityModels/doherty-may20.tar -rm activityModels/willetts-may20.tar -rm activityModels/walmsley-nov20.tar -rm activityModels/doherty-jan21.tar -rm activityModels/willetts-jan21.tar -rm activityModels/walmsley-jan21.tar -wget ${downloadDir}doherty-may20.tar -P activityModels/ || wget ${downloadDir}doherty-may20.tar -P activityModels/ --no-check-certificate -wget ${downloadDir}willetts-may20.tar -P activityModels/ || wget ${downloadDir}willetts-may20.tar -P activityModels/ --no-check-certificate -wget ${downloadDir}walmsley-nov20.tar -P activityModels/ || wget ${downloadDir}walmsley-nov20.tar -P activityModels/ --no-check-certificate -wget ${downloadDir}doherty-jan21.tar -P activityModels/ || wget ${downloadDir}doherty-jan21.tar -P activityModels/ --no-check-certificate -wget ${downloadDir}willetts-jan21.tar -P activityModels/ || wget ${downloadDir}willetts-jan21.tar -P activityModels/ --no-check-certificate -wget ${downloadDir}walmsley-jan21.tar -P activityModels/ || wget ${downloadDir}walmsley-jan21.tar -P activityModels/ --no-check-certificate - -# download sample training file -if ! [ -f "activityModels/labelled-acc-epochs.csv" ] -then - wget ${downloadDir}labelled-acc-epochs.csv -P activityModels/ || wget ${downloadDir}labelled-acc-epochs.csv -P activityModels/ --no-check-certificate -fi