├── settings.gradle
├── mltoolkit
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ └── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── java
│ │ └── si
│ │ │ └── uni_lj
│ │ │ └── fri
│ │ │ └── lrss
│ │ │ └── machinelearningtoolkit
│ │ │ ├── utils
│ │ │ ├── FeatureNumeric.java
│ │ │ ├── ClassifierConfig.java
│ │ │ ├── FeatureNominal.java
│ │ │ ├── MLException.java
│ │ │ ├── Value.java
│ │ │ ├── Constants.java
│ │ │ ├── Instance.java
│ │ │ ├── Feature.java
│ │ │ └── Signature.java
│ │ │ ├── classifier
│ │ │ ├── OnlineClassifier.java
│ │ │ ├── Classifier.java
│ │ │ ├── ZeroR.java
│ │ │ ├── DensityClustering.java
│ │ │ ├── ID3.java
│ │ │ └── NaiveBayes.java
│ │ │ ├── ClassifierList.java
│ │ │ └── MachineLearningManager.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':mltoolkit'
2 |
--------------------------------------------------------------------------------
/mltoolkit/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | library.iml
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MachineLearningToolkit
3 |
4 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpejovic/MachineLearningToolkit/HEAD/mltoolkit/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpejovic/MachineLearningToolkit/HEAD/mltoolkit/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpejovic/MachineLearningToolkit/HEAD/mltoolkit/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpejovic/MachineLearningToolkit/HEAD/mltoolkit/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/FeatureNumeric.java:
--------------------------------------------------------------------------------
1 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
2 |
3 | /**
4 | * Created by veljko on 04/09/15.
5 | */
6 | public class FeatureNumeric extends Feature {
7 |
8 | public FeatureNumeric(String name) {
9 | super(name, NUMERIC);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/mltoolkit/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/veljko/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
13 |
14 |
15 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/ClassifierConfig.java:
--------------------------------------------------------------------------------
1 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
2 |
3 | import java.util.HashMap;
4 | import java.util.Set;
5 |
6 | public class ClassifierConfig {
7 |
8 | private HashMap mParams;
9 |
10 | public ClassifierConfig() {
11 |
12 | mParams = new HashMap();
13 |
14 | }
15 |
16 | public void addParam(String param, Object value){
17 | mParams.put(param, value);
18 | }
19 |
20 | public Object getParam(String param) {
21 | if (mParams.containsKey(param)) {
22 | return mParams.get(param);
23 | }
24 | return null;
25 | }
26 |
27 | public boolean containsParam(String param) {
28 |
29 | return mParams.containsKey(param);
30 | }
31 |
32 | public Set getAllParams() {
33 | return mParams.keySet();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/FeatureNominal.java:
--------------------------------------------------------------------------------
1 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 |
6 | /**
7 | * Created by veljko on 04/09/15.
8 | */
9 | public class FeatureNominal extends Feature {
10 |
11 | protected ArrayList mCategories;
12 | protected HashMap mCategoryIndex;
13 |
14 | /**
15 | *
16 | * Create a feature object with the given name and type.
17 | * @param fname Feature name.
18 | * @param fvalues
19 | * @throws MLException
20 | */
21 | public FeatureNominal(String fname, ArrayList fvalues) {
22 | super(fname, NOMINAL);
23 | mCategories = (ArrayList) fvalues.clone();
24 | mCategoryIndex = new HashMap();
25 | for(int i=0;i getValues(){
29 | return mCategories;
30 | }
31 |
32 | public int indexOfCategory(String value){
33 | //Log.d(TAG, "feature "+mName+" going for value "+value);
34 | return mCategoryIndex.get(value);
35 |
36 | }
37 |
38 | public String categoryOfIndex(int index){
39 | return mCategories.get(index);
40 | }
41 |
42 | public int numberOfCategories(){
43 | if (mType == NOMINAL) return mCategories.size();
44 | else return 1;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MachineLearningToolkit
2 | ======================
3 |
4 | Machine learning toolkit is an Android library that enables local
5 | machine learning computations on the phone. The library preserves
6 | the state of a learner over the application lifecycle. I.e. it allows
7 | saving the state on a persistent file, and loading it once the application
8 | restarts. It also allows external file loading, thus enables learner
9 | sharing among multiple devices.
10 |
11 | https://github.com/vpejovic/MachineLearningToolkit/
12 |
13 | To use Machine Learning Toolkit in your Android project, simply put:
14 |
15 | compile 'si.uni_lj.fri.lrss.machinelearningtoolkit:mltoolkit:1.2'
16 |
17 | in your app's build.gradle file
18 |
19 |
20 | Copyright (c) 2013, University of Birmingham, UK
21 | Veljko Pejovic,
22 |
23 | This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
24 | Computing for Positive Behaviour Change) Project. For more information, please visit
25 | http://www.ubhave.org
26 |
27 | Permission to use, copy, modify, and/or distribute this software for any purpose with
28 | or without fee is hereby granted, provided that the above copyright notice and this
29 | permission notice appear in all copies.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
32 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
33 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
34 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
36 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
37 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/classifier/OnlineClassifier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.classifier;
24 |
25 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Instance;
26 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
27 |
28 | /**
29 | * A classifier implements this interface if it allows iterative training.
30 | *
31 | * @author Veljko Pejovic, University of Birmingham, UK
32 | *
33 | */
34 | public interface OnlineClassifier {
35 |
36 | /**
37 | * Update an online classifier with the given training instance.
38 | * @param instance A labelled instance with which we train the classifier.
39 | * @throws MLException
40 | */
41 | public void update(Instance instance) throws MLException;
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/MLException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
24 |
25 | public class MLException extends Exception {
26 |
27 | public static final int INCOMPATIBLE_FEATURE_TYPE = 100;
28 | public static final int INCOMPATIBLE_INSTANCE = 101;
29 | public static final int INVALID_PARAMETER = 102;
30 | public static final int INVALID_STATE = 103;
31 | public static final int IO_ERROR = 104;
32 | public static final int IO_FILE_NOT_FOUND_ERROR = 105;
33 | public static final int CLASSIFIER_EXISTS = 200;
34 |
35 | private int mErrorCode;
36 | private String mMessage;
37 |
38 | public MLException(int errorCode, String message) {
39 | super(message);
40 | mMessage = message;
41 | mErrorCode = errorCode;
42 | }
43 |
44 | public int getErrorCode()
45 | {
46 | return mErrorCode;
47 | }
48 |
49 | public String getMessage()
50 | {
51 | return mMessage;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/Value.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 |
24 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
25 |
26 | /**
27 | * Values can be double for numeric, int for nominal,
28 | * and a special NaN for missing values.
29 | *
30 | * @author Veljko Pejovic (v.pejovic@cs.bham.ac.uk)
31 | *
32 | */
33 | public class Value {
34 |
35 | public static final int NOMINAL_VALUE=0;
36 | public static final int NUMERIC_VALUE=1;
37 | public static final int MISSING_VALUE=2;
38 |
39 | private Object mValue;
40 | private int mType;
41 |
42 | public Value(Object value, int type){
43 | switch (type) {
44 | case NOMINAL_VALUE: mValue = value;
45 | mType = NOMINAL_VALUE;
46 | break;
47 | case NUMERIC_VALUE: mValue = value;
48 | mType = NUMERIC_VALUE;
49 | break;
50 | case MISSING_VALUE: mValue = Double.NaN;
51 | mType = MISSING_VALUE;
52 | break;
53 | }
54 | }
55 |
56 | public int getValueType(){
57 | return mType;
58 | }
59 |
60 | public Object getValue(){
61 | return mValue;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
24 |
25 | public class Constants {
26 |
27 | public static final int TYPE_ZERO_R = 1000;
28 | public static final int TYPE_NAIVE_BAYES = 1001;
29 | public static final int TYPE_BAYES_NET = 1002;
30 | public static final int TYPE_ID3 = 1003;
31 | public static final int TYPE_DENSITY_CLUSTER = 1004;
32 |
33 | public static final String CLASSIFIER_STORAGE_FILE = "classifiers.json";
34 |
35 | // Config params
36 |
37 | // Density clustering
38 | public static final String MAX_CLUSTER_DISTANCE = "maxClusterDistance";
39 | public static final String MIN_INCLUSION_PERCENT = "minInclusionPercent";
40 |
41 | public static final double DEFAULT_MAX_CLUSTER_DISTANCE = 1; // in km if GPS
42 | public static final double DEFAULT_MIN_INCLUSION_PERCENT = 50.0;
43 |
44 | // Naive Bayes
45 | public static final String LAPLACE_SMOOTHING = "laplaceSmoothing";
46 |
47 | public static final boolean DEFAULT_LAPLACE_SMOOTHING = true;
48 |
49 | public static final boolean DEBUG = false;
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/Instance.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 |
24 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
25 |
26 | import java.util.ArrayList;
27 |
28 | /**
29 | * Instance is merely a list of Values. It should be used, and comply with,
30 | * the signature of the classifier.
31 | *
32 | * @author Veljko Pejovic, University of Birmingham, UK
33 | *
34 | */
35 | public class Instance {
36 |
37 | private ArrayList mValues;
38 |
39 | public Instance(int a_numFeatures){
40 | mValues = new ArrayList(a_numFeatures);
41 | }
42 |
43 | public Instance(){
44 | this(0);
45 | }
46 |
47 | public Instance(ArrayList featureValues){
48 | mValues = featureValues;
49 | }
50 |
51 | public void addValue(Value value){
52 | mValues.add(value);
53 | }
54 |
55 | public Value getValueAtIndex(int i){
56 | return mValues.get(i);
57 | }
58 |
59 | public void setValueAtIndex(int i, Value value) throws IndexOutOfBoundsException {
60 | mValues.set(i, value);
61 | }
62 |
63 |
64 | public int size(){
65 | return mValues.size();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/Feature.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013, University of Birmingham, UK
3 | * Veljko Pejovic,
4 | *
5 | *
6 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
7 | * Computing for Positive Behaviour Change) Project. For more information, please visit
8 | * http://www.ubhave.org
9 | *
10 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
11 | * or without fee is hereby granted, provided that the above copyright notice and this
12 | * permission notice appear in all copies.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 | ******************************************************************************/
22 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Arrays;
26 | import java.util.HashMap;
27 |
28 | /**
29 | * Features can be nominal or numeric.
30 | *
31 | * @author Veljko Pejovic, University of Birmingham, UK
32 | *
33 | */
34 | public abstract class Feature {
35 |
36 | private static final String TAG = "Feature";
37 | public static final int NOMINAL = 0;
38 | public static final int NUMERIC = 1;
39 |
40 | protected int mType;
41 | protected String mName;
42 |
43 |
44 | /**
45 | * Create a feature object with the given name and type.
46 | * @param fname Feature name.
47 | * @param ftype Feature type. Has to be {@link Feature#NUMERIC}.
48 | * @throws MLException
49 | */
50 | protected Feature(String fname, int ftype) {
51 | mType = ftype;
52 | mName = fname;
53 | }
54 |
55 |
56 | /*public Feature(String fname, int ftype, String[] fvalues) throws MLException{
57 | if (ftype == NUMERIC){
58 | throw new MLException(MLException.INCOMPATIBLE_FEATURE_TYPE,
59 | "Numeric features do not need a list of possible categories;" +
60 | " use Feature(String, int) instead.");
61 | }
62 | mType = ftype;
63 | mName = fname;
64 | mCategories = new ArrayList(Arrays.asList(fvalues));
65 | mCategoryIndex = new HashMap();
66 | for(int i=0;i
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.classifier;
24 |
25 | import java.util.ArrayList;
26 |
27 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
28 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Instance;
29 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
30 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
31 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Value;
32 |
33 | /**
34 | * Every classifier has a signature that defines the features it uses,
35 | * as well as the class feature. It needs to support training and classification.
36 | *
37 | * @author Veljko Pejovic, University of Birmingham, UK
38 | *
39 | */
40 | public abstract class Classifier {
41 |
42 | protected Signature mSignature;
43 |
44 | protected int mType;
45 |
46 | protected ClassifierConfig mConfig;
47 |
48 | protected boolean mTrained;
49 |
50 | private static final String TAG = "Classifier";
51 |
52 | public Classifier(Signature a_signature, ClassifierConfig a_config) {
53 | mSignature = a_signature;
54 | mConfig = a_config;
55 | }
56 |
57 | /**
58 | * Train the classifier with labelled data instances.
59 | * @param instances Labelled data instances. The instances have to correspond to the classifier
60 | * signature.
61 | * @throws MLException
62 | */
63 | public abstract void train(ArrayList instances) throws MLException;
64 |
65 | /**
66 | * Classify an unlabelled instance.
67 | * @param instance Instance to be classified.
68 | * @return The inferred label corresponding to the given instance.
69 | * @throws MLException
70 | */
71 | public abstract Value classify(Instance instance) throws MLException;
72 |
73 | public abstract void printClassifierInfo();
74 |
75 | public boolean isTrained() {
76 | return mTrained;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/mltoolkit/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.jfrog.bintray'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | android {
5 | compileSdkVersion 23
6 | buildToolsVersion "23.0.1"
7 | resourcePrefix "mltoolkit__"
8 |
9 | defaultConfig {
10 | minSdkVersion 8
11 | targetSdkVersion 23
12 | versionCode 2
13 | versionName "1.2"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 |
24 | def siteUrl = 'https://github.com/vpejovic/MachineLearningToolkit' // Homepage URL of the library
25 | def gitUrl = 'https://github.com/vpejovic/MachineLearningToolkit.git' // Git repository URL
26 | group = "si.uni_lj.fri.lrss.machinelearningtoolkit" // Maven Group ID for the artifact
27 | version = "1.2"
28 |
29 | Properties properties = new Properties()
30 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
31 |
32 | bintray {
33 | user = properties.getProperty("bintray.user")
34 | key = properties.getProperty("bintray.apikey")
35 |
36 | configurations = ['archives']
37 | pkg {
38 | repo = "maven"
39 | name = "Machinelearningtoolkit"
40 | websiteUrl = siteUrl
41 | vcsUrl = gitUrl
42 | licenses = ["Apache-2.0"]
43 | publish = true
44 | version {
45 | name = '1.2'
46 | desc = 'Machine learning toolkit 1.2 final'
47 | released = new Date()
48 | vcsTag = '1.2'
49 | }
50 | }
51 | }
52 |
53 | install {
54 | repositories.mavenInstaller {
55 | // This generates POM.xml with proper parameters
56 | pom {
57 | project {
58 | packaging 'aar'
59 |
60 | // Add your description here
61 | name 'Machine learning library for Android'
62 | url siteUrl
63 |
64 | // Set your license
65 | licenses {
66 | license {
67 | name 'The Apache Software License, Version 2.0'
68 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
69 | }
70 | }
71 | developers {
72 | developer {
73 | id ''
74 | name 'Veljko Pejovic'
75 | email 'Veljko.Pejovic@fri.uni-lj.si'
76 | }
77 | }
78 | scm {
79 | connection gitUrl
80 | developerConnection gitUrl
81 | url siteUrl
82 |
83 | }
84 | }
85 | }
86 | }
87 | }
88 |
89 | dependencies {
90 | compile fileTree(dir: 'libs', include: ['*.jar'])
91 | compile 'com.google.code.gson:gson:2.3'
92 | }
93 |
94 |
95 | task sourcesJar(type: Jar) {
96 | from android.sourceSets.main.java.srcDirs
97 | classifier = 'sources'
98 | }
99 |
100 | task javadoc(type: Javadoc) {
101 | source = android.sourceSets.main.java.srcDirs
102 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
103 | }
104 |
105 | task javadocJar(type: Jar, dependsOn: javadoc) {
106 | classifier = 'javadoc'
107 | from javadoc.destinationDir
108 | }
109 | artifacts {
110 | archives javadocJar
111 | archives sourcesJar
112 | }
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/ClassifierList.java:
--------------------------------------------------------------------------------
1 | package si.uni_lj.fri.lrss.machinelearningtoolkit;
2 |
3 |
4 | import android.util.Log;
5 |
6 | import java.util.HashMap;
7 |
8 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.Classifier;
9 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.DensityClustering;
10 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.ID3;
11 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.NaiveBayes;
12 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.ZeroR;
13 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
14 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Constants;
15 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
16 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
17 |
18 | /**
19 | *
20 | * Takes care of classifier instantiation and registration.
21 | * Every classifier that is created has a unique name.
22 | *
23 | * @author Veljko Pejovic, University of Birmingham, UK
24 | *
25 | */
26 | public class ClassifierList {
27 |
28 | private static final String TAG = "ClassifierList";
29 |
30 | private HashMap mNamedClassifiers;
31 |
32 | //private final Random d_keyGenerator;
33 |
34 | protected ClassifierList(){
35 | if (Constants.DEBUG) Log.d(TAG, "ClassifierList empty constructor");
36 | mNamedClassifiers = new HashMap();
37 | //d_keyGenerator = new Random();
38 | }
39 |
40 | private static Classifier createClassifier (
41 | int type,
42 | Signature signature,
43 | ClassifierConfig config) throws MLException{
44 |
45 | if (Constants.DEBUG) Log.d(TAG, "createClassifier");
46 |
47 | switch (type) {
48 | case Constants.TYPE_NAIVE_BAYES:
49 | if (Constants.DEBUG) Log.d(TAG, "create NaiveBayes");
50 | return new NaiveBayes(signature, config);
51 | case Constants.TYPE_ID3:
52 | if (Constants.DEBUG) Log.d(TAG, "create ID3");
53 | return new ID3(signature, config);
54 | case Constants.TYPE_DENSITY_CLUSTER:
55 | if (Constants.DEBUG) Log.d(TAG, "create DensityClustering");
56 | return new DensityClustering(signature, config);
57 | case Constants.TYPE_ZERO_R:
58 | if (Constants.DEBUG) Log.d(TAG, "create ZeroR");
59 | return new ZeroR(signature, config);
60 | default:
61 | if (Constants.DEBUG) Log.d(TAG, "create default (NaiveBayes)");
62 | return new NaiveBayes(signature, config);
63 | }
64 | }
65 |
66 | protected void removeClassifier(String a_classifierID) {
67 | if (mNamedClassifiers.containsKey(a_classifierID)) {
68 | mNamedClassifiers.remove(a_classifierID);
69 | }
70 | }
71 |
72 | protected Classifier getClassifier(String a_classifierID)
73 | {
74 | if (mNamedClassifiers.containsKey(a_classifierID)) {
75 | return mNamedClassifiers.get(a_classifierID);
76 | } else {
77 | return null;
78 | }
79 | }
80 |
81 | protected synchronized Classifier addClassifier(
82 | int type, Signature signature, ClassifierConfig config, String name) throws MLException {
83 |
84 | if (Constants.DEBUG) Log.d(TAG, "addClassifier");
85 |
86 | Classifier classifier = createClassifier(type, signature, config);
87 | mNamedClassifiers.put(name, classifier);
88 | return classifier;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/utils/Signature.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.utils;
24 |
25 | import java.util.ArrayList;
26 |
27 | import android.util.Log;
28 |
29 | /**
30 | * Signature defines features used by a classifier, their names and the
31 | * index of the class feature. Instances of data (which consist of values)
32 | * need to correspond to the signature of the classifier they are used for.
33 | * Signature exposes a method for checking that compliance.
34 | *
35 | * @author Veljko Pejovic, University of Birmingham, UK
36 | *
37 | */
38 | public class Signature {
39 |
40 | private static final String TAG = "Signature";
41 |
42 | private ArrayList mFeatures;
43 |
44 | private int mClassIndex;
45 |
46 | public Signature(ArrayList features, int classIndex){
47 | mFeatures = features;
48 | mClassIndex = classIndex;
49 |
50 | }
51 |
52 | public Signature(ArrayList features){
53 | this(features, features.size() - 1);
54 | }
55 |
56 | public void setClassIndex(int classIndex){
57 | mClassIndex = classIndex;
58 | }
59 |
60 | public int getClassIndex(){
61 | return mClassIndex;
62 | }
63 |
64 | public Feature getClassFeature(){
65 | return getFeatureAtIndex(getClassIndex());
66 | }
67 |
68 | public Feature getFeatureAtIndex(int i){
69 | return mFeatures.get(i);
70 | }
71 |
72 | public ArrayList getFeatures(){
73 | return mFeatures;
74 | }
75 |
76 | public int size() {
77 | return mFeatures.size();
78 | }
79 |
80 | public boolean checkCompliance(Instance instance, boolean training) {
81 | Log.d(TAG, "checkInstanceCompliance");
82 | int checkSize = instance.size();
83 |
84 | // Instances that are used for training should have the exact same features as the signature.
85 | // Those that are about to be classified, should have one feature less -- the class feature.
86 | if (!training) {
87 | checkSize++;
88 | }
89 |
90 | if (checkSize != this.getFeatures().size()){
91 | Log.d(TAG, "Expected number of features: "+this.getFeatures().size()+" got "+checkSize);
92 | for (int i=0; i
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.classifier;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Arrays;
27 |
28 | import android.util.Log;
29 |
30 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
31 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Constants;
32 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Feature;
33 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.FeatureNominal;
34 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Instance;
35 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
36 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
37 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Value;
38 |
39 | /**
40 | *
41 | * ZeroR classifier is not taking any features into account during the classification.
42 | * It merely outputs the mean value/most frequent class.
43 | * Besides classification, we can use ZeroR for regression.
44 | *
45 | * @author Veljko Pejovic, University of Birmingham, UK
46 | *
47 | */
48 | public class ZeroR extends Classifier implements OnlineClassifier {
49 |
50 | private static final String TAG = "ZeroR";
51 |
52 | private double[] mClassCounts;
53 |
54 | private static final Object mLock = new Object();
55 |
56 | public ZeroR(Signature a_signature, ClassifierConfig a_config) {
57 | super(a_signature, a_config);
58 | Feature classFeature = mSignature.getClassFeature();
59 | if (classFeature.getFeatureType() == Feature.NOMINAL)
60 | mClassCounts = new double[((FeatureNominal)classFeature).numberOfCategories()];
61 | else if (classFeature.getFeatureType() == Feature.NUMERIC)
62 | mClassCounts = new double[2];
63 | Arrays.fill(mClassCounts, 0.0);
64 | }
65 |
66 | @Override
67 | public void update(Instance instance) throws MLException {
68 |
69 | if (!mSignature.checkCompliance(instance, true)){
70 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
71 | "Instance is not compatible with the dataset used for classifier construction.");
72 | }
73 |
74 | Feature classFeature = mSignature.getClassFeature();
75 |
76 | Value classValue = instance.getValueAtIndex(mSignature.getClassIndex());
77 |
78 | if (classFeature.getFeatureType() == Feature.NOMINAL) {
79 | int classValueInt = ((FeatureNominal)classFeature).indexOfCategory((String) classValue.getValue());
80 | mClassCounts[classValueInt] += 1;
81 | } else if (classFeature.getFeatureType() == Feature.NUMERIC) {
82 | mClassCounts[0] += (Double) classValue.getValue();
83 | mClassCounts[1] += 1;
84 | }
85 | }
86 |
87 | @Override
88 | public void train(ArrayList a_instances) throws MLException {
89 | for(Instance a_instance : a_instances){
90 | synchronized (mLock) {
91 | this.update(a_instance);
92 | }
93 | }
94 | }
95 |
96 | @Override
97 | public Value classify(Instance instance) throws MLException {
98 |
99 | if (!mSignature.checkCompliance(instance, false)){
100 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
101 | "Instance is not compatible with the dataset used for classifier construction.");
102 | }
103 | if (((FeatureNominal)mSignature.getClassFeature()).getFeatureType() == Feature.NOMINAL) {
104 | double maxCount = 0;
105 | int maxValueIndex = 0;
106 |
107 | for (int i=0; i< mClassCounts.length; i++) {
108 | if (Constants.DEBUG) Log.d(TAG, "Class value index "+i+" count "+ mClassCounts[i]);
109 | if (mClassCounts[i] > maxCount) {
110 | maxValueIndex = i;
111 | maxCount = mClassCounts[i];
112 | }
113 | }
114 |
115 | return new Value(((FeatureNominal)mSignature.getClassFeature()).categoryOfIndex(maxValueIndex),
116 | Value.NOMINAL_VALUE);
117 | } else { //it's NUMERIC
118 | double mean = mClassCounts[0]/ mClassCounts[1];
119 | return new Value(mean, Value.NUMERIC_VALUE);
120 | }
121 | }
122 |
123 | @Override
124 | public void printClassifierInfo() {
125 | // TODO Auto-generated method stub
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/MachineLearningManager.java:
--------------------------------------------------------------------------------
1 | package si.uni_lj.fri.lrss.machinelearningtoolkit;
2 |
3 |
4 | import java.io.BufferedReader;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.FileReader;
10 | import java.io.IOException;
11 | import java.io.InputStreamReader;
12 | import java.io.OutputStreamWriter;
13 | import java.lang.reflect.Type;
14 | import java.util.Arrays;
15 |
16 | import android.content.Context;
17 | import android.os.Environment;
18 | import android.util.Log;
19 |
20 | import com.google.gson.Gson;
21 | import com.google.gson.GsonBuilder;
22 | import com.google.gson.JsonDeserializationContext;
23 | import com.google.gson.JsonDeserializer;
24 | import com.google.gson.JsonElement;
25 | import com.google.gson.JsonObject;
26 | import com.google.gson.JsonParseException;
27 |
28 | import si.uni_lj.fri.lrss.machinelearningtoolkit.ClassifierList;
29 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.Classifier;
30 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.DensityClustering;
31 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.ID3;
32 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.NaiveBayes;
33 | import si.uni_lj.fri.lrss.machinelearningtoolkit.classifier.ZeroR;
34 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Constants;
35 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
36 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
37 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
38 |
39 | /**
40 | * Deals with instantiating classifiers, sending training/test data
41 | * to the right classifier, namely the one that an application has instantiated earlier.
42 | * Has methods that allow it to save classifiers to a file, and load them from a file.
43 | * This should be used when a service that uses the manager is (re)started/destroyed.
44 | * Only one MachineLearningManager exists per context to ensure consistency.
45 | *
46 | * @author Veljko Pejovic, University of Birmingham, UK
47 | *
48 | */
49 | public class MachineLearningManager {
50 |
51 | private static final String TAG = "MLManager";
52 |
53 | private static MachineLearningManager sManager;
54 | private final ClassifierList mClassifiers;
55 | private final Context mContext;
56 | private static final Object sLock = new Object();
57 |
58 | /**
59 | * Instantiates a new manager to be used for communication between the ML library and the
60 | * overlying application. If the manager for the given context has been instantiated already,
61 | * the existing objects will be returned. The returned manager is a singleton class for the
62 | * given context.
63 | * @param context Context for which the manager is to be instantiated.
64 | * @return Manager for the given context.
65 | * @throws MLException
66 | */
67 | public static MachineLearningManager getMLManager(Context context) throws MLException {
68 |
69 | if (context == null) {
70 | throw new MLException(MLException.INVALID_PARAMETER,
71 | " Invalid parameter, context object passed is null");
72 | }
73 | if (sManager == null)
74 | synchronized (sLock)
75 | {
76 | if (sManager == null) sManager = new MachineLearningManager(context);
77 | }
78 | return sManager;
79 | }
80 |
81 | private MachineLearningManager(Context context) throws MLException {
82 | mContext = context;
83 | // automatic loading if classifiers exist on the device
84 | if (Arrays.asList(mContext.fileList()).contains(Constants.CLASSIFIER_STORAGE_FILE)){
85 | mClassifiers = loadFromPersistent();
86 | }
87 | else{
88 | mClassifiers = new ClassifierList();
89 | }
90 | }
91 |
92 | /**
93 | * Instantiates a new, or returns an existing classifier with the given name and properties.
94 | * Properties include classifier type (available options can be found in {@link Constants}),
95 | * classifier signature ({@link Signature}) and classifier configuration
96 | * ({@link ClassifierConfig}).
97 | * @param type Type of classifier. One of the options from {@link Constants}).
98 | * @param signature Classifier signature
99 | * @param config Classifier configuration, if any.
100 | * @param name Unique classifier name.
101 | * @return A new, or an existing classifier if one with the given name is already instantiated.
102 | */
103 | public Classifier addClassifier(int type, Signature signature,
104 | ClassifierConfig config, String name) throws MLException {
105 |
106 | Log.d(TAG, "addClassifier");
107 |
108 | Classifier cls = mClassifiers.getClassifier(name);
109 |
110 | // TODO: Expose classifier properties so that we can check
111 | // if the existing classifier is the same as the one we require.
112 | if (cls != null) {
113 | //Log.d(TAG, "return existing classifier");
114 | return cls;
115 | }
116 | //throw new MLException(MLException.CLASSIFIER_EXISTS, "Classifier "+name+" already exists.");
117 | //Log.d(TAG, "return brand new classifier");
118 | return mClassifiers.addClassifier(type, signature, config, name);
119 | }
120 |
121 | /**
122 | * Removes a classifier if it exists. If a classifier with the given name does not exist, nothing
123 | * will happen.
124 | * @param name Classifier name.
125 | */
126 | public void removeClassifier(String name){
127 | mClassifiers.removeClassifier(name);
128 | }
129 |
130 | /**
131 | * Returns a classifier with the given name, or null if such a classifier doesn't exist.
132 | * @param name Classifier name.
133 | * @return An instance of the classifier with the given name.
134 | */
135 | public Classifier getClassifier(String name){
136 | return mClassifiers.getClassifier(name);
137 | }
138 |
139 | public String getJSON() {
140 | Gson gson = new Gson();
141 | return gson.toJson(mClassifiers);
142 | }
143 |
144 | /**
145 | * Saves classifiers to an external json-formatted file.
146 | * @param filename Desired classifier file name.
147 | */
148 | public void saveToPersistentExternal(String filename) throws MLException {
149 | Gson gson = new Gson();
150 | String jsonString = gson.toJson(mClassifiers);
151 |
152 | try {
153 | String root = Environment.getExternalStorageDirectory().toString();
154 | File file = new File(root + filename);
155 | FileOutputStream fos = new FileOutputStream(file);
156 | OutputStreamWriter osw = new OutputStreamWriter(fos);
157 | osw.write(jsonString);
158 | osw.flush();
159 | osw.close();
160 | } catch (FileNotFoundException e) {
161 | throw new MLException(MLException.IO_FILE_NOT_FOUND_ERROR, "File "+filename+" not found.");
162 | } catch (IOException e) {
163 | throw new MLException(MLException.IO_ERROR, "IO exception while writing "+filename+".");
164 | }
165 | }
166 |
167 | /**
168 | * Saves classifiers to a persistent internal file. The overlying application should call this
169 | * method before the application is closed/destroyed.
170 | */
171 | public void saveToPersistent() throws MLException {
172 | Gson gson = new Gson();
173 | String jsonString = gson.toJson(mClassifiers);
174 |
175 | try {
176 | FileOutputStream fos = mContext
177 | .openFileOutput(Constants.CLASSIFIER_STORAGE_FILE, Context.MODE_PRIVATE);
178 | OutputStreamWriter osw = new OutputStreamWriter(fos);
179 | osw.write(jsonString);
180 | osw.flush();
181 | osw.close();
182 | } catch (FileNotFoundException e) {
183 | throw new MLException(MLException.IO_FILE_NOT_FOUND_ERROR, "Classifier file not found.");
184 | } catch (IOException e) {
185 | throw new MLException(MLException.IO_ERROR, "IO exception while writing internal storage.");
186 | }
187 | }
188 |
189 | /**
190 | * Loads classifiers from a given file residing on the external storage.
191 | * @param filename JSON formatted file with classifier information.
192 | * @return List of classifiers loaded from the file.
193 | */
194 | public ClassifierList loadFromExternalPersistent(String filename) throws MLException {
195 |
196 | StringBuilder jsonString = new StringBuilder();
197 |
198 | try {
199 | File sdcard = Environment.getExternalStorageDirectory();
200 | File file = new File(sdcard,filename);
201 | FileReader fr = new FileReader(file);
202 | BufferedReader br = new BufferedReader(fr);
203 |
204 | String line;
205 | while ((line = br.readLine()) != null) {
206 | jsonString.append(line);
207 | Log.d(TAG, "Read "+line);
208 | }
209 | br.close();
210 | } catch (FileNotFoundException e) {
211 | throw new MLException(MLException.IO_FILE_NOT_FOUND_ERROR, "File "+filename+" not found.");
212 | } catch (IOException e) {
213 | throw new MLException(MLException.IO_ERROR, "IO exception while writing "+filename+".");
214 | }
215 |
216 | Gson gson = new GsonBuilder()
217 | .registerTypeHierarchyAdapter(Classifier.class, new ClassifierAdapter())
218 | .create();
219 |
220 | return (ClassifierList) gson.fromJson(jsonString.toString(), ClassifierList.class);
221 | }
222 |
223 | /**
224 | * Loads classifiers from a persistent internal file. The method is called automatically when
225 | * the ML manager is instantiated.
226 | */
227 | public ClassifierList loadFromPersistent() throws MLException {
228 |
229 | StringBuilder jsonString = new StringBuilder();
230 |
231 | try {
232 | FileInputStream is = mContext.openFileInput(Constants.CLASSIFIER_STORAGE_FILE);
233 | BufferedReader br = new BufferedReader(new InputStreamReader(is));
234 |
235 | String line;
236 | while ((line = br.readLine()) != null) {
237 | jsonString.append(line);
238 | }
239 | br.close();
240 | } catch (FileNotFoundException e) {
241 | throw new MLException(MLException.IO_FILE_NOT_FOUND_ERROR, "Classifier file not found.");
242 | } catch (IOException e) {
243 | throw new MLException(MLException.IO_ERROR, "IO exception while writing internal storage.");
244 | }
245 |
246 | Gson gson = new GsonBuilder()
247 | .registerTypeHierarchyAdapter(Classifier.class, new ClassifierAdapter())
248 | .create();
249 |
250 | return (ClassifierList) gson.fromJson(jsonString.toString(), ClassifierList.class);
251 | }
252 |
253 | static class ClassifierAdapter implements JsonDeserializer {
254 |
255 | Gson gson;
256 |
257 | ClassifierAdapter(){
258 | GsonBuilder gsonBuilder = new GsonBuilder();
259 | gson = gsonBuilder.create();
260 | }
261 |
262 | public Classifier deserialize(JsonElement elem, Type type, JsonDeserializationContext context)
263 | throws JsonParseException {
264 | Classifier result = null;
265 |
266 | JsonObject object = elem.getAsJsonObject();
267 | int intType = object.get("mType").getAsInt();
268 | switch(intType){
269 | case Constants.TYPE_NAIVE_BAYES:
270 | result = gson.fromJson(elem, NaiveBayes.class);
271 | break;
272 | case Constants.TYPE_ID3:
273 | result = gson.fromJson(elem, ID3.class);
274 | break;
275 | case Constants.TYPE_DENSITY_CLUSTER:
276 | result = gson.fromJson(elem, DensityClustering.class);
277 | break;
278 | case Constants.TYPE_ZERO_R:
279 | result = gson.fromJson(elem, ZeroR.class);
280 | break;
281 | }
282 | if (result != null) result.printClassifierInfo();
283 | return result;
284 | }
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/mltoolkit/src/main/java/si/uni_lj/fri/lrss/machinelearningtoolkit/classifier/DensityClustering.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, University of Birmingham, UK,
3 | * Copyright (c) 2013, University of Ljubljana, Slovenia,
4 | * Veljko Pejovic,
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 | package si.uni_lj.fri.lrss.machinelearningtoolkit.classifier;
24 |
25 | import java.util.ArrayList;
26 | import java.util.HashMap;
27 | import java.util.Iterator;
28 |
29 | import android.util.Log;
30 |
31 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
32 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Constants;
33 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Feature;
34 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.FeatureNominal;
35 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Instance;
36 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
37 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
38 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Value;
39 |
40 | /**
41 | * This classifier calculates centroids of labelled, clustered data instances.
42 | * The classifier first removes cluster outliers using the density method,
43 | * i.e. if less than a given percentage of other data instances are in the
44 | * epsilon environment of a point, the point is removed as an outlier.
45 | * Cluster centroids are then calculated. The classifier is not an online
46 | * classifier, and is batch trained from given instances.
47 | *
48 | * At the classification time, an instance is given a label that corresponds
49 | * to the closest cluster centroid. The distance used for density and closeness
50 | * calculation is euclidean distance. In case only two nominal features exist,
51 | * the classifier assumes that GPS coordinates are given, thus it adjusts the
52 | * distance calculation according to the harvesine formula.
53 | *
54 | * The classifier can only be instantiated with a nominal class feature and one
55 | * or more numeric attribute features.
56 | *
57 | * LIMITATION: If no data are present for a label, the assigned centroid will
58 | * have all zeros coordinates.
59 | *
60 | * @author Veljko Pejovic, University of Birmingham, UK
61 | *
62 | */
63 | public class DensityClustering extends Classifier {
64 |
65 | private static final String TAG = "DensityClustering";
66 |
67 | private HashMap mCentroids;
68 |
69 | private HashMap mNumTrains;
70 |
71 | private double mMaxDistance;
72 |
73 | private double mMinInclusionPct;
74 |
75 | private static double toRad(double a_degree) {
76 | return Math.PI*a_degree/180.0;
77 | }
78 |
79 | private static double distance(final double[] coordsA,final double[] coordsB)
80 | throws MLException {
81 |
82 | if (coordsA.length != coordsB.length) {
83 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
84 | "Instance is not compatible with the dataset used for classifier construction.");
85 | }
86 |
87 | // We assume GPS coordinates if vectors of size two are given
88 | if (coordsA.length == 2) {
89 |
90 | double lat1 = coordsA[0];
91 | double lon1 = coordsA[1];
92 | double lat2 = coordsB[0];
93 | double lon2 = coordsB[1];
94 | double R = 6371.0;
95 | double dLat = toRad(lat2 - lat1);
96 | double dLon = toRad(lon2 - lon1);
97 | double radLat1 = toRad(lat1);
98 | double radLat2 = toRad(lat2);
99 |
100 | double a = Math.sin(dLat/2.0) * Math.sin(dLat/2.0) +
101 | Math.sin(dLon/2.0) * Math.sin(dLon/2.0) * Math.cos(radLat1) * Math.cos(radLat2);
102 | double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
103 |
104 | return R * c * 1000.0;
105 | }
106 | // Otherwise Euclidean distance
107 | else {
108 | double sqrSum = 0;
109 | for(int i=0; i classValues = classFeature.getValues();
140 |
141 | mNumTrains = new HashMap();
142 | mCentroids = new HashMap();
143 | for (String classValue : classValues) {
144 | mCentroids.put(classValue, new double[mSignature.size() - 1]);
145 | mNumTrains.put(classValue, 0);
146 | }
147 |
148 | }
149 |
150 | @Override
151 | public void train(ArrayList instances) throws MLException {
152 |
153 | if (Constants.DEBUG) Log.d(TAG, "train with "+instances.size()+" instances");
154 |
155 | // Remove outliers (density based)
156 | String curLabel;
157 | double curCoordValues[] = new double[mSignature.size()-1];
158 |
159 | for (Iterator curIter = instances.iterator(); curIter.hasNext();) {
160 |
161 | Instance curInstance = curIter.next();
162 |
163 | if (!mSignature.checkCompliance(curInstance, true)){
164 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
165 | "Instance is not compatible with the dataset used for classifier construction.");
166 | }
167 |
168 | curLabel = (String) curInstance.getValueAtIndex(mSignature.getClassIndex()).getValue();
169 |
170 | for(int i=0; i< mSignature.size()-1; i++) {
171 | curCoordValues[i] = (Double) curInstance.getValueAtIndex(i).getValue();
172 | }
173 |
174 | String otherLabel;
175 | double otherCoordValues[] = new double[mSignature.size()-1];
176 |
177 | int total = 0;
178 | int totalInside = 0;
179 |
180 | for (Iterator otherIter = instances.iterator(); otherIter.hasNext();) {
181 |
182 | Instance otherInstance = otherIter.next();
183 |
184 | if (otherInstance != curInstance) {
185 |
186 | if (!mSignature.checkCompliance(otherInstance, true)){
187 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
188 | "Instance is not compatible with the dataset used for classifier construction.");
189 | }
190 |
191 | otherLabel = (String) otherInstance.getValueAtIndex(mSignature.getClassIndex()).getValue();
192 |
193 | if (otherLabel.equals(curLabel)) {
194 |
195 | for(int i=0; i< mSignature.size()-1; i++) {
196 | otherCoordValues[i] = (Double) otherInstance.getValueAtIndex(i).getValue();
197 | }
198 |
199 | double distance = distance(curCoordValues, otherCoordValues);
200 |
201 | total++;
202 |
203 | if (distance< mMaxDistance) totalInside++;
204 | }
205 | }
206 | }
207 |
208 | if (Constants.DEBUG) Log.d(TAG, "Points: "+totalInside+"/"+total+" vs "
209 | +mMinInclusionPct+"/100");
210 | if (total > 0) {
211 | if (totalInside/(double)total < (mMinInclusionPct /100.0)){
212 | if (Constants.DEBUG) Log.d(TAG, "Remove instance");
213 | curIter.remove();
214 | }
215 | }
216 |
217 | }
218 | // At this point only those instances that are tightly packed are in d_instanceQ
219 | if (Constants.DEBUG) Log.d(TAG, "Outliers removed. "+instances.size()+" instances left.");
220 |
221 | // Find cluster centroids
222 | double centroidCoords[];
223 | for (Instance curInstance : instances) {
224 |
225 | curLabel = (String) curInstance.getValueAtIndex(mSignature.getClassIndex()).getValue();
226 | centroidCoords = mCentroids.get(curLabel);
227 |
228 | if (Constants.DEBUG) Log.d(TAG, "Current instance label "+curLabel);
229 |
230 | for(int i=0; i< mSignature.size()-1; i++) {
231 | if (Constants.DEBUG) Log.d(TAG, "added coord "+i+ " with value "
232 | +(Double) curInstance.getValueAtIndex(i).getValue());
233 | centroidCoords[i] += (Double) curInstance.getValueAtIndex(i).getValue();
234 | }
235 |
236 | mNumTrains.put(curLabel, mNumTrains.get(curLabel)+1);
237 |
238 | }
239 |
240 | int numTrains;
241 | for (String classValue : mCentroids.keySet()) {
242 | centroidCoords = mCentroids.get(classValue);
243 | numTrains = mNumTrains.get(classValue);
244 |
245 | if (Constants.DEBUG) Log.d(TAG, "Centroid with label "+classValue
246 | +" contains " +numTrains+ " points.");
247 |
248 | for (int i=0; i< mSignature.size()-1; i++) {
249 | if (numTrains > 0)
250 | centroidCoords[i] = centroidCoords[i]/numTrains;
251 | // otherwise keep them to zero
252 | }
253 |
254 | mCentroids.put(classValue, centroidCoords);
255 | }
256 |
257 | }
258 |
259 | @Override
260 | public Value classify(Instance instance) throws MLException {
261 |
262 | if (!mSignature.checkCompliance(instance, false)){
263 | throw new MLException(MLException.INCOMPATIBLE_INSTANCE,
264 | "Instance is not compatible with the dataset used for classifier construction.");
265 | }
266 |
267 | // Calculate the centroid that is the closest
268 | double minDistance = Double.MAX_VALUE;
269 |
270 | // if not yet trained, we return the first label
271 | String minStringValue = ((FeatureNominal)mSignature.getClassFeature()).getValues().get(0);
272 | double centroidCoords[];
273 | double curCoordValues[] = new double[mSignature.size()-1];
274 | for(int i=0; i< mSignature.size()-1; i++) {
275 | curCoordValues[i] = (Double) instance.getValueAtIndex(i).getValue();
276 | }
277 |
278 | for (String classValue : mCentroids.keySet()) {
279 | centroidCoords = mCentroids.get(classValue);
280 | double curDistance = Double.MAX_VALUE;
281 | try {
282 | curDistance = distance(curCoordValues, centroidCoords);
283 | } catch (MLException e) {
284 | // TODO Auto-generated catch block
285 | e.printStackTrace();
286 | }
287 | if (curDistance < minDistance){
288 | minStringValue = classValue;
289 | minDistance = curDistance;
290 | }
291 | }
292 |
293 | return new Value(minStringValue, Value.NOMINAL_VALUE);
294 | }
295 |
296 | public HashMap getCentroids(){
297 | return mCentroids;
298 | }
299 |
300 | @Override
301 | public void printClassifierInfo() {
302 | StringBuilder builder = new StringBuilder();
303 | builder.append("Classifer type: "+ mType +"\n");
304 | builder.append("Signature: "+ mSignature.toString()+"\n");
305 | builder.append("Centroids:\n");
306 | for(String classValue : mCentroids.keySet()) {
307 | double centroidCoords[] = mCentroids.get(classValue);
308 | String coords = "[";
309 | for (int i=0; i
5 | *
6 | *
7 | * This library was developed as part of the EPSRC Ubhave (Ubiquitous and Social
8 | * Computing for Positive Behaviour Change) Project. For more information, please visit
9 | * http://www.ubhave.org
10 | *
11 | * Permission to use, copy, modify, and/or distribute this software for any purpose with
12 | * or without fee is hereby granted, provided that the above copyright notice and this
13 | * permission notice appear in all copies.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 | */
23 |
24 | package si.uni_lj.fri.lrss.machinelearningtoolkit.classifier;
25 |
26 | import java.util.ArrayList;
27 | import java.util.Arrays;
28 | import java.util.HashMap;
29 | import java.util.Iterator;
30 | import java.util.Map.Entry;
31 |
32 | import android.util.Log;
33 |
34 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.ClassifierConfig;
35 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Constants;
36 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Feature;
37 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.FeatureNominal;
38 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Instance;
39 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.MLException;
40 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Signature;
41 | import si.uni_lj.fri.lrss.machinelearningtoolkit.utils.Value;
42 |
43 | // TODO: Nominal attributes are supported for now.
44 | // TODO: How to handle missing attributes?
45 | // TODO: Pruning?
46 |
47 | /**
48 | * ID3, a tree-based classifier according to:
49 | * Quinlan, J. R. 1986. Induction of Decision Trees. Mach. Learn. 1, 1 (Mar. 1986), 81-106
50 | * This implementation supports nominal attributes only.
51 | *
52 | * @author Veljko Pejovic, University of Birmingham, UK
53 | *
54 | */
55 | public class ID3 extends Classifier{
56 |
57 | /*
58 | * Algorithm pseudocode (from Wikipedia):
59 | ID3 (Examples, Target_Attribute, Attributes)
60 | Create a root node for the tree
61 | If all examples are positive, Return the single-node tree Root, with label = +.
62 | If all examples are negative, Return the single-node tree Root, with label = -.
63 | If number of predicting attributes is empty, then Return the single node tree Root,
64 | with label = most common value of the target attribute in the examples.
65 | Otherwise Begin
66 | A <- The Attribute that best classifies examples.
67 | Decision Tree attribute for Root = A.
68 | For each possible value, v_i, of A,
69 | Add a new tree branch below Root, corresponding to the test A = v_i.
70 | Let Examples(v_i) be the subset of examples that have the value v_i for A
71 | If Examples(v_i) is empty
72 | Then below this new branch add a leaf node with label = most common target value in the examples
73 | Else below this new branch add the subtree ID3 (Examples(v_i), Target_Attribute, Attributes – {A})
74 | End
75 | Return Root
76 | */
77 |
78 | private Feature mBestFeature;
79 | private int mBestFeatureIndex;
80 | private int[] mCandidateFeatures;
81 | private Value mMajorValue;
82 | private boolean mIsLeaf;
83 | private HashMap