Estoy trabajando con filas individuales de marcos de datos de pandas, pero me encuentro con problemas de coerción al indexar e insertar filas. Parece que Pandas siempre quiere coaccionar de un tipo mixto int / float a todo tipo float, y no puedo ver ningún control obvio sobre este comportamiento.
Por ejemplo, aquí hay un marco de datos simple con a
as int
y b
como float
:
import pandas as pd
pd.__version__ # '0.25.2'
df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
# a b
# 0 1 2.2
print(df.dtypes)
# a int64
# b float64
# dtype: object
Aquí hay un problema de coerción al indexar una fila:
print(df.loc[0])
# a 1.0
# b 2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}
Y aquí hay un problema de coerción al insertar una fila:
df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
# a b
# 0 1.0 2.2
# 1 5.0 4.4
print(df.dtypes)
# a float64
# b float64
# dtype: object
En ambos casos, quiero que la a
columna permanezca como un tipo entero, en lugar de ser forzada a un tipo flotante.
df.loc[[0], df.columns]
.read_[type]
aunque admite varios tipos de dty ...Respuestas:
Después de excavar un poco, aquí hay algunas soluciones terriblemente feas. (Se aceptará una mejor respuesta).
Una peculiaridad que se encuentra aquí es que las columnas no numéricas detienen la coerción, por lo que aquí se explica cómo indexar una fila a
dict
:E insertar una fila se puede hacer creando un nuevo marco de datos con una fila:
Ambos trucos no están optimizados para grandes marcos de datos, por lo que agradecería mucho una mejor respuesta.
fuente
df['a'] = df.a.astype(mytype)
... Sin embargo, todavía está sucio y probablemente no sea eficiente..astype()
es peligroso para flotar -> entero; no tiene ningún problema1.1
para cambiar1
, por lo que realmente debe asegurarse de que todos sus valores sean 'enteros' antes de hacerlo. Probablemente la mejor manera de usarpd.to_numeric
condowncast='integer'
La raíz del problema es que
Podemos ver eso:
Y una serie solo puede tener un tipo de letra, en su caso int64 o float64.
Se me ocurren dos soluciones:
o
https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973
Entonces, su recorrido es realmente sólido, o de lo contrario podríamos:
fuente
object
tipos de datos! Otra es crear un objeto DataFrame desde el principio:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Siempre que obtenga datos de un marco de datos o anexe datos a un marco de datos y necesite mantener el mismo tipo de datos, evite la conversión a otras estructuras internas que no conozcan los tipos de datos necesarios.
Cuando lo haces
df.loc[0]
se convierte apd.Series
,Y ahora,
Series
solo tendrá unodtype
. Por lo tanto coaccionarint
afloat
.En cambio, mantenga la estructura como
pd.DataFrame
,Seleccione la fila necesaria como marco y luego convierta a
dict
Del mismo modo, para agregar una nueva fila, use la
pd.DataFrame.append
función pandas ,Lo anterior no causará conversión de tipo,
fuente
Un enfoque diferente con ligeras manipulaciones de datos:
Suponga que tiene una lista de diccionarios (o marcos de datos)
lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]
donde cada diccionario representa una fila (observe las listas en el segundo diccionario). Entonces puede crear un marco de datos fácilmente a través de:
y mantienes los tipos de las columnas. Ver concat
Entonces, si tiene un marco de datos y una lista de dictos, simplemente puede usar
fuente
En el primer caso, puede trabajar con el tipo de datos entero anulable . La selección de Series no coacciona
float
y los valores se colocan en unobject
contenedor. El diccionario se crea correctamente, con el valor subyacente almacenado como anp.int64
.Con su sintaxis, esto casi funciona también para el segundo caso, pero esto aumenta
object
, así que no es genial:Sin embargo, podemos hacer un pequeño cambio en la sintaxis para agregar una fila al final (con un RangeIndex) y ahora los tipos se tratan correctamente.
fuente