Pandas read_csv low_memory i dtype opcje

320

Dzwoniąc

df = pd.read_csv('somefile.csv')

Dostaję:

/Users/josh/anaconda/envs/py27/lib/python2.7/site-packages/pandas/io/parsers.py:1130: DtypeWarning: Kolumny (4,5,7,16) mają różne typy. Podaj opcję dtype podczas importu lub ustaw low_memory = False.

Dlaczego dtypeopcja jest powiązana low_memoryi dlaczego miałaby Falsepomóc w rozwiązaniu tego problemu?

Josh
źródło
2
Mam pytanie dotyczące tego ostrzeżenia. Czy indeks wspomnianych kolumn jest oparty na 0? Na przykład kolumna 4, która ma typ mieszany, to df [:, 4] lub df [:, 3]
maziar
@maziar podczas czytania pliku csv, domyślnie tworzony jest nowy indeks oparty na 0 i używany.
firelynx

Odpowiedzi:

431

Przestarzała opcja low_memory

low_memoryOpcja nie jest prawidłowo przestarzałe, ale powinno być, ponieważ w rzeczywistości nie robić nic inaczej [ źródło ]

Powodem, dla którego low_memorypojawia się to ostrzeżenie, jest to, że zgadywanie typów dla każdej kolumny jest bardzo wymagające pod względem pamięci. Pandas próbuje ustalić, który typ należy ustawić, analizując dane w każdej kolumnie.

Dtype Guessing (bardzo źle)

Pandy mogą określić, jaki typ powinien mieć kolumna po odczytaniu całego pliku. Oznacza to, że tak naprawdę nic nie można przeanalizować przed odczytaniem całego pliku, chyba że ryzykujesz koniecznością zmiany typu tej kolumny podczas czytania ostatniej wartości.

Rozważ przykład jednego pliku, który ma kolumnę o nazwie user_id. Zawiera 10 milionów wierszy, w których identyfikator_użytkownika to zawsze liczby. Ponieważ pandy nie mogą wiedzieć, że to tylko liczby, prawdopodobnie zachowa je jako oryginalne ciągi znaków, dopóki nie przeczyta całego pliku.

Określanie typów (zawsze należy to zrobić)

dodawanie

dtype={'user_id': int}

do pd.read_csv()połączenia uczyni pandy wiedzieć kiedy zaczyna odczytu pliku, że jest to tylko liczby całkowite.

Warto również zauważyć, że jeśli ostatni wiersz w pliku zostałby "foobar"zapisany w user_idkolumnie, ładowanie zawiesiłoby się, gdyby podano powyższy typ kodu.

Przykład uszkodzonych danych, które psują się, gdy zdefiniowane są dtypy

import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO


csvdata = """user_id,username
1,Alice
3,Bob
foobar,Caesar"""
sio = StringIO(csvdata)
pd.read_csv(sio, dtype={"user_id": int, "username": "string"})

ValueError: invalid literal for long() with base 10: 'foobar'

dtypy są zwykle dziwaczne, przeczytaj o nich więcej tutaj: http://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html

Jakie istnieją typy?

Mamy dostęp do typów numpy: float, int, bool, timedelta64 [ns] i datetime64 [ns]. Zauważ, że typy liczbowe data / czas nie są zależne od strefy czasowej.

Pandy rozszerzają ten zestaw typów o własne:

„datetime64 [ns,]” Który jest znacznikiem czasu uwzględniającym strefę czasową.

„kategoria”, która jest zasadniczo wyliczeniem (ciągi znaków reprezentowane przez klucze całkowite do zapisania

„okres []” Nie należy mylić ich z timedelta, obiekty te są faktycznie zakotwiczone w określonych przedziałach czasowych

„Sparse”, „Sparse [int]”, „Sparse [float]” jest przeznaczony do rzadkich danych lub „danych z dużą ilością dziur” Zamiast zapisywać NaN lub None w ramce danych pomija obiekty, oszczędzając miejsce .

„Interwał” jest odrębnym tematem, ale jego głównym zastosowaniem jest indeksowanie. Zobacz więcej tutaj

„Int8”, „Int16”, „Int32”, „Int64”, „UInt8”, „UInt16”, „UInt32”, „UInt64” to liczby całkowite specyficzne dla pand, które można zerować, w przeciwieństwie do wariantu numpy.

„ciąg” jest specyficznym typem do pracy z danymi ciąg i zapewnia dostęp do .stratrybutu w serii.

„boolean” jest jak numpy „bool”, ale obsługuje także brakujące dane.

Przeczytaj pełne odniesienie tutaj:

Odwołanie do typu pandy

Gotchas, zastrzeżenia, notatki

Ustawienie dtype=objectwyciszy powyższe ostrzeżenie, ale nie sprawi, że będzie bardziej wydajna pamięć, tylko wydajne przetwarzanie.

Ustawienie dtype=unicodenic nie zrobi, ponieważ dla numpy, a unicodejest reprezentowane jako object.

Wykorzystanie konwerterów

@sparrow poprawnie wskazuje użycie konwerterów, aby uniknąć wysadzenia pand podczas spotkania 'foobar'w kolumnie określonej jako int. Chciałbym dodać, że konwertery są naprawdę ciężkie i nieefektywne w użyciu w pandach i powinny być używane w ostateczności. Wynika to z faktu, że proces read_csv jest procesem pojedynczym.

Pliki CSV mogą być przetwarzane wiersz po wierszu, a tym samym mogą być przetwarzane przez wiele konwerterów równolegle bardziej wydajnie, po prostu dzieląc plik na segmenty i uruchamiając wiele procesów, czego nie obsługuje panda. Ale to inna historia.

firelynx
źródło
6
A zatem, biorąc pod uwagę, że ustawienie a dtype=objectnie jest bardziej wydajne pod względem pamięci, czy jest jakiś powód, aby z nim zadzierać, oprócz pozbycia się błędu?
zthomas.nc
6
@ zthomas.nc tak, Pandas nie musi zawracać sobie głowy testowaniem tego, co znajduje się w kolumnie. Teoretycznie oszczędzając trochę pamięci podczas ładowania (ale żadna po zakończeniu ładowania) i teoretycznie oszczędzając niektóre cykle procesora (czego nie zauważysz, ponieważ I / O dysku będzie wąskim gardłem.
firelynx
5
„Warto również zauważyć, że jeśli ostatni wiersz w pliku miałby„ foobar ”zapisany w kolumnie user_id, ładowanie zawiesiłoby się, gdyby podano powyższy typ.” czy jest jakaś opcja „przymusu”, której można by użyć do wyrzucenia tego wiersza zamiast awarii?
wróbel
5
@sparrow może być, ale ostatnim razem go użyłem, miał błędy. Można to naprawić w najnowszej wersji pand. error_bad_lines=False, warn_bad_lines=Truepowinien załatwić sprawę. Dokumentacja mówi, że jest ważna tylko z parserem C. Mówi także, że domyślnym parserem jest Brak, co utrudnia ustalenie, który z nich jest domyślny.
firelynx,
5
@nealmcb Możesz odczytać ramkę danych nrows=100jako argument, a następnie zrobić, df.dtypesaby zobaczyć otrzymane typy. Jednak podczas odczytywania całej ramki danych z tymi typami, pamiętaj, aby zrobić to, try/exceptaby złapać błędne domysły typu. Wiesz, że dane są brudne.
firelynx,
50

Próbować:

dashboard_df = pd.read_csv(p_file, sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

Zgodnie z dokumentacją pand:

dtype: wpisz nazwę lub dyktowanie kolumny -> wpisz

Jeśli chodzi o low_memory, jest to domyślnie Prawda i nie jest jeszcze udokumentowane. Nie sądzę jednak, żeby było to istotne. Komunikat o błędzie jest ogólny, więc i tak nie powinieneś zadzierać z low_memory. Mam nadzieję, że to pomoże i daj mi znać, jeśli masz dalsze problemy

hd1
źródło
1
Dodawanie dtype=unicodewyprodukowane: NameError: name 'unicode' is not defined. Ale wstawianie unicodecudzysłowów (jak w „Unicode”) wydaje się działać!
poniedziałek
5
@sedeh Możesz określić dtypy jako typy python lub jako numpy.dtype('unicode'). Gdy podasz ciągowi dtype ciąg, numpy.dtype()domyślnie spróbuje on rzucić go przez fabrykę. Określenie 'unicode'nic nie da, nic nie znaczą objects. Dostanieszdtype='object'
firelynx
43
df = pd.read_csv('somefile.csv', low_memory=False)

To powinno rozwiązać problem. Otrzymałem dokładnie ten sam błąd, gdy czytam 1,8 mln wierszy z pliku CSV.

Neal
źródło
51
To wycisza błąd, ale tak naprawdę nie zmienia niczego innego.
firelynx
2
Mam ten sam problem podczas uruchamiania pliku danych 1,5 GB
Sitz Blogz,
18

Jak wspomniano wcześniej przez firelynx, jeśli wyraźnie określono typ dtype i istnieją mieszane dane, które nie są zgodne z tym typem, ładowanie się zawiesi. Użyłem takiego konwertera jako obejścia, aby zmienić wartości z niezgodnym typem danych, aby dane mogły być nadal ładowane.

def conv(val):
    if not val:
        return 0    
    try:
        return np.float64(val)
    except:        
        return np.float64(0)

df = pd.read_csv(csv_file,converters={'COL_A':conv,'COL_B':conv})
wróbel
źródło
2

Miałem podobny problem z plikiem ~ 400 MB. Ustawienie low_memory=Falsezałatwiło sprawę dla mnie. Najpierw wykonaj proste czynności: sprawdzę, czy twoja ramka danych nie jest większa niż pamięć systemowa, uruchom ponownie, wyczyść pamięć RAM przed kontynuowaniem. Jeśli nadal występują błędy, warto upewnić się, że .csvplik jest w porządku, rzuć okiem na program Excel i upewnij się, że nie ma widocznego uszkodzenia. Zepsute oryginalne dane mogą siać spustoszenie ...

Dr Nigel
źródło
1

Miałem podobny problem podczas przetwarzania ogromnego pliku csv (6 milionów wierszy). Miałem trzy problemy: 1. plik zawierał dziwne znaki (naprawione za pomocą kodowania) 2. typ danych nie został określony (naprawiony za pomocą właściwości dtype) 3. Korzystając z powyższego nadal napotykałem problem związany z formatem pliku, który nie mógł być zdefiniowane na podstawie nazwy pliku (naprawione przy pomocy try .. oprócz ...)

df = pd.read_csv(csv_file,sep=';', encoding = 'ISO-8859-1',
                 names=['permission','owner_name','group_name','size','ctime','mtime','atime','filename','full_filename'],
                 dtype={'permission':str,'owner_name':str,'group_name':str,'size':str,'ctime':object,'mtime':object,'atime':object,'filename':str,'full_filename':str,'first_date':object,'last_date':object})

try:
    df['file_format'] = [Path(f).suffix[1:] for f in df.filename.tolist()]
except:
    df['file_format'] = ''
Wim Folkerts
źródło
-1

To działało dla mnie low_memory = Falsepodczas importowania DataFrame. To wszystko, co działało dla mnie:

df = pd.read_csv('export4_16.csv',low_memory=False)
Rajat Saxena
źródło