-
Notifications
You must be signed in to change notification settings - Fork 0
/
classify-unknowns.js
91 lines (74 loc) · 3 KB
/
classify-unknowns.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import bci from "bcijs";
// this will classify the data near zero as unknown and filter it out
(async () => {
// Load training data
let feetTraining = await bci.loadCSV("data/feet-training.csv");
let rightTraining = await bci.loadCSV("data/righthand-training.csv");
// Project it with CSP
let cspParams = bci.cspLearn(feetTraining, rightTraining);
// Compute training data features
let featuresFeetTraining = computeFeatures(cspParams, feetTraining);
let featuresRightTraining = computeFeatures(cspParams, rightTraining);
// Learn an LDA classifier
let ldaParams = bci.ldaLearn(featuresFeetTraining, featuresRightTraining);
// Load testing data
let feetTesting = await bci.loadCSV("data/feet-testing.csv");
let rightTesting = await bci.loadCSV("data/righthand-testing.csv");
// Compute testing data features
let featuresFeetTesting = computeFeatures(cspParams, feetTesting);
let featuresRightTesting = computeFeatures(cspParams, rightTesting);
// Classify testing data
let classify = (feature) => {
let projection = bci.ldaProject(ldaParams, feature);
// Filter out values between -0.5 and 0.5 as unknown classes
if (projection < -0.5) return 0;
if (projection > 0.5) return 1;
return -1;
};
let feetPredictions = featuresFeetTesting
.map(classify)
.filter((value) => value != -1);
let rightPredictions = featuresRightTesting
.map(classify)
.filter((value) => value != -1);
// Evaluate the classifer
let feetActual = new Array(feetPredictions.length).fill(0);
let rightActual = new Array(rightPredictions.length).fill(1);
let predictions = feetPredictions.concat(rightPredictions);
let actual = feetActual.concat(rightActual);
let confusionMatrix = bci.confusionMatrix(predictions, actual);
let bac = bci.balancedAccuracy(confusionMatrix);
let featureCount = featuresFeetTesting.length + featuresRightTesting.length;
let percentUnknowns = (featureCount - predictions.length) / featureCount;
console.log("confusion matrix");
console.log(bci.toTable(confusionMatrix));
console.log("balanced accuracy");
console.log(bac);
console.log("percent unknown");
console.log(percentUnknowns);
})();
const computeFeatures = (cspParams, eeg) => {
let epochSize = 64; // About a fourth of a second per feature
let trialLength = 750; // Each set of 750 samples is from a different trial
let features = bci.windowApply(
eeg,
(trial) => {
// Apply CSP over each 64 sample window with a 50% overlap between windows
return bci.windowApply(
trial,
(epoch) => {
// Project the data with CSP and select the 16 most relevant signals
let cspSignals = bci.cspProject(cspParams, epoch, 16);
// Use the log of the variance of each signal as a feature vector
return bci.features.logvar(cspSignals, "columns");
},
epochSize,
epochSize / 2
);
},
trialLength,
trialLength
);
// Concat the features from each trial
return [].concat(...features);
};