So ersetzen Sie negative Zahlen im Pandas-Datenrahmen durch Null

74

Ich würde gerne wissen, ob es eine Möglichkeit gibt, alle negativen DataFrame-Zahlen durch Nullen zu ersetzen.

Abwarten
quelle
Ich glaube auch, dass Ihre zweite Zeile lauten solltenum[num < 0] = 0
hlin117

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
Lev Levitsky
quelle
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).

Follyroof
quelle
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)
Alacy
quelle
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
Michael Conlin
quelle
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
MarKo9
quelle
Sie erhalten einen A-Wert versucht, auf eine Kopie eines Slice aus einer DataFrame- Warnung gesetzt zu werden, wenn Sie dies tun
alex_lewis