Considere el marco de datos df
df = pd.DataFrame(dict(A=[1, 2], B=['X', 'Y']))
df
A B
0 1 X
1 2 Y
Si me desplazo axis=0(el valor predeterminado)
df.shift()
A B
0 NaN NaN
1 1.0 X
Empuja todas las filas hacia abajo una fila como se esperaba.
Pero cuando cambio axis=1
df.shift(axis=1)
A B
0 NaN NaN
1 NaN NaN
Todo es nulo cuando esperaba
A B
0 NaN 1
1 NaN 2
Entiendo por qué sucedió esto. Para axis=0, Pandas está operando columna por columna donde cada columna es una sola dtypey al cambiar, hay un protocolo claro sobre cómo lidiar con el NaNvalor introducido al principio o al final. Pero cuando axis=1avanzamos introducimos una posible ambigüedad de dtypeuna columna a la siguiente. En este caso, trato de forzar int64una objectcolumna y Pandas decide simplemente anular los valores.
Esto se vuelve más problemático cuando dtypesson int64yfloat64
df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.]))
df
A B
0 1 1.0
1 2 2.0
Y sucede lo mismo
df.shift(axis=1)
A B
0 NaN NaN
1 NaN NaN
Mi pregunta
¿Cuáles son buenas opciones para crear un marco de datos que se desplaza axis=1en el que el resultado ha cambiado los valores y los tipos de letra?
Para el caso int64/ float64el resultado se vería así:
df_shifted
A B
0 NaN 1
1 NaN 2
y
df_shifted.dtypes
A object
B int64
dtype: object
Un ejemplo mas completo
df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.], C=['X', 'Y'], D=[4., 5.], E=[4, 5]))
df
A B C D E
0 1 1.0 X 4.0 4
1 2 2.0 Y 5.0 5
Debería verse así
df_shifted
A B C D E
0 NaN 1 1.0 X 4.0
1 NaN 2 2.0 Y 5.0
df_shifted.dtypes
A object
B int64
C float64
D object
E float64
dtype: object

object?objectblocks>. <Use esto en su lugar y veadf = pd.DataFrame(dict(A=[1, 2], B=[3., 4.], C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))Respuestas:
Resulta que Pandas está cambiando sobre bloques de similares
dtypesDefinir
dfcomoDesplazará los enteros a la siguiente columna entera, los flotantes a la siguiente columna flotante y los objetos a la siguiente columna de objetos.
No sé si es una buena idea, pero eso es lo que está sucediendo.
Enfoques
astype(object)primerotransposeLo haremos
objectitertuplesAunque probablemente haría esto
fuente
strtipo, entonces funciona correctamente, si haces lo mismo en este dfdf = pd.DataFrame(dict(C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z'])), cambia la'XY'columna por completo'F', esto definitivamente es incorrecto para mí, mi versión de pandas es0.24.2, no debería hacerdtypepromoción y no cambiar las columnas en tal una maneraIntenté usar un
numpymétodo. El método funciona siempre que mantenga sus datos en una matriz numpy:Pero cuando llama al
DataFrameconstructor, todas las columnas se conviertenobjectaunque los valores en la matriz sonfloat, int, object:fuente