Строки в DataFrame, но dtype - это объект

96

Почему Pandas сообщает мне, что у меня есть объекты, хотя каждый элемент в выбранном столбце является строкой - даже после явного преобразования.

Это мой 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 является объектом.

Вот пример:

  • массив int64 содержит 4 значения int64.
  • массив объектов содержит 4 указателя на 3 строковых объекта.

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

HYRY
источник
3
Однако обратите внимание на то, что наличие столбцов типа «объект» имеет большое влияние на производительность операций чтения / записи
DataFrame
Могу ли я каким-то образом получить тип данных, возвращенный в виде строки. Я знаю, что всегда могу использовать type (df ["column"]. Iloc [0]), но может случиться так, что это nan
user1953366
7

Принятый ответ хорош. Просто хотел дать ответ со ссылкой на документацию . В документации говорится:

Pandas использует объект dtype для хранения строк.

Как говорится в ведущем комментарии: «Не беспокойтесь об этом, так должно быть». (Хотя принятый ответ отлично объяснил «почему»; строки имеют переменную длину)

Но для строк длина строки не фиксирована.

Красный горошек
источник
Почему мне нужно преобразовать каждый столбец, который я передаю, в scipy или sklearn astype (str), чтобы он его принял? кажется, я должен сначала применить это ко всем столбцам.
Tinkinc
Я не понимаю; @Tinkinc, что произойдет, если вы не конвертируете столбцы в строку? И этот ответ кажется элегантным способом преобразовать все столбцы в,astype(str) хотя я все еще удивляюсь, что преобразование строк необходимо
Red Pea
Я не могу заполнить (0) все объекты в моем фрейме данных остаются (1, nan) вместо (1,0)
Tinkinc
Извините, @Tinkinc, я все еще не понимаю; Я хочу помочь, но ваша проблема кажется более сложной, чем комментарий о переполнении стека. Вы можете задать вопрос или присоединиться ко мне в чате. (только что пригласил вас)
The Red Pea
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
Fuglede
источник
2
Не используйте это ... пока. Как они заявили, The implementation may change without warning.это означает , что новые обновления сломают ваши старые программы.
NoName
1
Ну, все зависит от того, для чего вы собираетесь его использовать. Если вы хотите использовать его в производственной системе, где необходимы постоянные обновления пакетов и где поломка API вызывает неприемлемую нагрузку на обслуживание, тогда обязательно обратите пристальное внимание на слово «экспериментальный», но если вы используете pandas для выполнения исследовательских задач. анализ в сценариях, время жизни которых не увеличивает рабочий день, то эти опасения не должны ничего значить для вас.
fuglede
Начиная с Pandas 1.1, API кажется стабилизированным. Все типы dtypes теперь могут быть преобразованы в StringDtype .
D3f0