Рядки в DataFrame, але dtype є об'єктом


96

Чому Пандас каже мені, що у мене є об'єкти, хоча кожен елемент у вибраному стовпці є рядком - навіть після явного перетворення.

Це мій 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)

Їх п’ять dtype object. Я явно перетворюю ці об'єкти в рядки:

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

Потім, df["attr2"]все ще має dtype object, хоча і type(df["attr2"].ix[0]виявляє str, що правильно.

Панда розрізняє int64і float64та object. Яка логіка за цим, коли цього немає dtype str? Чому strпокривається object?


Прийшов сюди, оскільки з’єднання не вдаються через „тип об’єкта”, хоча кожен рядок „є”
Моніка Хеднек,

Відповіді:


145

Об'єкт dtype походить від NumPy, він описує тип елемента в ndarray. Кожен елемент у ndarray повинен мати однаковий розмір у байтах. Для int64 та float64 вони складають 8 байт. Але для рядків довжина рядка не є фіксованою. Отже, замість того, щоб зберігати байти рядків у ndarray безпосередньо, Pandas використовують об’єкт ndarray, який зберігає вказівники на об’єкти, через це dtype цього типу ndarray є object.

Ось приклад:

  • масив int64 містить 4 значення int64.
  • масив об’єктів містить 4 вказівники на 3 об’єкти рядка.

введіть тут опис зображення


3
Однак зауважте, що наявність стовпців типу "об'єкт" має великий вплив на ефективність операцій читання / запису
DataFrame

чи можу я якось повернути тип даних як рядок. Я знаю, що завжди можу використовувати type (df ["стовпець"]. Iloc [0]), але може статися так, що це nan
user1953366

7

Прийнята відповідь хороша. Просто хотів дати відповідь, на яку посилалася документація . У документації сказано:

Pandas використовує об'єкт dtype для зберігання рядків.

Як зазначає головний коментар: "Не турбуйся про це; це має бути так". (Хоча прийнята відповідь зробила чудову роботу, пояснивши "чому"; рядки мають змінну довжину)

Але для рядків довжина рядка не є фіксованою.


Чому мені потрібно перетворити кожен переданий стовпець на scipy або sklearn astype (str), щоб він його прийняв? здається, я мав би змогти застосувати це до всіх стовпців спочатку.
Tinkinc

Я не розумію; @Tinkinc, що відбувається, якщо ви не перетворюєте стовпці в рядок? І ця відповідь здається елегантним способом перетворити всі стовпці на,astype(str) хоча я все ще думаю, що перетворення рядків необхідне
Червоний горошок

Я не можу заповнити (0) всі об'єкти в моєму фреймі даних (1, nan) замість (1,0)
Tinkinc

Вибачте @Tinkinc, я все ще не розумію; Я хочу допомогти, але ваша проблема звучить складніше, ніж коментар Stack Overflow. Подумайте про те, щоб задати питання або приєднатися до мене в чаті. (щойно вас запросив)
Червона

5

Відповідь @ HYRY чудова. Я просто хочу надати трохи більше контексту ..

Масиви зберігаються дані , як безперервний , фіксованого розміру блоків пам'яті. Поєднання цих властивостей разом робить масиви блискавично швидкими для доступу до даних. Наприклад, розглянемо , як ваш комп'ютер може зберігати масив 32-бітових цілих чисел, [3,0,1].

введіть тут опис зображення

Якщо ви попросите ваш комп’ютер отримати 3-й елемент у масиві, він почнеться спочатку, а потім перескочить через 64 ​​біти, щоб дістатися до 3-го елемента. Точне знання, скільки бітів потрібно перестрибнути - це те, що робить масиви швидкими .

Тепер розглянемо послідовність рядків ['hello', 'i', 'am', 'a', 'banana']. Рядки - це об’єкти, які мають різний розмір, тому, якщо ви спробували зберегти їх у суміжних блоках пам’яті, це в кінцевому підсумку виглядає так.

введіть тут опис зображення

Тепер ваш комп’ютер не має швидкого способу доступу до випадково запитуваного елемента. Ключ до подолання цього - використання покажчиків. По суті, зберігайте кожен рядок у якомусь випадковому місці пам'яті та заповнюйте масив адресою пам'яті кожного рядка. (Адреси пам’яті - це просто цілі числа.) Тож тепер все виглядає так

введіть тут опис зображення

Тепер, якщо ви попросите ваш комп’ютер отримати 3-й елемент, як і раніше, він може перестрибнути через 64 ​​біти (припускаючи, що адреси пам’яті 32-бітові цілі числа), а потім зробити ще один додатковий крок для отримання рядка.

Проблема для NumPy полягає в тому, що немає гарантії, що вказівники насправді вказують на рядки. Ось чому він повідомляє dtype як "об'єкт".

Безсоромно підключу мою власну статтю в блозі, де я це спочатку обговорював.


Приємно
написано ..

1

Починаючи з версії 1.0.0 (січень 2020 р.), Pandas представила як експериментальну функцію, що забезпечує першокласну підтримку типів рядків pandas.StringDtype.

У той час як ви все ще будете бачити objectза замовчуванням новий тип можна використовувати, вказавши dtypeз pd.StringDtypeабо просто '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

2
Не використовуйте це .... поки. Як вони заявили, The implementation may change without warning.це означає , що нові оновлення зламають ваші старі програми.
NoName

1
Ну, все залежить від того, для чого ви його будете використовувати. Якщо ви хочете використовувати його у виробничій системі, де необхідне постійне оновлення упаковки і де поломка API спричиняє неприйнятне навантаження на технічне обслуговування, то, звичайно, зверніть пильну увагу на слово "експериментальний", але якщо ви використовуєте панди для проведення пошукових робіт аналізи сценаріїв, тривалість життя яких не збільшує робочий день, тоді ці занепокоєння мало для вас означатимуть.
fuglede

Починаючи з Pandas 1.1, API, здається, стабілізований. Усі dtypes тепер можуть бути перетворені в StringDtype .
D3f0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.