So ersetzen Sie negative Zahlen im Pandas-Datenrahmen durch Null


Antworten:


99

Wenn alle Ihre Spalten numerisch sind, können Sie die boolesche Indizierung verwenden:

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

Für den allgemeineren Fall zeigt diese Antwort die private Methode _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

Mit timedeltatype scheint die boolesche Indizierung für separate Spalten zu funktionieren, jedoch nicht für den gesamten Datenrahmen. So können Sie tun:

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

Update: Vergleich mit einem pd.Timedeltafunktioniert auf dem gesamten 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

65

Eine andere prägnante Methode hierfür ist pandas.DataFrame.clip .

Zum Beispiel:

import pandas as pd

In [20]: df = pd.DataFrame({'a': [-1, 100, -2]})

In [21]: df
Out[21]: 
     a
0   -1
1  100
2   -2

In [22]: df.clip(lower=0)
Out[22]: 
     a
0    0
1  100
2    0

Es gibt auch df.clip_lower(0).


1
Dies ist die Inline-Lösung, nach der ich gesucht habe! Vielen Dank!
DomingoR

6
Wenn Sie sich nur für clipeine bestimmte Spalte bewerben möchten, können Sie wie df['col_name'] = df['col_name'].clip(lower=0)
folgt vorgehen

clip_lowerwurde veraltet, also bleib lieber beidf.clip(lower=0)
Sally Levesque

12

Vielleicht könnten Sie pandas.where(args)so verwenden:

data_frame = data_frame.where(data_frame < 0, 0)

6

Eine andere saubere Option, die ich als nützlich empfunden habe, ist pandas.DataFrame.mask, die "Werte ersetzt, bei denen die Bedingung erfüllt ist".

Erstellen Sie den DataFrame:

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

Ersetzen Sie negative Zahlen durch 0:

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

Oder ersetzen Sie negative Zahlen durch NaN, die ich häufig benötige:

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

2

Wenn Sie mit einem großen df (40 mx 700 in meinem Fall) arbeiten, funktioniert es viel schneller und speicherfreundlicher durch Iteration von Spalten mit so etwas wie.

for col in df.columns:
    df[col][df[col] < 0] = 0

Sie erhalten einen A-Wert versucht, auf eine Kopie eines Slice aus einer DataFrame- Warnung gesetzt zu werden, wenn Sie dies tun
alex_lewis
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.