Repository: mne-tools/mne-python

Issue:
Error when processing ICA:  ValueError: Input contains NaN, infinity or a value too large
Hi,
Applying ICA to the following file and getting this error:

  File "C:\Users\bdyet\Anaconda3\envs\pyeeg\lib\site-packages\sklearn\utils\validation.py", line 58, in _assert_all_finite
    " or a value too large for %r." % X.dtype)
ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

The error originates from this line in mne\preprocessing\ica.py:
`data = pca.fit_transform(data.T)`

One of my data channels is all infinities, however, it is not inf before running the ICA function.
Although I'm not sure if you can open this file because it has load errors, see #4396 

[PAI_wd_sub2019_raw.zip](https://github.com/mne-tools/mne-python/files/1157591/PAI_wd_sub2019_raw.zip)

Thanks!



Discussion:
I'm not sure how exactly you got the error, but fitting the ICA should not tamper with the raw data. Can you see if updating the version works here as well? If not, provide a small snippet of code to reproduce the error.
Ok so i found where the error is coming from. There is a channel marked as bad, and that channels data get s "_pre_whiten"'ed until all its values are either + or - infinity.  Removing this channel (via picks) fixes the issue. Given that this channel is marked as bad, and generally mne ignores bad channels, i would consider this a bug (or at least it should be documented).  Furthermore, I think the "picks" attribute of the ICA.fit function should take channel names not channel indexes, this would match other functions in mne.
>
> Ok so i found where the error is coming from. There is a channel marked as
> bad, and that channels data get s "_pre_whiten"'ed until all its values are
> either + or - infinity.
>
can you provide a full gist to replicate? yes bad channel should be
ignored. You should not have to remove a bad channel.

> Furthermore, I think the "picks" attribute of the ICA.fit function should
> take channel names not channel indexes, this would match other functions in
> mne.
>

the semantic of picks is also indices. Otherwise it's called ch_names or
include.

> the semantic of picks is also indices. Otherwise it's called ch_names or
> include.
Oh right, I guess I use picks less than I thought it did.

Ok with some further investigation, ICA.fit() will only try to process bad channels when the "picks" argument is supplied that includes the bad channel. I guess that could be expected behavior given that I have explicitly asked it to pick the bad eeg channel, however, i assumed that once a channel is marked as bad, it will never be processed. 
Maybe a warning could be added to say that you have asked for analysis of a bad channel?

Gist (will file attached above):
```
    import mne
    import matplotlib.pyplot as plt
    eeg = mne.io.read_raw_fif('PAI_wd_sub2019_raw.fif', verbose=True)
    eeg.load_data()
    eeg.info['bads'] = ['C3']
    ica = ICA()
    channels = [chan for chan in eeg.ch_names if chan != 'events']
    chan_idxs = [idx for idx, chan in enumerate(eeg.ch_names) if chan in channels]
    reject = dict(eeg=40e-5)

    #working
    ica = ica.fit(eeg, reject=reject)

    #Failing
    ica = ica.fit(eeg, picks=chan_idxs, reject=reject)
```


use the picks functions such as pick_types. They remove bad channels
automatically.

so for me there is no bug.

Ok will do, Maybe a comment in the documentation under the "picks" argument would be helpful. Something like, "If indexes that represent bad channels are included, they will be analyzed"
Thanks for your help.
Reminding users that `picks` can override bad channel exclusion is good idea IMO.
no objection

PR more than welcome.

thx


Resolving patch:
diff --git a/mne/utils/docs.py b/mne/utils/docs.py
--- a/mne/utils/docs.py
+++ b/mne/utils/docs.py
@@ -429,27 +429,30 @@
 """
 
 # Picks
-docdict['picks_header'] = 'picks : str | list | slice | None'
-docdict['picks_base'] = docdict['picks_header'] + """
-    Channels to include. Slices and lists of integers will be
-    interpreted as channel indices. In lists, channel *type* strings
+picks_header = 'picks : str | list | slice | None'
+picks_intro = ('Channels to include. Slices and lists of integers will be '
+               'interpreted as channel indices.')
+_reminder = ("Note that channels in ``info['bads']`` *will be included* if "
+             "their {}indices are explicitly provided.\n")
+reminder = _reminder.format('names or ')
+reminder_nostr = _reminder.format('')
+noref = f'(excluding reference MEG channels). {reminder}'
+picks_base = f"""{picks_header}
+    {picks_intro} In lists, channel *type* strings
     (e.g., ``['meg', 'eeg']``) will pick channels of those
     types, channel *name* strings (e.g., ``['MEG0111', 'MEG2623']``
     will pick the given channels. Can also be the string values
     "all" to pick all channels, or "data" to pick :term:`data channels`.
-    None (default) will pick """
-docdict['picks_all'] = docdict['picks_base'] + 'all channels.\n'
-docdict['picks_all_data'] = docdict['picks_base'] + 'all data channels.\n'
-docdict['picks_all_data_noref'] = (docdict['picks_all_data'][:-2] +
-                                   '(excluding reference MEG channels).\n')
-docdict['picks_good_data'] = docdict['picks_base'] + 'good data channels.\n'
-docdict['picks_good_data_noref'] = (docdict['picks_good_data'][:-2] +
-                                    '(excluding reference MEG channels).\n')
-docdict['picks_nostr'] = """
-picks : list | slice | None
-    Channels to include. Slices and lists of integers will be
-    interpreted as channel indices. None (default) will pick all channels.
-"""
+    None (default) will pick"""
+docdict['picks_header'] = picks_header  # these get reused as stubs in a
+docdict['picks_base'] = picks_base      # couple places (e.g., BaseEpochs)
+docdict['picks_all'] = f'{picks_base} all channels. {reminder}'
+docdict['picks_all_data'] = f'{picks_base} all data channels. {reminder}'
+docdict['picks_good_data'] = f'{picks_base} good data channels. {reminder}'
+docdict['picks_all_data_noref'] = f'{picks_base} all data channels {noref}'
+docdict['picks_good_data_noref'] = f'{picks_base} good data channels {noref}'
+docdict['picks_nostr'] = f"""picks : list | slice | None
+    {picks_intro} None (default) will pick all channels. {reminder_nostr}"""
 
 # Filtering
 docdict['l_freq'] = """


Test patch: