Artefact Correction with ICA. Illustrated with an example from the... | by Thomas A Dorfer | Towards Data Science

Time-series data is often contaminated with unwanted signal artefacts that have the potential to considerably distort any further analysis. Independent component analysis, or ICA, is a powerful method to get around this very problem. Here, I will give a brief introduction to ICA followed by a demonstration of how to implement it to remove signal artefacts. Throughout this article, I will be using time-series data obtained through electroencephalography (EEG)— a technique from the neurosciences that measures electrical activity of the cerebral cortex of the brain.
Note: I only present crucial code snippets here. The full code, written in Python 3, can be found on my GitHub in form of a Jupyter Notebook.
ICA is a signal processing method capable of separating a multivariate signal into its additive subcomponents, or sources. It is based on the assumptions that the sources are statistically independent and that the values in each source underlie non-Gaussian distributions [1]. A classic example of source separation is the cocktail party problem, where multiple people in a room are talking simultaneously and their voices are recorded by microphones positioned at different spatial locations. ICA can then be applied to separate the mixed source data into various information sources representing maximally temporally independent signals. In other words, the individual voices of each person in the room can be restored with a fairly high degree of accuracy, as illustrated below.
In the context of EEG, ICA can identify components that include artefacts such as eye blinks or eye movements. These components can then be removed before the data is transformed back from source space (individual sources as computed by ICA) to sensor space (original EEG data). An illustration of the placement of these sensors, or electrodes, is shown below.
Eye blinks and eye movements can usually be detected fairly easily by inspecting the time-series data. They are picked up particularly by frontal channels sitting either right above or in close proximity to the eyes. Examples of each are shown below.
The scientific community has been using various ICA algorithms, such as Infomax, JADE, and FastICA [3, 4], with the latter being arguably the most popular one. Additionally, scikit-learn provides the FastICA algorithm in its decomposition module, which further prompted me to use it for this demonstration.
The data used here was acquired from an approximately 8min resting-state EEG session. Before we start, let’s take a look at a slice of the EEG time-series.
The sampling rate here was 500 Hz, so the above figure shows 4 seconds of data. An eye blink can be seen between samples 1250 and 1500. Eye blinks are typically most pronounced in channels Fp1 and Fp2, so let’s plot them individually.
Looking at Fp1, a slight box shape can be detected just before the start of the eye blink. This represents horizontal eye movement and should ideally be removed as well. Now, let’s run scikit-learn’s FastICA and plot all 63 ICA components to see if we can identify the sources of any artefacts.
## Computing ICA componentsfrom sklearn.decomposition import FastICAica = FastICA(n_components=63, random_state=0, tol=0.05)comps = ica.fit_transform(eeg)# eeg --> raw data, shape: (224930, 63)# comps --> ICA components, shape: (224930, 63)
For the sake of simplicity, I have only plotted the components over 400 samples, from 1200 to 1600, hoping to spot that eye blink visible in Fp1 and Fp2. Upon close inspection, it appears as though component 29 contains horizontal eye movements and component 42 contains eye blink artefacts. To confirm this, I had a look at longer slices of data (not shown here) and found that the artefacts in these components in fact co-occur with the eye blink and eye movement artefacts in various frontal channels.
Note: ICA separates signals into their subcomponents based on statistical measures, meaning that there is no specific component order. If you don’t specify random_state, you will find that the components containing the artefacts can vary.
Let’s now remove components 29 and 42 and transform our source data back into the original sensor space, using the inverse transform.
## Set artefact components to zero before inverse transformcomps[:,[29,42]] = 0 restored = ica.inverse_transform(comps)
It worked! The restored signals (Fp1_post and Fp2_post, darker colors) no longer contain the eye blink and eye movement artefacts present in the raw signals (Fp1_pre and Fp2_pre, faint colors).
Cautionary note: ICA has been shown to work really well with stereotyped artefacts such as eye blinks and eye movements. However, non-stereotyped artefacts that produce noise in various spatial locations, i.e. when subjects are scratching their head, defy the workings of ICA and should be treated with caution.
[1] Hyvärinen, A., 2016. Independent component analysis: recent advances. Philos Trans A Math Phys Eng Sci. 371(1984):20110534. [PubMed]
[2] Tharwat, A., 2018. Independent component analysis: An introduction. Appl. Comput. Inform. https://doi.org/10.1016/j.aci.2018.08.006 [PDF]
[3] Hyvärinen, A., 1999. Fast and robust fixed-point algorithms for independent component analysis. IEEE Transactions on Neural Networks. 10(3): 626–634. [PDF]
[4] Hyvärinen, A.; Oja, E., 2000. Independent component analysis: Algorithms and applications. Neural Networks. 13(4–5): 411–430. [PDF]