NumPy lub Pandas: Zachowywanie typu tablicy jako liczby całkowitej z wartością NaN


160

Czy istnieje preferowany sposób, aby zachować typ danych numpytablicy ustalony jako int( int64lub cokolwiek), jednocześnie mając wewnątrz element wymieniony jako numpy.NaN?

W szczególności konwertuję wewnętrzną strukturę danych na Pandas DataFrame. W naszej strukturze mamy kolumny typu całkowitego, które nadal mają NaN (ale dtype kolumny to int). Wygląda na to, że jeśli zrobimy z tego DataFrame, wszystko przekształci się w float, ale naprawdę chcielibyśmy, aby tak było int.

Myśli?

Próbowano:

Próbowałem użyć from_records()funkcji pod pandas.DataFrame z coerce_float=Falsei to nie pomogło. Próbowałem też użyć tablic maskowanych NumPy z NaN fill_value, co również nie działało. Wszystko to spowodowało, że typ danych kolumny stał się zmiennoprzecinkowy.


Czy mógłbyś użyć numpy zamaskowanej tablicy?
mgilson

Dam temu szansę. Wypróbowałem również from_recordsfunkcję pod pandas.DataFrame, coerce_float=Falseale bez powodzenia ... nadal sprawia, że ​​nowe dane mają typ float64.
ely

1
Tak, bez szczęścia. Nawet z zamaskowaną tablicą nadal konwertuje się na float. Wygląda na to, że Pandy mówi tak: „Czy jest gdzieś NaN? ... Więc wszystko jest pływające”. Miejmy nadzieję, że jest na to sposób.
ely

1
Opcjonalna obsługa Nullable Integer jest teraz oficjalnie dodana na pandach 0.24.0 - w końcu :) - proszę znaleźć zaktualizowaną odpowiedź poniżej. pandy 0.24.x
mork

Odpowiedzi:


70

Ta możliwość została dodana do pand (począwszy od wersji 0.24): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na-support

W tym momencie wymaga użycia rozszerzenia dtype Int64 (pisane wielką literą) zamiast domyślnego dtype int64 (małe litery).


1
Na razie musisz określić specjalny typ, taki jak, 'Int64'aby działał. Będzie jeszcze lepiej, gdy będzie domyślnie włączony.
Jean Paul

To jest świetne! Jest jednak mały problem, że PyCharm nie wyświetla ramki danych w oknie debugowania, jeśli jest używany w ten sposób. Możesz zobaczyć moją odpowiedź na inne pytanie, jak wymusić jej wyświetlenie: stackoverflow.com/questions/38956660/… (oryginalny problem jest inny, ale rozwiązanie do wyświetlania ramki danych działa)
Alaa M.

Czy muszę używać, 'Int64'czy jest coś takiego 'Int8'? Zużywa szaloną ilość pamięci w porównaniu do np.float.
Superdooperhero

'Int8'wydaje się działać, ale np.floatnadal wydaje się ładować znacznie szybciej. Wydaje się, że problem polega na tym, że nie zwalnia pamięci pomiędzy. Załóżmy, że odśmiecacz w końcu się uruchomi.
Superdooperhero

103

NaNnie można przechowywać w tablicy liczb całkowitych. Jest to obecnie znane ograniczenie pand; Czekałem na postęp z wartościami NA w NumPy (podobnie jak NA w R), ale minie co najmniej 6 miesięcy do roku, zanim NumPy uzyska te funkcje, wydaje się:

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

(Ta funkcja została dodana począwszy od wersji 0.24 pand, ale pamiętaj, że wymaga użycia rozszerzenia dtype Int64 (pisane wielkimi literami), zamiast domyślnego dtype int64 (małe litery): https://pandas.pydata.org/pandas- docs / version / 0.24 / whatsnew / v0.24.0.html # optional-integer-na-support )


7
Cześć Wes, czy jest jakaś aktualizacja w tej sprawie? Występują problemy polegające na tym, że kolumny sprzężone są konwertowane na wartości typu int lub float, w oparciu o istnienie wartości NA na oryginalnej liście. (Tworzenie problemów później podczas próby scalenia tych ramek danych)
Carst,


8

Jeśli wydajność nie jest głównym problemem, możesz zamiast tego przechowywać ciągi.

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

Następnie możesz mieszać NaNtyle, ile chcesz. Jeśli naprawdę chcesz mieć liczby całkowite, w zależności od aplikacji, możesz użyć -1, lub 0, lub 1234567890, lub innej dedykowanej wartości do reprezentacji NaN.

Możesz także tymczasowo zduplikować kolumny: jedną taką, jaką masz, z pływakami; druga eksperymentalna, z intami lub stringami. Następnie wstawia assertsw każdym rozsądnym miejscu, sprawdzając, czy oba są zsynchronizowane. Po wystarczających testach możesz puścić pływaki.


5

To nie jest rozwiązanie dla wszystkich przypadków, ale moje (współrzędne genomowe) uciekłem się do użycia 0 jako NaN

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

Pozwala to przynajmniej na użycie właściwego „natywnego” typu kolumny, operacje takie jak odejmowanie, porównywanie itp. Działają zgodnie z oczekiwaniami


5

Pandy v0.24 +

Funkcjonalność do obsługi NaNserii liczb całkowitych będzie dostępna od wersji 0.24 wzwyż. Nie ma informacji na ten temat w v0.24 „Co nowego” sekcji, a więcej szczegółów pod pustych Integer typ danych .

Pandas v0.23 i starsze

Ogólnie rzecz biorąc, najlepiej jest pracować z floatseriami, jeśli to możliwe, nawet jeśli seria jest nadawana od intdo z floatpowodu uwzględnienia NaNwartości. Umożliwia to wektoryzację obliczeń opartych na NumPy, w których w przeciwnym razie byłyby przetwarzane pętle na poziomie Pythona.

Dokumentacja sugeruje : „Jedną z możliwości jest użycie dtype=objectzamiast tego tablic”. Na przykład:

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

print(s.astype(object))

0      1
1      2
2      3
3    NaN
dtype: object

Ze względów kosmetycznych, np. Wyjście do pliku, może to być preferowane.

Pandy v0.23 i starsze: tło

NaNjest uważany zafloat . Dokumentacja obecnie (od wersji 0.23) określa powód, dla którego serie liczb całkowitych są aktualizowane do float:

W przypadku braku od podstaw wbudowanej w NumPy obsługi NA o wysokiej wydajności, główną ofiarą jest możliwość reprezentowania NA w tablicach całkowitych.

Ten kompromis jest dokonywany głównie ze względu na pamięć i wydajność, a także dlatego, że wynikowa seria nadal jest „numeryczna”.

Dokumenty zawierają również zasady upcastingu z powodu NaNwłączenia:

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


1

Chciałem tylko dodać, że w przypadku, gdy próbujesz przekonwertować wektor typu float (1.143) na liczbę całkowitą (1), która ma konwersję NA do nowego typu `` Int64 '', spowoduje to błąd. Aby rozwiązać ten problem, musisz zaokrąglić liczby, a następnie wykonać „.astype ('Int64')”

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

Mój przypadek użycia jest taki, że mam serię zmiennoprzecinkową, którą chcę zaokrąglić do int, ale kiedy wykonasz .round (), pozostanie '* .0' na końcu liczby, więc możesz upuścić to 0 z końca o konwersja na int.


0

Jeśli w danych tekstowych znajdują się spacje, kolumny, które normalnie byłyby liczbami całkowitymi, zostaną rzutowane na elementy zmiennoprzecinkowe jako float64 dtype, ponieważ int64 dtype nie obsługuje wartości null. Może to spowodować niespójny schemat, jeśli ładujesz wiele plików, niektóre z pustymi wartościami (które kończą się jako float64, a inne bez których kończą się jako int64

Ten kod podejmie próbę konwersji dowolnych kolumn typu liczbowego na Int64 (w przeciwieństwie do int64), ponieważ Int64 może obsługiwać wartości null

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.