Cadenas en un DataFrame, pero dtype es un objeto

96

¿Por qué Pandas me dice que tengo objetos, aunque cada elemento de la columna seleccionada es una cadena, incluso después de una conversión explícita?

Este es mi 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)

Cinco de ellos lo son dtype object. Convierto explícitamente esos objetos en cadenas:

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

Entonces, df["attr2"]todavía tiene dtype object, aunque type(df["attr2"].ix[0]revela str, lo que es correcto.

Pandas distingue entre int64y float64y object. ¿Cuál es la lógica detrás de esto cuando no hay dtype str? ¿Por qué está strcubierto por object?

Xiphias
fuente
Vine aquí porque las uniones fallan debido al 'tipo de objeto' a pesar de que cada cadena "es"
Monica Heddneck

Respuestas:

145

El objeto dtype proviene de NumPy, describe el tipo de elemento en un ndarray. Todos los elementos de un ndarray deben tener el mismo tamaño en bytes. Para int64 y float64, son 8 bytes. Pero para las cuerdas, la longitud de la cuerda no es fija. Entonces, en lugar de guardar los bytes de cadenas en el ndarray directamente, Pandas usa object ndarray, que guarda punteros a objetos, debido a esto, el dtype de este tipo ndarray es object.

Aquí hay un ejemplo:

  • la matriz int64 contiene 4 valores int64.
  • la matriz de objetos contiene 4 punteros a 3 objetos de cadena.

ingrese la descripción de la imagen aquí

HYRY
fuente
3
Sin embargo, tenga en cuenta que tener columnas de tipo 'objeto' tiene un impacto importante en el rendimiento de las operaciones de lectura / escritura de
DataFrame
¿Puedo obtener el tipo de datos devuelto como una cadena, de alguna manera? Sé que siempre puedo usar type (df ["column"]. Iloc [0]), pero puede suceder que sea nan
user1953366
7

La respuesta aceptada es buena. Solo quería proporcionar una respuesta que hiciera referencia a la documentación . La documentación dice:

Pandas usa el objeto dtype para almacenar cadenas.

Como dice el comentario principal "No se preocupe, se supone que debe ser así". (Aunque la respuesta aceptada hizo un gran trabajo al explicar el "por qué"; las cadenas son de longitud variable)

Pero para las cuerdas, la longitud de la cuerda no es fija.

El guisante rojo
fuente
¿Por qué necesito convertir cada columna que paso a scipy o sklearn astype (str) para que la acepte? parece que debería poder aplicar eso a todas las columnas inicialmente.
Tinkinc
No entiendo; @Tinkinc, ¿qué sucede si no convierte columnas en cadenas? Y esta respuesta parece una forma elegante de convertir todas las columnas a,astype(str) aunque todavía me pregunto si la conversión de cadenas es necesaria
The Red Pea
No puedo llenar (0) todos los objetos en mi marco de datos permanecen (1, nan) en lugar de (1,0)
Tinkinc
Lo siento @Tinkinc, todavía no entiendo; Quiero ayudar, pero su problema suena más complejo que un comentario de Stack Overflow. Considere hacer una pregunta o unirse a mí en el chat. (te acabo de invitar)
The Red Pea
5

La respuesta de @ HYRY es genial. Solo quiero proporcionar un poco más de contexto ...

Arrays almacenan datos como contiguos , de tamaño fijo bloques de memoria. La combinación de estas propiedades juntas es lo que hace que los arreglos sean increíblemente rápidos para el acceso a los datos. Por ejemplo, considere cómo su equipo puede almacenar una matriz de enteros de 32 bits, [3,0,1].

ingrese la descripción de la imagen aquí

Si le pide a su computadora que busque el tercer elemento en la matriz, comenzará desde el principio y luego saltará a través de 64 bits para llegar al tercer elemento. Saber exactamente cuántos bits atravesar es lo que hace que las matrices sean rápidas .

Ahora considere la secuencia de cadenas ['hello', 'i', 'am', 'a', 'banana']. Las cadenas son objetos que varían en tamaño, por lo que si intentara almacenarlos en bloques de memoria contiguos, terminaría luciendo así.

ingrese la descripción de la imagen aquí

Ahora su computadora no tiene una forma rápida de acceder a un elemento solicitado al azar. La clave para superar esto es utilizar punteros. Básicamente, almacene cada cadena en una ubicación de memoria aleatoria y llene la matriz con la dirección de memoria de cada cadena. (Las direcciones de memoria son solo números enteros). Así que ahora, las cosas se ven así

ingrese la descripción de la imagen aquí

Ahora, si le pide a su computadora que busque el tercer elemento, como antes, puede saltar 64 bits (asumiendo que las direcciones de memoria son enteros de 32 bits) y luego dar un paso adicional para ir a buscar la cadena.

El desafío para NumPy es que no hay garantía de que los punteros apunten realmente a cadenas. Es por eso que informa el dtype como 'objeto'.

Desvergonzadamente voy a conectar mi propio artículo de blog donde originalmente discutí esto.

Ben
fuente
Muy bien
escrito
1

A partir de la versión 1.0.0 (enero de 2020), pandas se introdujo como una característica experimental que brinda soporte de primera clase para los tipos de cadenas pandas.StringDtype.

Si bien seguirá viendo objectde forma predeterminada, el nuevo tipo se puede usar especificando una dtypede pd.StringDtypeo simplemente '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
fuente
2
No uses esto ... todavía. Como dijeron, lo The implementation may change without warning.que significa que las nuevas actualizaciones romperán sus programas antiguos.
NoName
1
Bueno, todo depende de para qué lo vas a usar. Si desea usarlo en un sistema de producción donde son necesarias actualizaciones continuas de paquetes y donde la rotura de la API causa una carga de mantenimiento inaceptable, entonces preste mucha atención a la palabra "experimental", pero si está usando pandas para realizar exploraciones análisis en guiones cuya vida útil no aumenta una jornada laboral, entonces esas preocupaciones deberían significar poco para usted.
fuglede
A partir de Pandas 1.1, la API parece estar estabilizada. Todos los dtypes ahora se pueden convertir a StringDtype .
D3f0