Marco de datos pandas vista vs copia, ¿cómo lo digo?

Cuál es la diferencia entre:

pandas df.loc[:,('col_a','col_b')]

y

df.loc[:,['col_a','col_b']]

El siguiente enlace no menciona este último, aunque funciona. ¿Ambos sacan una vista? ¿El primero saca una vista y el segundo saca una copia? Me encanta aprender pandas.

http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

Gracias

Si su DataFrame tiene un índice de columna simple, entonces no hay diferencia. Por ejemplo,

 In [8]: df = pd.DataFrame(np.arange(12).reshape(4,3), columns=list('ABC')) In [9]: df.loc[:, ['A','B']] Out[9]: AB 0 0 1 1 3 4 2 6 7 3 9 10 In [10]: df.loc[:, ('A','B')] Out[10]: AB 0 0 1 1 3 4 2 6 7 3 9 10 

Pero si el DataFrame tiene un MultiIndex, puede haber una gran diferencia:

 df = pd.DataFrame(np.random.randint(10, size=(5,4)), columns=pd.MultiIndex.from_arrays([['foo']*2+['bar']*2, list('ABAB')]), index=pd.MultiIndex.from_arrays([['baz']*2+['qux']*3, list('CDCDC')])) # foo bar # ABAB # baz C 7 9 9 9 # D 7 5 5 4 # qux C 5 0 5 1 # D 1 7 7 4 # C 6 4 3 5 In [27]: df.loc[:, ('foo','B')] Out[27]: baz C 9 D 5 qux C 0 D 7 C 4 Name: (foo, B), dtype: int64 In [28]: df.loc[:, ['foo','B']] KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (1), lexsort depth (0)' 

El KeyError está diciendo que el MultiIndex tiene que ser lexsorted. Si hacemos eso, todavía obtendremos un resultado diferente:

 In [29]: df.sortlevel(axis=1).loc[:, ('foo','B')] Out[29]: baz C 9 D 5 qux C 0 D 7 C 4 Name: (foo, B), dtype: int64 In [30]: df.sortlevel(axis=1).loc[:, ['foo','B']] Out[30]: foo AB baz C 7 9 D 7 5 qux C 5 0 D 1 7 C 6 4 

¿Porqué es eso? df.sortlevel(axis=1).loc[:, ('foo','B')] está seleccionando la columna donde el primer nivel de columna es igual a foo , y el segundo nivel de columna es B

En contraste, df.sortlevel(axis=1).loc[:, ['foo','B']] está seleccionando las columnas donde el primer nivel de columna es foo o B Con respecto al primer nivel de columna, no hay columnas B , pero hay dos columnas foo .

Creo que el principio de funcionamiento con Pandas es que si usa df.loc[...] como una expresión , debe asumir que df.loc puede devolver una copia o una vista. Los documentos de Pandas no especifican ninguna regla acerca de lo que debe esperar. Sin embargo, si realiza una cesión del formulario.

 df.loc[...] = value 

Entonces puedes confiar en que Pandas se altere a sí mismo.

La razón por la que la documentación advierte sobre la distinción entre vistas y copias es para que esté al tanto de la dificultad de usar asignaciones en cadena del formulario.

 df.loc[...][...] = value 

Aquí, Pandas evalúa df.loc[...] primero, que puede ser una vista o una copia. Ahora si es una copia, entonces

 df.loc[...][...] = value 

está alterando una copia de alguna parte de df , y por lo tanto no tiene efecto en df sí mismo. Para agregar insulto al daño, el efecto en la copia también se pierde, ya que no hay referencias a la copia y, por lo tanto, no hay forma de acceder a la copia después de que se complete la statement de asignación, y (al menos en CPython) es pronto -en-ser la basura recogida.


No conozco una manera práctica a prueba de df.loc[...] a priori para determinar si df.loc[...] devolverá una vista o una copia.

Sin embargo, hay algunas reglas generales que pueden ayudar a guiar su intuición (pero tenga en cuenta que estamos hablando de detalles de implementación aquí, por lo que no hay garantía de que Pandas deba comportarse de esta manera en el futuro):

  • Si el NDFrame resultante no se puede express como un segmento básico de la matriz NumPy subyacente, entonces probablemente será una copia. Por lo tanto, una selección de filas o columnas arbitrarias conducirá a una copia. Una selección de filas secuenciales y / o columnas secuenciales (que pueden expressse como una porción) puede devolver una vista.
  • Si el NDFrame resultante tiene columnas de dtypes diferentes, df.loc probablemente volverá a df.loc una copia.

Sin embargo, hay una manera fácil de determinar si x = df.loc[..] es una vista a posteriori : Simplemente vea si cambiar un valor en x afecta a df . Si lo hace, es una vista, si no, x es una copia.