¿Qué reglas usa Pandas para generar una vista frente a una copia?

119

Estoy confundido acerca de las reglas que usa Pandas al decidir que una selección de un marco de datos es una copia del marco de datos original o una vista del original.

Si tengo, por ejemplo,

df = pd.DataFrame(np.random.randn(8,8), columns=list('ABCDEFGH'), index=range(1,9))

Entiendo que querydevuelve una copia para que algo como

foo = df.query('2 < index <= 5')
foo.loc[:,'E'] = 40

no tendrá ningún efecto sobre la trama de datos original, df. También entiendo que los segmentos escalares o con nombre devuelven una vista, de modo que las asignaciones a estos, como

df.iloc[3] = 70

o

df.ix[1,'B':'E'] = 222

cambiará df. Pero estoy perdido cuando se trata de casos más complicados. Por ejemplo,

df[df.C <= df.B] = 7654321

cambios df, pero

df[df.C <= df.B].ix[:,'B':'E']

no.

¿Existe una regla simple que utiliza Pandas y que me falta? ¿Qué está pasando en estos casos específicos? y, en particular, ¿cómo cambio todos los valores (o un subconjunto de valores) en un marco de datos que satisface una consulta en particular (como intento hacer en el último ejemplo anterior)?


Nota: No es lo mismo que esta pregunta ; y he leído la documentación , pero no me iluminó. También leí las preguntas "relacionadas" sobre este tema, pero todavía me falta la regla simple que usa Pandas y cómo la aplicaría, por ejemplo, a modificar los valores (o un subconjunto de valores) en un marco de datos que satisfaga una consulta en particular.

orome
fuente

Respuestas:

138

Aquí están las reglas, anulación posterior:

  • Todas las operaciones generan una copia

  • Si inplace=Truese proporciona, se modificará en el lugar; solo algunas operaciones apoyan esto

  • Un indexador que establece, por ejemplo .loc/.iloc/.iat/.at, se colocará en su lugar.

  • Un indexador que llega a un objeto de un solo tipo es casi siempre una vista (dependiendo del diseño de la memoria, puede que no sea por eso que no es confiable). Esto es principalmente por eficiencia. (el ejemplo de arriba es para .query; esto siempre devolverá una copia según sea evaluada por numexpr)

  • Un indexador que llega a un objeto de varios tipos siempre es una copia.

Tu ejemplo de chained indexing

df[df.C <= df.B].loc[:,'B':'E']

no está garantizado que funcione (y, por lo tanto, nunca debería hacer esto).

En su lugar, haz lo siguiente:

df.loc[df.C <= df.B, 'B':'E']

ya que esto es más rápido y siempre funcionará

La indexación encadenada son 2 operaciones de Python separadas y, por lo tanto, los pandas no pueden interceptarla de manera confiable (a menudo obtendrá un SettingWithCopyWarning, pero tampoco es 100% detectable). Los documentos de desarrollo , que señaló, ofrecen una explicación mucho más completa.

Jeff
fuente
3
.querySIEMPRE devolverá una copia debido a lo que está haciendo (y no una vista), porque es evaluado por n numexpr. Así que agregaré eso a las 'reglas'
Jeff
3
pandas se basa en numpy para determinar si se genera una vista. En un solo caso dtype (que podría ser un 1-d para una serie, un 2-d para un marco, etc.). numpy puede generar una vista; depende de lo que esté cortando; a veces puedes ver y otras no. pandas no se basa en absoluto en este hecho, ya que no siempre es obvio si se genera una vista. pero esto no importa ya que loc no se basa en esto al configurar. Sin embargo, cuando la cadena de indexación esto es muy importante (y por lo tanto la razón por la indexación cadena es malo)
Jeff
3
Muchas gracias Jeff, tu respuesta es de lo más útil. ¿Cuál es su fuente / referencia sobre este tema?
Kamixave
4
Entonces primero, ¡gracias por tu gran trabajo! Y en segundo lugar, si tiene suficiente tiempo, creo que sería genial agregar un párrafo similar a su respuesta principal en el documento.
Kamixave
2
sin duda tomaría una solicitud de extracción para agregar / revisar los documentos. ve a por ello.
Jeff