¿Copiar una columna de un DataFrame a otro da valores de NaN?

4 minutos de lectura

avatar de usuario de innm
posada

Esta pregunta se ha hecho tantas veces, y parece funcionar para otros, sin embargo, me estoy poniendo NaN valores cuando copio una columna de un DataFrame diferente (df1 y df2 tienen la misma longitud).

df1

        date     hour      var1
a   2017-05-01  00:00:00   456585
b   2017-05-01  01:00:00   899875
c   2017-05-01  02:00:00   569566
d   2017-05-01  03:00:00   458756
e   2017-05-01  04:00:00   231458
f   2017-05-01  05:00:00   986545

df2

      MyVar1     MyVar2 
 0  6169.719338 3688.045368
 1  5861.148007 3152.238704
 2  5797.053347 2700.469871
 3  5779.102340 2730.471948
 4  6708.219647 3181.298291
 5  8550.380343 3793.580394

Necesito así en mi df2

       MyVar1    MyVar2        date        hour
 0  6169.719338 3688.045368  2017-05-01  00:00:00
 1  5861.148007 3152.238704  2017-05-01  01:00:00
 2  5797.053347 2700.469871  2017-05-01  02:00:00
 3  5779.102340 2730.471948  2017-05-01  03:00:00
 4  6708.219647 3181.298291  2017-05-01  04:00:00
 5  8550.380343 3793.580394  2017-05-01  05:00:00

Intenté lo siguiente,

df2['date'] = df1['date']
df2['hour'] = df1['hour']

type(df1)
>> pandas.core.frame.DataFrame

type(df2)
>> pandas.core.frame.DataFrame

Estoy recibiendo lo siguiente,

       MyVar1    MyVar2      date       hour
 0  6169.719338 3688.045368  NaN        NaN
 1  5861.148007 3152.238704  NaN        NaN
 2  5797.053347 2700.469871  NaN        NaN

¿Por qué está pasando esto? Hay otro post que habla merge, pero solo necesito copiarlo. Cualquier ayuda sería apreciada.

avatar de usuario de cs95
cs95

El culpable son los índices que no se pueden alinear

Los índices de sus DataFrames son diferentes (y, en consecuencia, los índices de cada columna), por lo que al intentar asignar una columna de un DataFrame a otro, pandas intentará alinear los índices y, al no hacerlo, insertará NaNs.

Considere los siguientes ejemplos para entender lo que esto significa:

# Setup
A = pd.DataFrame(index=['a', 'b', 'c']) 
B = pd.DataFrame(index=['b', 'c', 'd', 'f'])                                  
C = pd.DataFrame(index=[1, 2, 3])
# Example of alignable indexes - A & B (complete or partial overlap of indexes)
A.index B.index
      a        
      b       b   (overlap)
      c       c   (overlap)
              d
              f
# Example of unalignable indexes - A & C (no overlap at all)
A.index C.index
      a        
      b        
      c        
              1
              2
              3

Cuando no hay superposiciones, los pandas no pueden hacer coincidir ni un solo valor entre los dos DataFrames para ingresar el resultado de la asignación, por lo que la salida es una columna llena de NaN.

Si está trabajando en una computadora portátil IPython, puede verificar que esta sea la causa principal usando,

df1.index.equals(df2.index)
# False
df1.index.intersection(df2.index).empty
# True

Puede usar cualquiera de las siguientes soluciones para solucionar este problema.

Solución 1: restablezca los índices de ambos DataFrames

Es posible que prefiera esta opción si no tenía la intención de tener índices diferentes en primer lugar, o si no le importa particularmente conservar el índice.

# Optional, if you want a RangeIndex => [0, 1, 2, ...]
# df1.index = pd.RangeIndex(len(df))
# Homogenize the index values,
df2.index = df1.index
# Assign the columns.
df2[['date', 'hour']] = df1[['date', 'hour']]

Si desea mantener el índice existente, pero como una columna, puede usar reset_index() en cambio.


Solución 2: asigne matrices NumPy (omita la alineación del índice)

Esta solución solo funcionará si las longitudes de los dos DataFrames coinciden.

# pandas >= 0.24
df2['date'] = df1['date'].to_numpy()
# pandas < 0.24
df2['date'] = df1['date'].values

Para asignar múltiples columnas fácilmente, use,

df2[['date', 'hour']] = df1[['date', 'hour']].to_numpy()

  • @innm Podría ser un problema con su index. Intenta agregar ignore_index=True? De lo contrario, restablezca primero ambos índices y luego concatene.

    – cs95

    18 de agosto de 2017 a las 2:35


  • @innm prueba df2['date'] = df1['date'].values

    – BENY

    18 de agosto de 2017 a las 2:37


  • @innm Ah, lo adiviné. Los índices no eran idénticos.

    – cs95

    18 de agosto de 2017 a las 2:40

  • Tenía dos marcos de datos donde uno tenía un índice de rango y el otro tenía un índice entero con valores dentro de ese rango. Mirando los marcos de datos, los índices parecen estar bien, pero la intersección estaba vacía. Así que tuve que usar to_numpy() en su lugar.

    – Lyte FM

    14 de noviembre de 2019 a las 20:54

  • ¿Alguna idea de cómo hacer que los nombres de las columnas sean dinámicos, en lugar de uno codificado?

    – Manu Batham

    19 de febrero a las 7:04

Prueba esto ?

df2['date'] = df1['date'].values
df2['hour'] = df1['hour'].values

  • ¡Esto es mejor que la solución aceptada!

    – Gokul nath

    16 de septiembre de 2021 a las 9:02

  • cuando los datos son grandes (alrededor de 10 ^ 5), son muy lentos, ¿hay alguna forma?

    – lemmingxuan

    16 de noviembre de 2021 a las 13:56

Sé que llego tarde a este hilo, pero este formato me ha funcionado bien.

df2.insert(1, value=df1['Name'], column='Name')

también puede realizar funciones en df1 en ese argumento de conjunto de valores. Espero que esto ayude

¿Ha sido útil esta solución?