Spiegare il percorso di migrazione per Copy-on-Write

fotografato da Zoe Nicolaou SU Unsplash

introduzione

L’introduzione di Copy-on-Write (CoW) è una modifica rivoluzionaria che avrà un certo impatto sul codice Panda esistente. Esamineremo come adattare il nostro codice per evitare errori quando CoW sarà abilitato per impostazione predefinita. Questo è attualmente previsto per il rilascio di Pandas 3.0, previsto per aprile 2024. Il primo articolo in questa serie è stato spiegato il comportamento di Copy-on-Write while il secondo post si è tuffato nelle ottimizzazioni delle prestazioni relative al Copy-on-Write.

Stiamo pianificando di aggiungere una modalità di avviso che avviserà per tutte le operazioni che cambieranno il comportamento con CoW. L’avviso sarà molto rumoroso per gli utenti e quindi deve essere trattato con una certa attenzione. Questo post spiega i casi comuni e come adattare il codice per evitare cambiamenti nel comportamento.

Assegnazione concatenata

L’assegnazione concatenata è una tecnica in cui un oggetto viene aggiornato attraverso 2 operazioni successive.

import pandas as pd

df = pd.DataFrame({"x": (1, 2, 3)})

df("x")(df("x") > 1) = 100

La prima operazione seleziona la colonna "x" mentre la seconda operazione limita il numero di righe. Esistono molte combinazioni diverse di queste operazioni (ad esempio combinate con loc O iloc). Nessuna di queste combinazioni funzionerà con CoW. Invece, lanceranno un avvertimento ChainedAssignmentError per rimuovere questi schemi invece di non fare nulla in silenzio.

In generale, puoi usare loc Invece:

df.loc(df("x") > 1, "x") = 100

La prima dimensione di loc corrisponde sempre a row-indexer. Ciò significa che puoi selezionare un sottoinsieme di righe. La seconda dimensione corrisponde a column-indexerche consente di selezionare un sottoinsieme di colonne.

In genere è più veloce da usare loc quando desideri impostare valori in un sottoinsieme di righe, quindi questo ripulirà il tuo codice e fornirà un miglioramento delle prestazioni.

Questo è il caso ovvio in cui CoW avrà un impatto. Avrà un impatto anche sulle operazioni sul posto concatenate:

df("x").replace(1, 100)

Lo schema è lo stesso di sopra. La selezione della colonna è la prima operazione. IL replace Il metodo tenta di operare sull’oggetto temporaneo, che non riuscirà ad aggiornare l’oggetto iniziale. Puoi anche rimuovere questi modelli abbastanza facilmente specificando le colonne su cui desideri operare.

df = df.replace({"x": 1}, {"x": 100})

Modelli da evitare

Il mio post precedente spiega come funziona il meccanismo CoW e come i DataFrames condividono i dati sottostanti. Verrà eseguita una copia difensiva se due oggetti condividono gli stessi dati mentre si modifica un oggetto sul posto.

df2 = df.reset_index()
df2.iloc(0, 0) = 100

IL reset_index L’operazione creerà una visualizzazione dei dati sottostanti. Il risultato viene assegnato a una nuova variabile df2ciò significa che due oggetti condividono gli stessi dati. Questo vale fino al df è la raccolta dei rifiuti. IL setitem l’operazione attiverà quindi una copia. Questo è completamente inutile se non hai bisogno dell’oggetto iniziale df più. La semplice riassegnazione alla stessa variabile invaliderà il riferimento mantenuto dall’oggetto.

df = df.reset_index()
df.iloc(0, 0) = 100

Riassumendo, la creazione di più riferimenti nello stesso metodo mantiene vivi i riferimenti non necessari.

I riferimenti temporanei creati quando si concatenano metodi diversi vanno bene.

df = df.reset_index().drop(...)

Ciò manterrà vivo solo un riferimento.

Accesso all’array NumPy sottostante

pandas attualmente ci dà accesso all’array NumPy sottostante tramite to_numpy O .values. L’array restituito è una copia, se il tuo DataFrame è costituito da diversi dtype, ad esempio:

df = pd.DataFrame({"a": (1, 2), "b": (1.5, 2.5)})
df.to_numpy()

((1. 1.5)
(2. 2.5))

Il DataFrame è supportato da due array che devono essere combinati in uno solo. Questo attiva la copia.

L’altro caso è un DataFrame supportato solo da un singolo array NumPy, ad esempio:

df = pd.DataFrame({"a": (1, 2), "b": (3, 4)})
df.to_numpy()

((1 3)
(2 4))

Possiamo accedere direttamente all’array e ottenere una vista invece di una copia. Questo è molto più veloce della copia di tutti i dati. Ora possiamo operare sull’array NumPy e potenzialmente modificarlo sul posto, il che aggiornerà anche il DataFrame e potenzialmente tutti gli altri DataFrame che condividono dati. Ciò diventa molto più complicato con Copy-on-Write, poiché abbiamo rimosso molte copie difensive. Molti più DataFrame ora condivideranno la memoria tra loro.

to_numpy E .values restituirà un array di sola lettura per questo motivo. Ciò significa che l’array risultante non è scrivibile.

df = pd.DataFrame({"a": (1, 2), "b": (3, 4)})
arr = df.to_numpy()

arr(0, 0) = 1

Ciò attiverà un ValueError:

ValueError: assignment destination is read-only

Puoi evitarlo in due modi diversi:

  • Attiva una copia manualmente se vuoi evitare di aggiornare DataFrames che condividono memoria con il tuo array.
  • Rendi l’array scrivibile. Questa è una soluzione più performante ma elude le regole Copy-on-Write, quindi dovrebbe essere usata con cautela.
arr.flags.writeable = True

Ci sono casi in cui ciò non è possibile. Un evento comune è, se si accede a una singola colonna supportata da PyArrow:

ser = pd.Series((1, 2), dtype="int64(pyarrow)")
arr = ser.to_numpy()
arr.flags.writeable = True

Questo restituisce a ValueError:

ValueError: cannot set WRITEABLE flag to True of this array

Gli array di frecce sono immutabili, quindi non è possibile rendere scrivibile l’array NumPy. In questo caso la conversione da Arrow a NumPy è a copia zero.

Conclusione

Abbiamo esaminato le modifiche più invasive relative al Copy-on-Write. Queste modifiche diventeranno il comportamento predefinito in Pandas 3.0. Abbiamo anche studiato come possiamo adattare il nostro codice per evitare di romperlo quando la funzione Copy-on-Write è abilitata. Il processo di aggiornamento dovrebbe essere abbastanza fluido se riesci a evitare questi schemi.

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *