├── CSP.py ├── license.txt └── readme.txt /CSP.py: -------------------------------------------------------------------------------- 1 | # Common Spatial Pattern implementation in Python, used to build spatial filters for identifying task-related activity. 2 | import numpy as np 3 | import scipy.linalg as la 4 | 5 | # CSP takes any number of arguments, but each argument must be a collection of trials associated with a task 6 | # That is, for N tasks, N arrays are passed to CSP each with dimensionality (# of trials of task N) x (feature vector) 7 | # Trials may be of any dimension, provided that each trial for each task has the same dimensionality, 8 | # otherwise there can be no spatial filtering since the trials cannot be compared 9 | def CSP(*tasks): 10 | if len(tasks) < 2: 11 | print "Must have at least 2 tasks for filtering." 12 | return (None,) * len(tasks) 13 | else: 14 | filters = () 15 | # CSP algorithm 16 | # For each task x, find the mean variances Rx and not_Rx, which will be used to compute spatial filter SFx 17 | iterator = range(0,len(tasks)) 18 | for x in iterator: 19 | # Find Rx 20 | Rx = covarianceMatrix(tasks[x][0]) 21 | for t in range(1,len(tasks[x])): 22 | Rx += covarianceMatrix(tasks[x][t]) 23 | Rx = Rx / len(tasks[x]) 24 | 25 | # Find not_Rx 26 | count = 0 27 | not_Rx = Rx * 0 28 | for not_x in [element for element in iterator if element != x]: 29 | for t in range(0,len(tasks[not_x])): 30 | not_Rx += covarianceMatrix(tasks[not_x][t]) 31 | count += 1 32 | not_Rx = not_Rx / count 33 | 34 | # Find the spatial filter SFx 35 | SFx = spatialFilter(Rx,not_Rx) 36 | filters += (SFx,) 37 | 38 | # Special case: only two tasks, no need to compute any more mean variances 39 | if len(tasks) == 2: 40 | filters += (spatialFilter(not_Rx,Rx),) 41 | break 42 | return filters 43 | 44 | # covarianceMatrix takes a matrix A and returns the covariance matrix, scaled by the variance 45 | def covarianceMatrix(A): 46 | Ca = np.dot(A,np.transpose(A))/np.trace(np.dot(A,np.transpose(A))) 47 | return Ca 48 | 49 | # spatialFilter returns the spatial filter SFa for mean covariance matrices Ra and Rb 50 | def spatialFilter(Ra,Rb): 51 | R = Ra + Rb 52 | E,U = la.eig(R) 53 | 54 | # CSP requires the eigenvalues E and eigenvector U be sorted in descending order 55 | ord = np.argsort(E) 56 | ord = ord[::-1] # argsort gives ascending order, flip to get descending 57 | E = E[ord] 58 | U = U[:,ord] 59 | 60 | # Find the whitening transformation matrix 61 | P = np.dot(np.sqrt(la.inv(np.diag(E))),np.transpose(U)) 62 | 63 | # The mean covariance matrices may now be transformed 64 | Sa = np.dot(P,np.dot(Ra,np.transpose(P))) 65 | Sb = np.dot(P,np.dot(Rb,np.transpose(P))) 66 | 67 | # Find and sort the generalized eigenvalues and eigenvector 68 | E1,U1 = la.eig(Sa,Sb) 69 | ord1 = np.argsort(E1) 70 | ord1 = ord1[::-1] 71 | E1 = E1[ord1] 72 | U1 = U1[:,ord1] 73 | 74 | # The projection matrix (the spatial filter) may now be obtained 75 | SFa = np.dot(np.transpose(U1),P) 76 | return SFa.astype(np.float32) -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | 4 | Copyright (c) 2014 Seth Polsley 5 | 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Common Spatial Pattern Algorithm for Filter Construction 2 | 3 | CSP is a statistical algorithm for construction of spatial filters. These filters may be used in constructing feature vectors, or other analyses, where it is useful to remove as much noise as possible from a signal. For example, in a system that classifies between two movements, a given reading will include information from the current task-related activity as well as noise from the other, non-task-related activity. The classifier will be able to distinguish between the two classes better if a spatial filter is used to reduce noise from the non-task-related activity. 4 | 5 | This implementation is a written in python. To use, simply call CSP(C1,C2,..,Cn) where Cx has the shape (number of samples x feature vector). That is, each class Cx passed to CSP should be an array where each row is a unique test case/sample. Each sample will then be a feature vector of some given dimension. As with other classifiers, the feature vector does not have a required dimension, but it must be the same across all classes in order for the filters to be constructed. 6 | 7 | For anyone curious to read more about the algorithm, I based the code on the following paper: 8 | 9 | Wang, Yunhua, Patrick Berg, and Michael Scherg. "Common spatial subspace decomposition applied to analysis of brain responses under multiple task conditions: a simulation study." Clinical Neurophysiology 110.4 (1999): 604-614. (available online through Elsevier at https://www.sciencedirect.com/science/article/pii/S138824579800056X) 10 | --------------------------------------------------------------------------------