├── Feature Extraction ├── dataAR.mat ├── dataCSP.mat ├── dataDWT.mat ├── dataPSD.mat ├── dataset_BCIcomp1.mat ├── extractAR.m ├── extractPSD.m ├── app3.m ├── app1.m ├── app2.m ├── app4.m ├── extractDWT.m ├── extractCSP.m └── learnCSP.m ├── Ensemble Learning ├── Bagging │ ├── dataDWT.mat │ ├── app1.m │ ├── bagging_predict.m │ └── bagging_train.m ├── AdaBoost │ ├── dataDWT.mat │ ├── initStump.m │ ├── initAdaBoost.m │ ├── predStump.m │ ├── buildStump.m │ ├── predAdaBoost.m │ ├── buildOneDStump.m │ ├── buildAdaBoost.m │ └── app1.m └── Boosting │ ├── dataDWT.mat │ ├── app1.m │ ├── gradient_boosting_predict.m │ └── gradient_boosting_train.m └── README /Feature Extraction/dataAR.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Feature Extraction/dataAR.mat -------------------------------------------------------------------------------- /Feature Extraction/dataCSP.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Feature Extraction/dataCSP.mat -------------------------------------------------------------------------------- /Feature Extraction/dataDWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Feature Extraction/dataDWT.mat -------------------------------------------------------------------------------- /Feature Extraction/dataPSD.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Feature Extraction/dataPSD.mat -------------------------------------------------------------------------------- /Ensemble Learning/Bagging/dataDWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Ensemble Learning/Bagging/dataDWT.mat -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/dataDWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Ensemble Learning/AdaBoost/dataDWT.mat -------------------------------------------------------------------------------- /Ensemble Learning/Boosting/dataDWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Ensemble Learning/Boosting/dataDWT.mat -------------------------------------------------------------------------------- /Feature Extraction/dataset_BCIcomp1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-bit/EEGClassification/HEAD/Feature Extraction/dataset_BCIcomp1.mat -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/initStump.m: -------------------------------------------------------------------------------- 1 | function stump = initStump(dim) 2 | stump.dim = dim; 3 | stump.error = 1e6; 4 | stump.threshold = []; 5 | stump.less = 1; 6 | stump.more = -1; 7 | end 8 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/initAdaBoost.m: -------------------------------------------------------------------------------- 1 | function abClassifier = initAdaBoost(N) 2 | abClassifier.nWC = 0; 3 | abClassifier.WeakClas = cell(N,1); 4 | abClassifier.Weight = zeros(N,1); 5 | abClassifier.trnErr = zeros(N, 1); 6 | abClassifier.tstErr = zeros(N, 1); 7 | abClassifier.hasTestData = false; 8 | end 9 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/predStump.m: -------------------------------------------------------------------------------- 1 | % Make prediction based on a decision stump 2 | 3 | function label = predStump(X, stump) 4 | N = size(X, 1); 5 | x = X(:, stump.dim); 6 | idx = logical(x >= stump.threshold); % N x 1 7 | label = zeros(N, 1); 8 | label(idx) = stump.more; 9 | label(~idx) = stump.less; 10 | end 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Implementation of EEG signal classification. 2 | 3 | This program has two stages: 4 | 5 | First Stage is feature extraction method using Autoregression (AR), Common Spatial Pattern (CSP), Discrete Wavelet Transform (DWT) and Power Spectral Density (PSD). 6 | 7 | Second stage is classification of extracted features using Bagging, Boosting and AdaBoost methods. 8 | 9 | 10 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/buildStump.m: -------------------------------------------------------------------------------- 1 | function stump = buildStump(X, y, weight) 2 | D = size(X, 2); % Dimension 3 | 4 | if nargin <= 2 5 | weight = ones(size(X,1), 1); 6 | end 7 | 8 | cellDS = cell(D, 1); 9 | Err = zeros(D, 1); 10 | for i = 1:D 11 | cellDS{i} = buildOneDStump(X(:,i), y, i, weight); 12 | Err(i) = cellDS{i}.error; 13 | end 14 | [v, idx] = min(Err); 15 | stump = cellDS{idx}; 16 | end 17 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/predAdaBoost.m: -------------------------------------------------------------------------------- 1 | function [Label, Err] = predAdaBoost(abClassifier, X, Y) 2 | N = size(X, 1); 3 | 4 | if nargin < 3 5 | Y = []; 6 | end 7 | 8 | M = abClassifier.nWC; 9 | LabM = zeros(N, M); 10 | for i = 1:M 11 | LabM(:,i) = abClassifier.Weight(i)*predStump(X, abClassifier.WeakClas{i}); 12 | end 13 | 14 | % 15 | Label = zeros(N, 1); 16 | LabM = sum(LabM, 2); 17 | idx = logical(LabM > 0); 18 | Label(idx) = 1; 19 | Label(~idx) = -1; 20 | 21 | % 22 | if ~isempty(Y) 23 | Err = logical(Label ~= Y); 24 | Err = sum(Err)/N; 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /Feature Extraction/extractAR.m: -------------------------------------------------------------------------------- 1 | function X=extractAR(x_train,AROrder,startS,endS,wStep,wRange) 2 | 3 | FS=128; 4 | 5 | N=size(x_train,3); 6 | sz=floor((endS-(startS+wRange))/wStep)+1; 7 | X=zeros(sz*FS,2); 8 | cn=0; 9 | for i=1:N 10 | 11 | for sig=startS:wStep:endS-wRange 12 | 13 | sW=sig*FS+1; 14 | eW=(sig+wRange)*FS; 15 | 16 | C3Sig=x_train(sW:eW,1,i); 17 | C4Sig=x_train(sW:eW,3,i); 18 | 19 | c3= arburg(C3Sig, AROrder); 20 | c4= arburg(C4Sig, AROrder); 21 | cn=cn+1; 22 | X(cn,1)=sum(c3.^2)/numel(c3); 23 | X(cn,2)=sum(c4.^2)/numel(c4); 24 | 25 | end 26 | end 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /Feature Extraction/extractPSD.m: -------------------------------------------------------------------------------- 1 | function X=extractPSD(x_train,startS,endS,wStep,wRange) 2 | Fs=1; % sampling frequency (seconds) 3 | 4 | FS=128; 5 | 6 | N=size(x_train,3); 7 | sz=floor((endS-(startS+wRange))/wStep)+1; 8 | X=zeros(sz*FS,2); 9 | cn=0; 10 | for i=1:N 11 | 12 | for sig=startS:wStep:endS-wRange 13 | 14 | sW=sig*FS+1; 15 | eW=(sig+wRange)*FS; 16 | 17 | C3Sig=x_train(sW:eW,1,i); 18 | C4Sig=x_train(sW:eW,3,i); 19 | 20 | [pxx3, ~] = pwelch(C3Sig,[],[],[],Fs); 21 | [pxx4, ~] = pwelch(C4Sig,[],[],[],Fs); 22 | 23 | cn=cn+1; 24 | X(cn,1)=sum(pxx3); 25 | X(cn,2)=sum(pxx4); 26 | 27 | end 28 | end 29 | 30 | end 31 | 32 | 33 | -------------------------------------------------------------------------------- /Feature Extraction/app3.m: -------------------------------------------------------------------------------- 1 | % Extract Power Spectrum Density (PSD) Feature 2 | close all; clear; clc; 3 | 4 | load dataset_BCIcomp1.mat 5 | Y=y_train; 6 | 7 | % Range is 0 to 9 sec 8 | startS=0; 9 | endS=9; 10 | wStep=1; 11 | wRange=9; 12 | 13 | X=extractPSD(x_train,startS,endS,wStep,wRange); 14 | T=extractPSD(x_test,startS,endS,wStep,wRange); 15 | save dataPSD.mat X Y T 16 | 17 | 18 | color_L = [0 102 255] ./ 255; 19 | color_R = [255, 0, 102] ./ 255; 20 | 21 | pos = find(Y==1); 22 | plot(X(pos,1),X(pos,2),'x','Color',color_L,'LineWidth',2); 23 | 24 | hold on 25 | pos = find(Y==2); 26 | plot(X(pos,1),X(pos,2),'o','Color',color_R,'LineWidth',2); 27 | 28 | legend('Left Hand','Right Hand') 29 | xlabel('C3','fontweight','bold') 30 | ylabel('C4','fontweight','bold') 31 | 32 | -------------------------------------------------------------------------------- /Feature Extraction/app1.m: -------------------------------------------------------------------------------- 1 | % Extract Discrete Wavelet Transform (DWT) Feature 2 | close all; clear; clc; 3 | 4 | load dataset_BCIcomp1.mat 5 | Y=y_train; 6 | 7 | % Range is 0 to 9 sec 8 | startS=0; 9 | endS=9; 10 | wStep=1; 11 | wRange=9; 12 | 13 | X=extractDWT(x_train,startS,endS,wStep,wRange); 14 | T=extractDWT(x_test,startS,endS,wStep,wRange); 15 | save dataDWT.mat X Y T 16 | 17 | 18 | color_L = [0 102 255] ./ 255; 19 | color_R = [255, 0, 102] ./ 255; 20 | 21 | pos = find(Y==1); 22 | plot(X(pos,1),X(pos,2),'x','Color',color_L,'LineWidth',2); 23 | 24 | hold on 25 | pos = find(Y==2); 26 | plot(X(pos,1),X(pos,2),'o','Color',color_R,'LineWidth',2); 27 | 28 | legend('Left Hand','Right Hand') 29 | xlabel('C3','fontweight','bold') 30 | ylabel('C4','fontweight','bold') 31 | 32 | 33 | -------------------------------------------------------------------------------- /Feature Extraction/app2.m: -------------------------------------------------------------------------------- 1 | % Extract Autoregression (AR) Feature 2 | close all; clear; clc; 3 | 4 | load dataset_BCIcomp1.mat 5 | Y=y_train; 6 | 7 | % Range is 0 to 9 sec 8 | startS=0; 9 | endS=9; 10 | wStep=1; 11 | wRange=9; 12 | 13 | AROrder=5; 14 | X=extractAR(x_train,AROrder,startS,endS,wStep,wRange); 15 | T=extractAR(x_test,AROrder,startS,endS,wStep,wRange); 16 | save dataAR.mat X Y T 17 | 18 | 19 | color_L = [0 102 255] ./ 255; 20 | color_R = [255, 0, 102] ./ 255; 21 | 22 | pos = find(Y==1); 23 | plot(X(pos,1),X(pos,2),'x','Color',color_L,'LineWidth',2); 24 | 25 | hold on 26 | pos = find(Y==2); 27 | plot(X(pos,1),X(pos,2),'o','Color',color_R,'LineWidth',2); 28 | 29 | legend('Left Hand','Right Hand') 30 | xlabel('C3','fontweight','bold') 31 | ylabel('C4','fontweight','bold') 32 | -------------------------------------------------------------------------------- /Feature Extraction/app4.m: -------------------------------------------------------------------------------- 1 | % Extract Common Spatial Pattern (CSP) Feature 2 | close all; clear; clc; 3 | 4 | load dataset_BCIcomp1.mat 5 | 6 | EEGSignals.x=x_train; 7 | EEGSignals.y=y_train; 8 | Y=y_train; 9 | 10 | classLabels = unique(EEGSignals.y); 11 | CSPMatrix = learnCSP(EEGSignals,classLabels); 12 | nbFilterPairs = 1; 13 | 14 | X = extractCSP(EEGSignals, CSPMatrix, nbFilterPairs); 15 | EEGSignals.x=x_test; 16 | T = extractCSP(EEGSignals, CSPMatrix, nbFilterPairs); 17 | 18 | save dataCSP.mat X Y T 19 | 20 | 21 | color_L = [0 102 255] ./ 255; 22 | color_R = [255, 0, 102] ./ 255; 23 | 24 | pos = find(Y==1); 25 | plot(X(pos,1),X(pos,2),'x','Color',color_L,'LineWidth',2); 26 | 27 | hold on 28 | pos = find(Y==2); 29 | plot(X(pos,1),X(pos,2),'o','Color',color_R,'LineWidth',2); 30 | 31 | legend('Left Hand','Right Hand') 32 | xlabel('C3','fontweight','bold') 33 | ylabel('C4','fontweight','bold') 34 | 35 | -------------------------------------------------------------------------------- /Feature Extraction/extractDWT.m: -------------------------------------------------------------------------------- 1 | function X=extractDWT(x_train,startS,endS,wStep,wRange) 2 | % x_train = input signal 3 | % startS = from second 4 | % endS = end second 5 | % wStep = overlapping 6 | % wRange = window size 7 | FS=128; 8 | 9 | N=size(x_train,3); 10 | sz=floor((endS-(startS+wRange))/wStep)+1; 11 | X=zeros(sz*140,2); 12 | cn=0; 13 | for i=1:N 14 | 15 | for sig=startS:wStep:endS-wRange 16 | 17 | sW=sig*FS+1; 18 | eW=(sig+wRange)*FS; 19 | 20 | C3Sig=x_train(sW:eW,1,i); 21 | C4Sig=x_train(sW:eW,3,i); 22 | 23 | waveletFunction = 'db4'; 24 | waveletLevel=3; 25 | [wCoe,L] = wavedec(C3Sig,waveletLevel,waveletFunction); 26 | C3D3 = detcoef(wCoe,L,3); % Mu 27 | 28 | 29 | [wCoe,L] = wavedec(C4Sig,waveletLevel,waveletFunction); 30 | C4D3 = detcoef(wCoe,L,3); % Mu 31 | 32 | cn=cn+1; 33 | % Mean of the absolute values 34 | X(cn,1)=sum(C3D3.^2)/numel(C3D3); 35 | X(cn,2)=sum(C4D3.^2)/numel(C4D3); 36 | end 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/buildOneDStump.m: -------------------------------------------------------------------------------- 1 | function stump = buildOneDStump(x, y, d, w) 2 | [err_1, t_1] = searchThreshold(x, y, w, '>'); % > t_1 -> +1 3 | [err_2, t_2] = searchThreshold(x, y, w, '<'); % < t_2 -> +1 4 | stump = initStump(d); 5 | if err_1 <= err_2 6 | stump.threshold = t_1; 7 | stump.error = err_1; 8 | stump.less = -1; 9 | stump.more = 1; 10 | else 11 | stump.threshold = t_2; 12 | stump.error = err_2; 13 | stump.less = 1; 14 | stump.more = -1; 15 | end 16 | end 17 | 18 | function [error, thresh] = searchThreshold(x, y, w, sign) 19 | N = length(x); 20 | err_n = zeros(N, 1); 21 | y_predict = zeros(N, 1); 22 | for n=1:N 23 | switch sign 24 | case '>' 25 | idx = logical(x >= x(n)); 26 | y_predict(idx) = 1; 27 | y_predict(~idx) = -1; 28 | case '<' 29 | idx = logical(x < x(n)); 30 | y_predict(idx) = 1; 31 | y_predict(~idx) = -1; 32 | end 33 | err_label = logical(y ~= y_predict); 34 | %sum(err_label) 35 | err_n(n) = sum(err_label.*w)/sum(w); 36 | end 37 | [v, idx] = min(err_n); 38 | error = v; 39 | thresh = x(idx); 40 | end 41 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/buildAdaBoost.m: -------------------------------------------------------------------------------- 1 | function abClassifier = buildAdaBoost(trnX, trnY, iter, tstX, tstY) 2 | if nargin < 4 3 | tstX = []; 4 | tstY = []; 5 | end 6 | abClassifier = initAdaBoost(iter); 7 | 8 | N = size(trnX, 1); % Number of training samples 9 | sampleWeight = repmat(1/N, N, 1); 10 | 11 | for i = 1:iter 12 | weakClassifier = buildStump(trnX, trnY, sampleWeight); 13 | abClassifier.WeakClas{i} = weakClassifier; 14 | abClassifier.nWC = i; 15 | % Compute the weight of this classifier 16 | abClassifier.Weight(i) = 0.5*log((1-weakClassifier.error)/weakClassifier.error); 17 | % Update sample weight 18 | label = predStump(trnX, weakClassifier); 19 | tmpSampleWeight = -1*abClassifier.Weight(i)*(trnY.*label); % N x 1 20 | tmpSampleWeight = sampleWeight.*exp(tmpSampleWeight); % N x 1 21 | sampleWeight = tmpSampleWeight./sum(tmpSampleWeight); % Normalized 22 | 23 | % Predict on training data 24 | [ttt, abClassifier.trnErr(i)] = predAdaBoost(abClassifier, trnX, trnY); 25 | % Predict on test data 26 | if ~isempty(tstY) 27 | abClassifier.hasTestData = true; 28 | [ttt, abClassifier.tstErr(i)] = predAdaBoost(abClassifier, tstX, tstY); 29 | end 30 | % fprintf('\tIteration %d, Training error %f\n', i, abClassifier.trnErr(i)); 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /Ensemble Learning/AdaBoost/app1.m: -------------------------------------------------------------------------------- 1 | close all; clear; clc; 2 | 3 | load dataDWT.mat; 4 | %load dataCSP.mat; 5 | %load dataAR.mat; 6 | %load dataPSD.mat; 7 | 8 | Y(Y==2) = -1; 9 | 10 | N=size(X,1); 11 | trnX = X(1:N, :); 12 | trnY = Y(1:N); 13 | 14 | iter = 30; 15 | abClassifier = initAdaBoost(iter); 16 | 17 | N = size(trnX, 1); % Number of training samples 18 | sampleWeight = repmat(1/N, N, 1); 19 | 20 | for t = 1:iter 21 | weakClassifier = buildStump(trnX, trnY, sampleWeight); 22 | 23 | abClassifier.WeakClas{t} = weakClassifier; 24 | abClassifier.nWC = t; 25 | % Compute the weight of this classifier 26 | abClassifier.Weight(t) = 0.5*log((1-weakClassifier.error)/weakClassifier.error); 27 | weakClassifier.error 28 | % Update sample weight 29 | label = predStump(trnX, weakClassifier); 30 | tmpSampleWeight = -1*abClassifier.Weight(t)*(trnY.*label); % N x 1 31 | tmpSampleWeight = sampleWeight.*exp(tmpSampleWeight); % N x 1 32 | 33 | sampleWeight = tmpSampleWeight./sum(tmpSampleWeight); % Normalized 34 | 35 | % Predict on training data 36 | [ttt, abClassifier.trnErr(t)] = predAdaBoost(abClassifier, trnX, trnY); 37 | 38 | fprintf('\tIteration %d, Training error %f\n', t, abClassifier.trnErr(t)); 39 | end 40 | 41 | trnError = abClassifier.trnErr; 42 | plot(1:iter, trnError); 43 | 44 | -------------------------------------------------------------------------------- /Ensemble Learning/Bagging/app1.m: -------------------------------------------------------------------------------- 1 | close all; clear;clc; 2 | 3 | load dataDWT.mat; 4 | %load dataAR.mat; 5 | %load dataCSP.mat; 6 | %load dataPSD.mat; 7 | Y(Y==2) = -1; 8 | 9 | 10 | y=Y; 11 | min_parent = 20; 12 | num_iterations=30; 13 | base_algorithm= 'classification_tree'; 14 | 15 | no_objects = length(y); 16 | fifth = floor(no_objects / 5); 17 | error_train = zeros([num_iterations 1]); 18 | error_test = zeros([num_iterations 1]); 19 | 20 | for fold = 1 : 5 21 | mask_test = zeros([1 no_objects]); 22 | mask_test((fold - 1) * fifth + 1 : fifth * fold) = 1; 23 | mask_test = logical(mask_test); 24 | train_set = X(~mask_test,:); 25 | train_ans = y(~mask_test); 26 | test_set = X(mask_test,:); 27 | test_ans = y(mask_test); 28 | 29 | 30 | model = bagging_train(train_set, train_ans, num_iterations, base_algorithm, ... 31 | 'min_parent', min_parent); 32 | 33 | [~, error_train_loop] = bagging_predict(model, train_set, train_ans); 34 | [~, error_test_loop] = bagging_predict(model, test_set, test_ans); 35 | error_train = error_train + error_train_loop; 36 | error_test = error_test + error_test_loop; 37 | end 38 | error_train = error_train / 5; 39 | error_test = error_test / 5; 40 | 41 | hold on; 42 | xlabel('Number of iterations'); 43 | ylabel('Error'); 44 | title('Bagging '); 45 | plot(1 : num_iterations, error_train, 'linewidth', 2); 46 | 47 | 48 | -------------------------------------------------------------------------------- /Ensemble Learning/Boosting/app1.m: -------------------------------------------------------------------------------- 1 | close all; clear;clc; 2 | 3 | load dataDWT.mat; 4 | %load dataAR.mat; 5 | %load dataCSP.mat; 6 | %load dataPSD.mat; 7 | Y(Y==2) = -1; 8 | 9 | y=Y; 10 | 11 | num_iterations=30; 12 | base_algorithm= 'regression_tree'; 13 | min_parent = floor(size(X, 1) / 5) * 4 - 1; 14 | loss='logistic'; 15 | learning_rate=1; 16 | 17 | no_objects = length(y); 18 | fifth = floor(no_objects / 5); 19 | error_train = zeros([num_iterations 1]); 20 | error_test = zeros([num_iterations 1]); 21 | 22 | for fold = 1 : 5 23 | mask_test = zeros([1 no_objects]); 24 | mask_test((fold - 1) * fifth + 1 : fifth * fold) = 1; 25 | mask_test = logical(mask_test); 26 | train_set = X(~mask_test,:); 27 | train_ans = y(~mask_test); 28 | test_set = X(mask_test,:); 29 | test_ans = y(mask_test); 30 | model = gradient_boosting_train(train_set, train_ans, num_iterations, ... 31 | base_algorithm, loss, 'learning_rate', learning_rate, ... 32 | 'min_parent', min_parent); 33 | [~, error_train_loop] = gradient_boosting_predict(model, train_set, train_ans); 34 | [~, error_test_loop] = gradient_boosting_predict(model, test_set, test_ans); 35 | error_train = error_train + error_train_loop; 36 | error_test = error_test + error_test_loop; 37 | end 38 | error_train = error_train / 5; 39 | error_test = error_test / 5; 40 | 41 | hold on; 42 | xlabel('Number of iterations'); 43 | ylabel('Error'); 44 | title('Gradient boosting - PSD'); 45 | plot(1 : num_iterations, error_train, 'linewidth', 2); 46 | 47 | 48 | -------------------------------------------------------------------------------- /Feature Extraction/extractCSP.m: -------------------------------------------------------------------------------- 1 | function features = extractCSP(EEGSignals, CSPMatrix, nbFilterPairs) 2 | % 3 | %extract features from an EEG data set using the Common Spatial Patterns (CSP) algorithm 4 | % 5 | %Input: 6 | %EEGSignals: the EEGSignals from which extracting the CSP features. These signals 7 | %are a structure such that: 8 | % EEGSignals.x: the EEG signals as a [Ns * Nc * Nt] Matrix where 9 | % Ns: number of EEG samples per trial 10 | % Nc: number of channels (EEG electrodes) 11 | % nT: number of trials 12 | % EEGSignals.y: a [1 * Nt] vector containing the class labels for each trial 13 | % EEGSignals.s: the sampling frequency (in Hz) 14 | %CSPMatrix: the CSP projection matrix, learnt previously (see function learnCSP) 15 | %nbFilterPairs: number of pairs of CSP filters to be used. The number of 16 | % features extracted will be twice the value of this parameter. The 17 | % filters selected are the one corresponding to the lowest and highest 18 | % eigenvalues 19 | % 20 | %Output: 21 | %features: the features extracted from this EEG data set 22 | % as a [Nt * (nbFilterPairs*2 + 1)] matrix, with the class labels as the 23 | % last column 24 | % 25 | %initializations 26 | 27 | nbTrials = size(EEGSignals.x,3); 28 | features = zeros(nbTrials, 2*nbFilterPairs+1); 29 | Filter = CSPMatrix([1:nbFilterPairs (end-nbFilterPairs+1):end],:); 30 | 31 | %extracting the CSP features from each trial 32 | for t=1:nbTrials 33 | %projecting the data onto the CSP filters 34 | projectedTrial = Filter * EEGSignals.x(:,:,t)'; 35 | 36 | %generating the features as the log variance of the projected signals 37 | variances = var(projectedTrial,0,2); 38 | for f=1:length(variances) 39 | features(t,f) = log(1+variances(f)); 40 | end 41 | end -------------------------------------------------------------------------------- /Ensemble Learning/Bagging/bagging_predict.m: -------------------------------------------------------------------------------- 1 | % Practicum, Task #3, 'Compositions of algorithms'. 2 | % 3 | % FUNCTION: 4 | % [prediction, err] = bagging_predict (model, X, y) 5 | % 6 | % DESCRIPTION: 7 | % This function use the composition of algorithms, trained with bagging 8 | % method, for prediction. 9 | % 10 | % INPUT: 11 | % X --- matrix of objects, N x K double matrix, N --- number of objects, 12 | % K --- number of features. 13 | % y --- vector of answers, N x 1 double vector, N --- number of objects. y 14 | % can have only two values --- +1 and -1. 15 | % model --- trained composition. 16 | % 17 | % OUTPUT: 18 | % prediction --- vector of predicted answers, N x 1 double vector. 19 | % error --- the ratio of number of correct answers to number of objects on 20 | % each iteration, num_iterations x 1 vector 21 | % 22 | % AUTHOR: 23 | % Murat Apishev (great-mel@yandex.ru) 24 | % 25 | 26 | function [prediction, err] = bagging_predict (model, X, y) 27 | 28 | num_iterations = length(model.models); 29 | no_objects = length(y); 30 | pred_prediction = zeros([no_objects num_iterations]); 31 | err = zeros([num_iterations 1]); 32 | 33 | if strcmp(model.algorithm, 'svm') 34 | for alg = 1 : num_iterations 35 | pred_prediction(:,alg) = svmpredict(y, X, model.models{alg}); 36 | func = @(i) find_max(pred_prediction(i,:)); 37 | prediction = arrayfun(func, 1 : no_objects)'; 38 | err(alg) = sum(prediction ~= y) / no_objects; 39 | end 40 | elseif strcmp(model.algorithm, 'classification_tree') 41 | for alg = 1 : num_iterations 42 | pred_prediction(:,alg) = predict(model.models{alg}, X); 43 | func = @(i) find_max(pred_prediction(i,:)); 44 | prediction = arrayfun(func, 1 : no_objects)'; 45 | err(alg) = sum(prediction ~= y) / no_objects; 46 | end 47 | else 48 | error('Incorrect type of algorithm!'); 49 | end 50 | end 51 | 52 | function [result] = find_max (vector) 53 | 54 | if sum(vector == -1) > sum(vector == +1) 55 | result = -1; 56 | else 57 | result = +1; 58 | end 59 | end -------------------------------------------------------------------------------- /Ensemble Learning/Boosting/gradient_boosting_predict.m: -------------------------------------------------------------------------------- 1 | % Practicum, Task #3, 'Compositions of algorithms'. 2 | % 3 | % FUNCTION: 4 | % [prediction, err] = gradient_boosting_predict (model, X, y) 5 | % 6 | % DESCRIPTION: 7 | % This function use the composition of algorithms, trained with gradient 8 | % boosting method, for prediction. 9 | % 10 | % INPUT: 11 | % X --- matrix of objects, N x K double matrix, N --- number of objects, 12 | % K --- number of features. 13 | % y --- vector of answers, N x 1 double vector, N --- number of objects. y 14 | % can have only two values --- +1 and -1. 15 | % model --- trained composition. 16 | % 17 | % OUTPUT: 18 | % prediction --- vector of predicted answers, N x 1 double vector. 19 | % error --- the ratio of number of correct answers to number of objects on 20 | % each iteration, num_iterations x 1 vector 21 | % 22 | % AUTHOR: 23 | % Murat Apishev (great-mel@yandex.ru) 24 | % 25 | 26 | function [prediction, err] = gradient_boosting_predict (model, X, y) 27 | 28 | num_iterations = length(model.weights); 29 | no_objects = length(y); 30 | pred_prediction = zeros([no_objects num_iterations]); 31 | 32 | for alg = 1 : num_iterations 33 | value = zeros([no_objects 1]) + model.b_0; 34 | for i = 1 : alg 35 | if strcmp(model.algorithm, 'epsilon_svr') 36 | value = value + svmpredict(y, X, model.models{i}) * model.weights(i); 37 | elseif strcmp(model.algorithm, 'regression_tree') 38 | value = value + predict(model.models{i}, X) * model.weights(i); 39 | end 40 | end 41 | pred_prediction(:,alg) = value; 42 | end 43 | prediction = pred_prediction(:,end); 44 | err = zeros([num_iterations 1]); 45 | if strcmp(model.loss, 'absolute') 46 | temp = (bsxfun(@minus, pred_prediction, y)); 47 | err = abs(sum(temp)) / no_objects; 48 | elseif strcmp(model.loss, 'logistic') 49 | prediction = sign(prediction); 50 | temp = (bsxfun(@eq, sign(pred_prediction), y)); 51 | err = sum(temp == 0) / no_objects; 52 | end 53 | if size(err, 1) == 1 54 | err = err'; 55 | end 56 | end -------------------------------------------------------------------------------- /Feature Extraction/learnCSP.m: -------------------------------------------------------------------------------- 1 | function CSPMatrix = learnCSP(EEGSignals,classLabels) 2 | % 3 | %Input: 4 | %EEGSignals: the training EEG signals, composed of 2 classes. These signals 5 | %are a structure such that: 6 | % EEGSignals.x: the EEG signals as a [Ns * Nc * Nt] Matrix where 7 | % Ns: number of EEG samples per trial 8 | % Nc: number of channels (EEG electrodes) 9 | % nT: number of trials 10 | % EEGSignals.y: a [1 * Nt] vector containing the class labels for each trial 11 | % EEGSignals.s: the sampling frequency (in Hz) 12 | % 13 | %Output: 14 | %CSPMatrix: the learnt CSP filters (a [Nc*Nc] matrix with the filters as rows) 15 | % 16 | %See also: extractCSPFeatures 17 | 18 | %check and initializations 19 | nbChannels = size(EEGSignals.x,2); 20 | nbTrials = size(EEGSignals.x,3); 21 | nbClasses = length(classLabels); 22 | 23 | if nbClasses ~= 2 24 | disp('ERROR! CSP can only be used for two classes'); 25 | return; 26 | end 27 | 28 | covMatrices = cell(nbClasses,1); %the covariance matrices for each class 29 | 30 | %% Computing the normalized covariance matrices for each trial 31 | trialCov = zeros(nbChannels,nbChannels,nbTrials); 32 | for t=1:nbTrials 33 | E = EEGSignals.x(:,:,t)'; %note the transpose 34 | EE = E * E'; 35 | trialCov(:,:,t) = EE ./ trace(EE); 36 | end 37 | clear E; 38 | clear EE; 39 | 40 | %computing the covariance matrix for each class 41 | for c=1:nbClasses 42 | covMatrices{c} = mean(trialCov(:,:,EEGSignals.y == classLabels(c)),3); %EEGSignals.y==classLabels(c) returns the indeces corresponding to the class labels 43 | end 44 | 45 | %the total covariance matrix 46 | covTotal = covMatrices{1} + covMatrices{2}; 47 | 48 | %whitening transform of total covariance matrix 49 | [Ut Dt] = eig(covTotal); %caution: the eigenvalues are initially in increasing order 50 | eigenvalues = diag(Dt); 51 | [eigenvalues egIndex] = sort(eigenvalues, 'descend'); 52 | Ut = Ut(:,egIndex); 53 | P = diag(sqrt(1./eigenvalues)) * Ut'; 54 | 55 | %transforming covariance matrix of first class using P 56 | transformedCov1 = P * covMatrices{1} * P'; 57 | 58 | %EVD of the transformed covariance matrix 59 | [U1 D1] = eig(transformedCov1); 60 | eigenvalues = diag(D1); 61 | [eigenvalues egIndex] = sort(eigenvalues, 'descend'); 62 | U1 = U1(:, egIndex); 63 | CSPMatrix = U1' * P; -------------------------------------------------------------------------------- /Ensemble Learning/Bagging/bagging_train.m: -------------------------------------------------------------------------------- 1 | % Practicum, Task #3, 'Compositions of algorithms'. 2 | % 3 | % FUNCTION: 4 | % [model] = bagging_train (X, y, num_iterations, base_algorithm, ... 5 | % param_name1, param_value1, param_name2, param_value2) 6 | % 7 | % DESCRIPTION: 8 | % This function train the composition of algorithms using bagging method. 9 | % 10 | % INPUT: 11 | % X --- matrix of objects, N x K double matrix, N --- number of objects, 12 | % K --- number of features. 13 | % y --- vector of answers, N x 1 double vector, N --- number of objects. y 14 | % can have only two values --- +1 and -1. 15 | % num_iterations --- the number ob algorithms in composition, scalar. 16 | % base_algorithm --- the base algorithm, string. Can have one of two 17 | % values: 'classification_tree' or 'svm'. 18 | % param_name1 --- parameter of base_algorithm. For 'classification_tree' it 19 | % is a 'min_parent' --- min number of objects in the leaf of 20 | % classification tree. For 'svm' it is 'gamma' parameter. 21 | % param_name2 --- parameter, that exists only for 'svm', it is a 'C' 22 | % parameter. 23 | % param_value1, param_value2 --- values of corresponding parametres, 24 | % scalar. 25 | % OUTPUT: 26 | % model --- trained composition, structure with two fields 27 | % - models --- cell array with trained models 28 | % - algorithm --- string, 'svm' or 'classification_tree' 29 | % 30 | % AUTHOR: 31 | % Murat Apishev (great-mel@yandex.ru) 32 | % 33 | 34 | function [model] = bagging_train (X, y, num_iterations, base_algorithm, ... 35 | param_name1, param_value1, param_name2, param_value2) 36 | 37 | no_objects = size(X, 1); 38 | models = cell([1 num_iterations]); 39 | 40 | if strcmp(base_algorithm, 'svm') 41 | if ~strcmp(param_name1, 'gamma') 42 | temp = param_value1; 43 | param_value1 = param_value2; 44 | param_value2 = temp; 45 | end 46 | 47 | for iter = 1 : num_iterations 48 | indices = randi(no_objects, 1, no_objects); 49 | indices = unique(indices); 50 | models{iter} = svmtrain(y(indices), X(indices,:), ... 51 | [' -g ', num2str(param_value1), ' -c ', num2str(param_value2)]); 52 | end 53 | elseif strcmp(base_algorithm, 'classification_tree') 54 | for iter = 1 : num_iterations 55 | indices = randi(no_objects, 1, no_objects); 56 | indices = unique(indices); 57 | if (param_value1 > length(indices)) 58 | value = length(indices); 59 | else 60 | value = param_value1; 61 | end 62 | models{iter} = ClassificationTree.fit(X(indices,:), y(indices), 'MinParent', value); 63 | end 64 | else 65 | error('Incorrect type of algorithm!'); 66 | end 67 | 68 | model.models = models; 69 | model.algorithm = base_algorithm; 70 | end -------------------------------------------------------------------------------- /Ensemble Learning/Boosting/gradient_boosting_train.m: -------------------------------------------------------------------------------- 1 | % Practicum, Task #3, 'Compositions of algorithms'. 2 | % 3 | % FUNCTION: 4 | % [model] = gradient_boosting_train (X, y, num_iterations, base_algorithm, loss, ... 5 | % param_name1, param_value1, param_name2, param_value2, ... 6 | % param_name3, param_value3, param_name3, param_value3) 7 | % 8 | % DESCRIPTION: 9 | % This function train the composition of algorithms using gradient boosting method. 10 | % 11 | % INPUT: 12 | % X --- matrix of objects, N x K double matrix, N --- number of objects, 13 | % K --- number of features. 14 | % y --- vector of answers, N x 1 double vector, N --- number of objects. y 15 | % can have only two values --- +1 and -1 in case of classification 16 | % and all possible double values in case of regression. 17 | % num_iterations --- the number ob algorithms in composition, scalar. 18 | % base_algorithm --- the base algorithm, string. Can have one of two 19 | % values: 'regression_tree' or 'epsilon_svr'. 20 | % loss --- the loss function, string. Can have one of two values: 21 | % 'logistic' (for classification) or 'absolute' (for regression). 22 | % param_name1 --- learning rate, scalar. 23 | % param_name2 --- parameter of base_algorithm. For 'regression_tree' it 24 | % is a 'min_parent' --- min number of objects in the leaf of 25 | % regression tree. For 'epsilon_svr' it is 'epsilon' parameter. 26 | % param_name3 --- parameter, that exists only for 'epsilon_svr', it is a 27 | % 'gamma' parameter. 28 | % param_name4 --- parameter, that exists only for 'epsilon_svr', it is a 29 | % 'C' parameter. 30 | % param_value1, param_value2, param_value3, param_value4 --- values of 31 | % corresponding parametres, scalar. 32 | % OUTPUT: 33 | % model --- trained composition, structure with three fields 34 | % - b_0 --- the base of composition, scalar 35 | % - weights --- double array of weights, 1 x num_iterations 36 | % - models --- cell array with trained models, 1 x num_iterations 37 | % - algorithm --- string, 'epsilon_svr' or 'regression_tree' 38 | % - loss --- loss parameter (from INPUT). 39 | % 40 | % AUTHOR: 41 | % Murat Apishev (great-mel@yandex.ru) 42 | % 43 | 44 | function [model] = gradient_boosting_train (X, y, num_iterations, base_algorithm, loss, ... 45 | param_name1, param_value1, param_name2, param_value2, ... 46 | param_name3, param_value3, param_name4, param_value4) 47 | 48 | no_objects = size(X, 1); 49 | if ~strcmp(base_algorithm, 'epsilon_svr') && ~strcmp(base_algorithm, 'regression_tree') 50 | error('Incorrect type of algorithm!') 51 | end 52 | 53 | if strcmp(loss, 'logistic') 54 | loss_function = @(a, b) log(1 + exp(-a .* b)); 55 | grad_a_loss_function = @(a, b) -b .* exp(-a .* b) ./ ((1 + exp(-a .* b))); 56 | elseif strcmp(loss, 'absolute') 57 | loss_function = @(a, b) abs(a - b); 58 | grad_a_loss_function = @(a, b) -sign(b - a); 59 | else 60 | error('Incorrect type of loss function!'); 61 | end 62 | 63 | func = @(c) sum(loss_function(y, c)); 64 | b_0 = fminsearch(func, 0); 65 | model.b_0 = b_0; 66 | model.algorithm = base_algorithm; 67 | model.models = cell([1 num_iterations]); 68 | model.loss = loss; 69 | % the length of model is number of finite weights, not number of models! 70 | model.weights = repmat(+Inf, 1, num_iterations); 71 | 72 | z = zeros([no_objects 1]) + b_0; 73 | delta = zeros([no_objects 1]); 74 | 75 | for iter = 1 : num_iterations 76 | for obj = 1 : no_objects 77 | delta(obj) = -grad_a_loss_function(z(obj), y(obj)); 78 | end 79 | 80 | if strcmp(base_algorithm, 'epsilon_svr') 81 | model.models{iter} = svmtrain(delta, X, [' -s 3 -g ', num2str(param_value3), ... 82 | ' -c ', num2str(param_value4), ' -e ', num2str(param_value2)]); 83 | value = svmpredict(y, X, model.models{iter}); 84 | elseif strcmp(base_algorithm, 'regression_tree') 85 | model.models{iter} = RegressionTree.fit(X, delta, 'minparent', param_value2); 86 | value = predict(model.models{iter}, X); 87 | end 88 | 89 | func = @(g) sum(loss_function(z + g * value, y)); 90 | model.weights(iter) = fminsearch(func, 0); 91 | z = z + model.weights(iter) * value * param_value1; 92 | end 93 | end --------------------------------------------------------------------------------