Ciągi w DataFrame, ale dtype jest obiektem

101

Dlaczego Pandy mówią mi, że mam obiekty, chociaż każdy element w wybranej kolumnie jest ciągiem - nawet po jawnej konwersji.

To jest moja ramka DataFrame:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 56992 entries, 0 to 56991
Data columns (total 7 columns):
id            56992  non-null values
attr1         56992  non-null values
attr2         56992  non-null values
attr3         56992  non-null values
attr4         56992  non-null values
attr5         56992  non-null values
attr6         56992  non-null values
dtypes: int64(2), object(5)

Pięć z nich jest dtype object. Jawnie konwertuję te obiekty na ciągi:

for c in df.columns:
    if df[c].dtype == object:
        print "convert ", df[c].name, " to string"
        df[c] = df[c].astype(str)

Następnie df["attr2"]nadal ma dtype object, chociaż type(df["attr2"].ix[0]ujawnia str, co jest poprawne.

Pandy rozróżniają między int64i float64i object. Jaka logika się za tym kryje, kiedy nie ma dtype str? Dlaczego jest strobjęty gwarancją object?

Xiphias
źródło
Pojawił się tutaj, ponieważ łączenia
kończą

Odpowiedzi:

149

Obiekt dtype pochodzi z NumPy, opisuje typ elementu w ndarray. Każdy element w tablicy ndarray musi mieć ten sam rozmiar w bajtach. W przypadku int64 i float64 mają one 8 bajtów. Ale w przypadku sznurków długość sznurka nie jest ustalona. Więc zamiast zapisywać bajty łańcuchów bezpośrednio w ndarray, Pandy używają obiektu ndarray, który zapisuje wskaźniki do obiektów, z tego powodu dtype tego rodzaju ndarray to object.

Oto przykład:

  • tablica int64 zawiera 4 wartości int64.
  • tablica obiektów zawiera 4 wskaźniki do 3 obiektów łańcuchowych.

wprowadź opis obrazu tutaj

HYRY
źródło
4
Należy jednak pamiętać, że kolumny typu „obiekt” mają duży wpływ na wydajność operacji odczytu / zapisu
DataFrame
czy mogę w jakiś sposób zwrócić typ danych jako ciąg. Wiem, że zawsze mogę użyć typu (df ["kolumna"]. Iloc [0]), ale może się tak zdarzyć, że jest to nan
user1953366
9

Odpowiedź @ HYRY'ego jest świetna. Chcę tylko podać trochę więcej kontekstu.

Tablice przechowywać dane jak przyległe , stałej wielkości bloków pamięci. Połączenie tych właściwości razem sprawia, że ​​tablice są błyskawiczne w dostępie do danych. Na przykład, rozważmy, jak komputer może przechowywać tablicę 32-bitowych liczb całkowitych [3,0,1].

wprowadź opis obrazu tutaj

Jeśli poprosisz komputer o pobranie trzeciego elementu tablicy, rozpocznie się on od początku, a następnie przeskoczy przez 64 bity, aby dotrzeć do trzeciego elementu. Wiedza dokładnie, przez ile bitów przeskoczyć, sprawia, że ​​tablice są szybkie .

Teraz rozważ sekwencję ciągów ['hello', 'i', 'am', 'a', 'banana']. Łańcuchy to obiekty o różnej wielkości, więc jeśli spróbujesz zapisać je w ciągłych blokach pamięci, skończy się to tak.

wprowadź opis obrazu tutaj

Teraz twój komputer nie ma szybkiego dostępu do losowo żądanego elementu. Kluczem do przezwyciężenia tego jest użycie wskaźników. Zasadniczo przechowuj każdy ciąg w jakiejś losowej lokalizacji pamięci i wypełnij tablicę adresem pamięci każdego ciągu. (Adresy pamięci to tylko liczby całkowite). Więc teraz wygląda to tak

wprowadź opis obrazu tutaj

Teraz, jeśli poprosisz komputer o pobranie trzeciego elementu, tak jak poprzednio, może przeskoczyć przez 64 bity (zakładając, że adresy pamięci są 32-bitowymi liczbami całkowitymi), a następnie wykonać jeden dodatkowy krok, aby pobrać ciąg.

Wyzwaniem dla NumPy jest to, że nie ma gwarancji, że wskaźniki faktycznie wskazują na ciągi. Dlatego zgłasza typ dtype jako „obiekt”.

Bezwstydnie podłączę własny artykuł na blogu, w którym pierwotnie o tym dyskutowałem.

Ben
źródło
Ładnie written..Thanks
Tedd
7

Przyjęta odpowiedź jest dobra. Chciałem tylko udzielić odpowiedzi, która odnosiła się do dokumentacji . Dokumentacja mówi:

Pandy używa obiektu dtype do przechowywania łańcuchów.

Jak mówi główny komentarz: „Nie martw się o to, tak powinno być”. (Chociaż zaakceptowana odpowiedź świetnie się spisała, wyjaśniając „dlaczego”; ciągi znaków mają zmienną długość)

Ale w przypadku sznurków długość sznurka nie jest ustalona.

Groszek czerwony
źródło
Dlaczego muszę konwertować każdą kolumnę, którą przekazuję, na scipy lub sklearn astype (str), aby ją zaakceptować? wydaje się, że powinienem być w stanie zastosować to na początku do wszystkich kolumn.
Tinkinc
Nie rozumiem; @Tinkinc co się stanie, jeśli nie przekonwertujesz kolumn na ciąg? I ta odpowiedź wydaje elegancki sposób przekonwertować wszystkie kolumnyastype(str) mimo to wciąż konwersja dziwnego ciąg jest konieczne
Red Pea
Nie mogę wypełnić (0) wszystkich obiektów w mojej ramce danych pozostają (1, nan) zamiast (1,0)
Tinkinc
Przepraszam @Tinkinc, nadal nie rozumiem; Chcę pomóc, ale Twój problem wydaje się bardziej złożony niż komentarz przepełnienia stosu. Rozważ zadanie pytania lub dołączenie do czatu. (właśnie cię zaprosiłem)
The Red Pea
2

Począwszy od wersji 1.0.0 (styczeń 2020 r.), Pandy zostały wprowadzone jako funkcja eksperymentalna zapewniająca pierwszorzędną obsługę typów ciągów poprzez pandas.StringDtype.

Choć nadal będziesz widzieć objectdomyślnie nowego typu mogą być wykorzystywane przez podanie dtypeod pd.StringDtypelub po prostu 'string':

>>> pd.Series(['abc', None, 'def'])
0     abc
1    None
2     def
dtype: object
>>> pd.Series(['abc', None, 'def'], dtype=pd.StringDtype())
0     abc
1    <NA>
2     def
dtype: string
>>> pd.Series(['abc', None, 'def']).astype('string')
0     abc
1    <NA>
2     def
dtype: string
zepsuty
źródło
2
Nie używaj tego ... jeszcze. Jak powiedzieli, The implementation may change without warning.co oznacza , że nowe aktualizacje zepsują stare programy.
NoName
1
Cóż, wszystko zależy od tego, do czego go użyjesz. Jeśli chcesz go używać w systemie produkcyjnym, w którym konieczne są ciągłe aktualizacje pakietów i gdzie awaria API powoduje niedopuszczalne obciążenie konserwacją, zwróć szczególną uwagę na słowo „eksperymentalny”, ale jeśli używasz pand do wykonywania eksploracyjnych analiz w skryptach, których czas życia nie wydłuża dnia pracy, wtedy te obawy powinny niewiele dla Ciebie znaczyć.
fuglede
1
Począwszy od wersji Pandas 1.1, API wydaje się być ustabilizowane. Wszystkie typy dtypów można teraz przekonwertować na StringDtype .
D3f0