NumPy oder Pandas: Behalten Sie den Array-Typ als Ganzzahl bei, während Sie einen NaN-Wert haben

160

Gibt es eine bevorzugte Möglichkeit, den Datentyp eines numpyArrays als int( int64oder was auch immer) festzuhalten, während ein Element weiterhin als aufgeführt ist numpy.NaN?

Insbesondere konvertiere ich eine interne Datenstruktur in einen Pandas DataFrame. In unserer Struktur haben wir Spalten vom Typ Integer, die noch NaNs haben (aber der d-Typ der Spalte ist int). Es scheint alles als Float neu zu formulieren, wenn wir dies zu einem DataFrame machen, aber wir würden es wirklich gerne sein int.

Gedanken?

Dinge versucht:

Ich habe versucht, die from_records()Funktion unter pandas.DataFrame mit zu verwenden, coerce_float=Falseund das hat nicht geholfen. Ich habe auch versucht, NumPy-maskierte Arrays mit NaN fill_value zu verwenden, was ebenfalls nicht funktioniert hat. All dies führte dazu, dass der Spaltendatentyp zu einem Float wurde.

ely
quelle
Könnten Sie ein numpy maskiertes Array verwenden?
mgilson
Ich werde es versuchen. Ich habe auch die from_recordsFunktion unter pandas.DataFrame mit ausprobiert, coerce_float=Falseaber kein Glück ... die neuen Daten haben immer noch den Typ float64.
Ely
1
Ja, kein Glück. Selbst mit maskiertem Array wird es immer noch in Float konvertiert. Es sieht so aus, als ob Pandas so aussieht: "Gibt es irgendwo eine NaN? ... Dann ist alles ein Schwimmer." Hoffentlich gibt es einen Weg, dies zu umgehen.
Ely
1
Die optionale Nullable Integer-Unterstützung wurde jetzt offiziell für Pandas 0.24.0 hinzugefügt - endlich :) - eine aktualisierte Antwort finden Sie unten. Pandas 0.24.x Versionshinweise
Mork

Antworten:

70

Diese Funktion wurde Pandas hinzugefügt (beginnend mit Version 0.24): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na-support

Zu diesem Zeitpunkt muss die Erweiterung dtype Int64 (großgeschrieben) anstelle des Standard-dtype int64 (Kleinbuchstaben) verwendet werden.

techvslife
quelle
1
Im Moment müssen Sie einen speziellen dtype angeben 'Int64', damit es funktioniert. Es ist sogar noch besser, wenn es standardmäßig aktiviert ist.
Jean Paul
Das ist toll! Es gibt jedoch ein kleines Problem, dass PyCharm den Datenrahmen nicht im Debug-Fenster anzeigt, wenn es auf diese Weise verwendet wird. Sie können meine Antwort auf eine andere Frage sehen, wie das Anzeigen erzwungen werden kann: stackoverflow.com/questions/38956660/… (das ursprüngliche Problem dort ist anders, aber die Lösung für das Anzeigen des Datenrahmens funktioniert)
Alaa M.
Muss ich verwenden 'Int64'oder gibt es so etwas 'Int8'? Es verbraucht eine verrückte Menge an Speicher im Vergleich zu np.float.
Superdooperhero
'Int8'scheint zu funktionieren, np.floatscheint aber immer noch viel schneller zu laden. Das Problem scheint zu sein, dass dazwischen kein Speicher freigegeben wird. Angenommen, der Garbage Collector wird irgendwann ausgeführt.
Superdooperhero
103

NaNkann nicht in einem Integer-Array gespeichert werden. Dies ist derzeit eine bekannte Einschränkung von Pandas. Ich habe darauf gewartet, dass Fortschritte bei den NA-Werten in NumPy erzielt werden (ähnlich wie bei den NAs in R), aber es wird mindestens 6 Monate bis ein Jahr dauern, bis NumPy diese Funktionen erhält.

http://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na

(Diese Funktion wurde ab Version 0.24 von pandas hinzugefügt. Beachten Sie jedoch, dass die Erweiterung dtype Int64 (großgeschrieben) anstelle des Standard-dtype int64 (Kleinbuchstaben) verwendet werden muss: https://pandas.pydata.org/pandas- docs / version / 0.24 / whatsnew / v0.24.0.html # optional-integer-na-support )

Wes McKinney
quelle
7
Hallo Wes, gibt es ein Update dazu? Wir stoßen auf Probleme, bei denen Verknüpfungsspalten entweder in Ints oder Floats konvertiert werden, basierend auf dem Vorhandensein eines NA-Werts in der ursprünglichen Liste. (Erstellen von Problemen später beim Versuch, diese Datenrahmen zusammenzuführen)
Carst
1
Aktualisierter Link: pandas-docs.github.io/pandas-docs-travis/whatsnew/…
techvslife
8

Wenn die Leistung nicht das Hauptproblem ist, können Sie stattdessen Zeichenfolgen speichern.

df.col = df.col.dropna().apply(lambda x: str(int(x)) )

Dann können Sie dann mit NaNso viel mischen, wie Sie möchten. Wenn Sie wirklich Ganzzahlen haben möchten, können Sie abhängig von Ihrer Anwendung -1oder 0, oder 1234567890oder einen anderen dedizierten Wert zur Darstellung verwenden NaN.

Sie können die Spalten auch vorübergehend duplizieren: eine wie Sie mit Floats; der andere experimentell, mit Ints oder Strings. Fügt dann assertsan jeder vernünftigen Stelle ein, um zu überprüfen, ob die beiden synchron sind. Nach genügend Tests können Sie die Schwimmer loslassen.

osa
quelle
5

Dies ist nicht für alle Fälle eine Lösung, aber für meine (Genomkoordinaten) habe ich 0 als NaN verwendet

a3['MapInfo'] = a3['MapInfo'].fillna(0).astype(int)

Dies ermöglicht zumindest die Verwendung des richtigen "nativen" Spaltentyps. Operationen wie Subtraktion, Vergleich usw. funktionieren wie erwartet

Kugelfisch
quelle
5

Pandas v0.24 +

Funktionen zur Unterstützung NaNin Ganzzahlserien sind ab Version 0.24 verfügbar. Es gibt Informationen zu diesem Thema in den v0.24 Abschnitt „Was ist neu“, und weitere Details unter Nullable Integer - Datentyp .

Pandas v0.23 und früher

Im Allgemeinen ist es am besten, floatwenn möglich mit Serien zu arbeiten , auch wenn die Serie aufgrund der Einbeziehung von Werten von intbis floatnach oben übertragen wird NaN. Dies ermöglicht vektorisierte NumPy-basierte Berechnungen, bei denen andernfalls Python-Schleifen verarbeitet würden.

In den Dokumenten wird Folgendes vorgeschlagen : "Eine Möglichkeit besteht darin, dtype=objectstattdessen Arrays zu verwenden." Beispielsweise:

s = pd.Series([1, 2, 3, np.nan])

print(s.astype(object))

0      1
1      2
2      3
3    NaN
dtype: object

Aus kosmetischen Gründen, z. B. Ausgabe in eine Datei, kann dies sein dies vorzuziehen sein.

Pandas v0.23 und früher: Hintergrund

NaNgilt als afloat . In den aktuellen Dokumenten (ab Version 0.23) wird der Grund angegeben, warum Ganzzahlserien auf Folgendes übertragen werden float:

Da von Grund auf keine leistungsstarke NA-Unterstützung in NumPy integriert ist, besteht das Hauptopfer in der Fähigkeit, NAs in ganzzahligen Arrays darzustellen.

Dieser Kompromiss wird größtenteils aus Speicher- und Leistungsgründen getroffen, und auch, damit die resultierende Serie weiterhin "numerisch" ist.

Die Dokumente enthalten auch Regeln für das Upcasting aufgrund der NaNAufnahme:

Typeclass   Promotion dtype for storing NAs
floating    no change
object      no change
integer     cast to float64
boolean     cast to object
jpp
quelle
1

Dies ist jetzt möglich, da pandas v 0.24.0

Versionshinweise zu pandas 0.24.x Zitat: " Pandas hat die Fähigkeit erlangt, ganzzahlige d-Typen mit fehlenden Werten zu halten.

mork
quelle
1

Ich wollte nur hinzufügen, dass für den Fall, dass Sie versuchen, einen float (1.143) -Vektor in eine Ganzzahl (1) zu konvertieren, bei der NA in den neuen 'Int64'-D-Typ konvertiert wird, eine Fehlermeldung angezeigt wird. Um dies zu lösen, müssen Sie die Zahlen runden und dann ".astype ('Int64')" ausführen.

s1 = pd.Series([1.434, 2.343, np.nan])
#without round() the next line returns an error 
s1.astype('Int64')
#cannot safely cast non-equivalent float64 to int64
##with round() it works
s1.round().astype('Int64')
0      1
1      2
2    NaN
dtype: Int64

Mein Anwendungsfall ist, dass ich eine Float-Reihe habe, die ich auf int runden möchte, aber wenn Sie .round () tun, bleibt ein '* .0' am Ende der Zahl übrig, sodass Sie diese 0 vom Ende bis zum Ende löschen können Konvertierung in int.

Pedro Moisés Camacho Ureña
quelle
0

Wenn die Textdaten Leerzeichen enthalten, werden Spalten, die normalerweise Ganzzahlen sind, als float64-Typ in Floats umgewandelt, da der int64-Typ keine Nullen verarbeiten kann. Dies kann zu inkonsistenten Schemata führen, wenn Sie mehrere Dateien laden, von denen einige Leerzeichen enthalten (die als float64 und andere als int64 enden)

Dieser Code versucht, alle Spalten vom Typ Nummer in Int64 (im Gegensatz zu int64) zu konvertieren, da Int64 Nullen verarbeiten kann

import pandas as pd
import numpy as np

#show datatypes before transformation
mydf.dtypes

for c in mydf.select_dtypes(np.number).columns:
    try:
        mydf[c] = mydf[c].astype('Int64')
        print('casted {} as Int64'.format(c))
    except:
        print('could not cast {} to Int64'.format(c))

#show datatypes after transformation
mydf.dtypes
Kynrek
quelle