Как заменить отрицательные числа в Pandas Data Frame на ноль

Я хотел бы знать, есть ли способ заменить все отрицательные числа DataFrame нулями?


person Hangon    schedule 03.01.2015    source источник
comment
Кроме того, я считаю, что ваша вторая строка должна читаться как num[num < 0] = 0   -  person hlin117    schedule 19.02.2015


Ответы (6)


Если все ваши столбцы числовые, вы можете использовать логическое индексирование:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': [0, -1, 2], 'b': [-3, 2, 1]})

In [3]: df
Out[3]: 
   a  b
0  0 -3
1 -1  2
2  2  1

In [4]: df[df < 0] = 0

In [5]: df
Out[5]: 
   a  b
0  0  0
1  0  2
2  2  1

В более общем случае этот ответ показывает закрытый метод _get_numeric_data:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': [0, -1, 2], 'b': [-3, 2, 1],
                           'c': ['foo', 'goo', 'bar']})

In [3]: df
Out[3]: 
   a  b    c
0  0 -3  foo
1 -1  2  goo
2  2  1  bar

In [4]: num = df._get_numeric_data()

In [5]: num[num < 0] = 0

In [6]: df
Out[6]: 
   a  b    c
0  0  0  foo
1  0  2  goo
2  2  1  bar

С типом timedelta логическое индексирование работает для отдельных столбцов, но не для всего фрейма данных. Итак, вы можете сделать:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': pd.to_timedelta([0, -1, 2], 'd'),
   ...:                    'b': pd.to_timedelta([-3, 2, 1], 'd')})

In [3]: df
Out[3]: 
        a       b
0  0 days -3 days
1 -1 days  2 days
2  2 days  1 days

In [4]: for k, v in df.iteritems():
   ...:     v[v < 0] = 0
   ...:     

In [5]: df
Out[5]: 
       a      b
0 0 days 0 days
1 0 days 2 days
2 2 days 1 days

Обновление: сравнение с pd.Timedelta работает для всего DataFrame:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': pd.to_timedelta([0, -1, 2], 'd'),
   ...:                    'b': pd.to_timedelta([-3, 2, 1], 'd')})

In [3]: df[df < pd.Timedelta(0)] = 0

In [4]: df
Out[4]: 
       a      b
0 0 days 0 days
1 0 days 2 days
2 2 days 1 days
person Lev Levitsky    schedule 03.01.2015


Возможно, вы могли бы использовать pandas.where(args) так:

data_frame = data_frame.where(data_frame < 0, 0)
person alacy    schedule 04.01.2015

Еще один чистый вариант, который я нашел полезным, — это pandas.DataFrame.mask, который "заменит значения, где условие истинно".

Создайте кадр данных:

In [2]: import pandas as pd

In [3]: df = pd.DataFrame({'a': [0, -1, 2], 'b': [-3, 2, 1]})

In [4]: df
Out[4]: 
   a  b
0  0 -3
1 -1  2
2  2  1

Замените отрицательные числа на 0:

In [5]: df.mask(df < 0, 0)
Out[5]: 
   a  b
0  0  0
1  0  2
2  2  1

Или замените отрицательные числа на NaN, которые мне часто нужны:

In [7]: df.mask(df < 0)
Out[7]: 
     a    b
0  0.0  NaN
1  NaN  2.0
2  2.0  1.0
person Michael Conlin    schedule 19.10.2019

С лямбда-функцией

df['column'] = df['column'].apply(lambda x : x if x > 0 else 0)
person Wickkiey    schedule 26.12.2020

Если вы имеете дело с большим df (40 м x 700 в моем случае), он работает намного быстрее и экономит память за счет итерации по столбцам с чем-то вроде.

for col in df.columns:
    df[col][df[col] < 0] = 0
person MarKo9    schedule 05.11.2018
comment
Вы получаете предупреждение Значение пытается быть установлено для копии фрагмента из DataFrame, когда вы делаете это - person alex_lewis; 05.07.2019