Ich möchte alle Werte in einem Pandas-Datenrahmen finden, die Leerzeichen enthalten (beliebige Anzahl) und diese Werte durch NaNs ersetzen.
Irgendwelche Ideen, wie man das verbessern kann?
Grundsätzlich möchte ich das drehen:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz
2000-01-05 -0.222552 4
2000-01-06 -1.176781 qux
Das sehr gut finden:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz NaN
2000-01-05 -0.222552 NaN 4
2000-01-06 -1.176781 qux NaN
Ich habe es mit dem folgenden Code geschafft, aber der Mensch ist hässlich. Es ist nicht Pythonic und ich bin sicher, es ist auch nicht die effizienteste Verwendung von Pandas. Ich durchlaufe jede Spalte und führe eine boolesche Ersetzung gegen eine Spaltenmaske aus, die durch Anwenden einer Funktion erzeugt wird, die eine Regex-Suche nach jedem Wert durchführt und auf Whitespace übereinstimmt.
for i in df.columns:
df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None
Es könnte etwas optimiert werden, indem nur Felder durchlaufen werden, die leere Zeichenfolgen enthalten könnten:
if df[i].dtype == np.dtype('object')
Aber das ist keine große Verbesserung
Und schließlich setzt dieser Code die Zielzeichenfolgen auf None, was mit den Funktionen von Pandas wie fillna()
funktioniert. Der Vollständigkeit halber wäre es jedoch nett, wenn ich tatsächlich eine NaN
direkt anstelle von None
einfügen könnte.
Ich denke, df.replace()
macht den Job:
df = pd.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'foo', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ' '],
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))
print df.replace(r'\s+', np.nan, regex=True)
Produziert:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz NaN
2000-01-05 -0.222552 NaN 4
2000-01-06 -1.176781 qux NaN
Wenn Temak darauf hinweist, verwenden Sie df.replace(r'^\s+$', np.nan, regex=True)
, falls Ihre gültigen Daten Leerzeichen enthalten.
Wie wäre es mit:
d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)
Die Funktion applymap
wendet eine Funktion auf jede Zelle des Datenrahmens an.
Wenn Sie eine leere Zeichenfolge und Datensätze nur durch Leerzeichen ersetzen möchten, ist das richtige Antwort
df = df.replace(r'^\s*$', np.nan, regex=True)
Die akzeptierte Antwort
df.replace(r'\s+', np.nan, regex=True)
Ersetzt keine leere Zeichenfolge! Sie können sich selbst mit dem etwas aktualisierten Beispiel versuchen:
df = pd.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'fo o', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ''],
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))
Beachten Sie auch, dass 'fo o' nicht durch Nan ersetzt wird, obwohl es ein Leerzeichen enthält . Beachten Sie außerdem, dass ein einfaches:
df.replace(r'', np.NaN)
Funktioniert auch nicht - probieren Sie es aus.
Ich werde das tun:
df = df.apply(lambda x: x.str.strip()).replace('', np.nan)
oder
df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)
Sie können alle Striche entfernen und dann leere Striche durch np.nan
ersetzen.
Einfachste aller Lösungen:
df = df.replace(r'^\s+$', np.nan, regex=True)
Wenn Sie die Daten aus der CSV-Datei exportieren, kann dies so einfach sein:
df = pd.read_csv(file_csv, na_values=' ')
Dadurch wird der Datenrahmen erstellt und leere Werte als Na ersetzt
Dies ist keine elegante Lösung, aber was anscheinend funktioniert, speichert XLSX und importiert es dann zurück. Die anderen Lösungen auf dieser Seite haben für mich nicht funktioniert, unsicher, warum.
data.to_Excel(filepath, index=False)
data = pd.read_Excel(filepath)
sie können dazu auch einen Filter verwenden.
df = PD.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'foo', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ' '])
df[df=='']='nan'
df=df.astype(float)
Für eine sehr schnelle und einfache Lösung, bei der Sie die Gleichheit mit einem einzelnen Wert überprüfen, können Sie die mask
-Methode verwenden.
df.mask(df == ' ')
Diese sind alle nah an der richtigen Antwort, aber ich würde nicht sagen, dass sie das Problem lösen und gleichzeitig für andere, die Ihren Code lesen, am besten lesbar sind. Ich würde sagen, dass die Antwort eine Kombination aus BrenBarns Antwort und tuomasttiks Kommentar unter dieser Antwort ist. Die Antwort von BrenBarn verwendet isspace
builtin, unterstützt jedoch nicht das Entfernen leerer Zeichenfolgen, wie vom OP angefordert, und ich würde dies tendenziell als Standardanwendungsfall für das Ersetzen von Zeichenfolgen durch null angeben.
Ich habe es mit .apply
umgeschrieben, sodass Sie es auf einem pd.Series
oder pd.DataFrame
aufrufen können.
Python 3:
Um leere Zeichenfolgen oder Zeichenfolgen mit Leerzeichen zu ersetzen:
df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)
Um Zeichenketten vollständig durch Leerzeichen zu ersetzen:
df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)
Um dies in Python 2 zu verwenden, müssen Sie str
durch basestring
ersetzen.
Python 2:
Um leere Zeichenfolgen oder Zeichenfolgen mit Leerzeichen zu ersetzen:
df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)
Um Zeichenketten vollständig durch Leerzeichen zu ersetzen:
df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)
print(df.isnull().sum()) # check numbers of null value in each column
modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"
# modifiedDf = fd.dropna() # Remove rows with empty values
print(modifiedDf.isnull().sum()) # check numbers of null value in each column