отбрасывать бесконечные значения из информационных кадров в пандах?

220

Каков самый быстрый / простой способ отбросить значения nan и inf / -inf из DataFrame pandas без сброса mode.use_inf_as_null? Я хотел бы иметь возможность использовать аргументы subsetи , за исключением значений, которые считаются пропущенными, например:howdropnainf

df.dropna(subset=["col1", "col2"], how="all", with_inf=True)

Это возможно? Есть ли способ сказать, dropnaчтобы включить infв его определение отсутствующих значений?


источник

Ответы:

418

Простейшим способом было бы сначала сделать replaceинфу для NaN:

df.replace([np.inf, -np.inf], np.nan)

а затем используйте dropna:

df.replace([np.inf, -np.inf], np.nan).dropna(subset=["col1", "col2"], how="all")

Например:

In [11]: df = pd.DataFrame([1, 2, np.inf, -np.inf])

In [12]: df.replace([np.inf, -np.inf], np.nan)
Out[12]:
    0
0   1
1   2
2 NaN
3 NaN

Тот же метод будет работать для серии.

Энди Хейден
источник
2
Как можно «обменять» infзначения на заранее определенные, intнапример 0, в определенном столбце?
3kstc
4
@ 3kstc использовать .replace(..., 0). Чтобы просто сделать по столбцам, вы обновляете эти столбцы, т. Е.df[cols] = df[cols].replace(..., 0)
Энди Хейден,
3
Может быть, стоит указать, что replaceне работает на месте, поэтому DataFrameвозвращается новое
Марко
37

В контексте контекста это возможно без постоянной настройки use_inf_as_na. Например:

with pd.option_context('mode.use_inf_as_na', True):
    df = df.dropna(subset=['col1', 'col2'], how='all')

Конечно , он может быть установлен , чтобы лечить , infкак на NaNпостоянной основе с

pd.set_option('use_inf_as_na', True)

Для более старых версий замените use_inf_as_naна use_inf_as_null.

Айхан
источник
6
Это самый читаемый ответ и, следовательно, лучший, хотя он нарушает буквально (но не по духу) исходный вопрос.
Иосиф
2
Панды с (по крайней мере) 0.24: use_inf_as_nullустарела и будет удалена в следующей версии. Используйте use_inf_as_naвместо этого. Добавить / обновить ответ?
Хокон Т.
1
Этот вариант лучше рассматривать infкак нули на глобальном уровне настройки, а не на рабочем уровне. Это может потенциально сэкономить время, вначале вменяя значения.
TaoPR
15

Вот еще один метод, использующий .locдля замены inf на nan в серии:

s.loc[(~np.isfinite(s)) & s.notnull()] = np.nan

Итак, в ответ на оригинальный вопрос:

df = pd.DataFrame(np.ones((3, 3)), columns=list('ABC'))

for i in range(3): 
    df.iat[i, i] = np.inf

df
          A         B         C
0       inf  1.000000  1.000000
1  1.000000       inf  1.000000
2  1.000000  1.000000       inf

df.sum()
A    inf
B    inf
C    inf
dtype: float64

df.apply(lambda s: s[np.isfinite(s)].dropna()).sum()
A    2
B    2
C    2
dtype: float64
Александр
источник
11

Используйте (быстро и просто):

df = df[np.isfinite(df).all(1)]

Этот ответ основан на ответе Дугра на другой вопрос. Вот пример кода:

import pandas as pd
import numpy as np
df=pd.DataFrame([1,2,3,np.nan,4,np.inf,5,-np.inf,6])
print('Input:\n',df,sep='')
df = df[np.isfinite(df).all(1)]
print('\nDropped:\n',df,sep='')

Результат:

Input:
    0
0  1.0000
1  2.0000
2  3.0000
3     NaN
4  4.0000
5     inf
6  5.0000
7    -inf
8  6.0000

Dropped:
     0
0  1.0
1  2.0
2  3.0
4  4.0
6  5.0
8  6.0
Маркус Дучке
источник
8

Еще одним решением будет использование isinметода. Используйте его, чтобы определить, является ли каждое значение бесконечным или отсутствующим, а затем объедините allметод, чтобы определить, являются ли все значения в строках бесконечными или отсутствуют.

Наконец, используйте отрицание этого результата, чтобы выбрать строки, которые не имеют всех бесконечных или пропущенных значений через логическое индексирование.

all_inf_or_nan = df.isin([np.inf, -np.inf, np.nan]).all(axis='columns')
df[~all_inf_or_nan]
Тед Петру
источник
7

Вышеупомянутое решение изменит те inf, которые не находятся в целевых столбцах. Чтобы исправить это,

lst = [np.inf, -np.inf]
to_replace = {v: lst for v in ['col1', 'col2']}
df.replace(to_replace, np.nan)
has2k1
источник
3
Python 2.7 и выше поддерживают DICT понимания:{v: lst for v in cols}
Арье Лейб Таурог
4

Вы можете использовать pd.DataFrame.maskс np.isinf. Сначала убедитесь, что все ваши ряды данных имеют тип float. Тогда используйте dropnaс вашей существующей логикой.

print(df)

       col1      col2
0 -0.441406       inf
1 -0.321105      -inf
2 -0.412857  2.223047
3 -0.356610  2.513048

df = df.mask(np.isinf(df))

print(df)

       col1      col2
0 -0.441406       NaN
1 -0.321105       NaN
2 -0.412857  2.223047
3 -0.356610  2.513048
JPP
источник