Vues vs copies – Real Python

By | juin 10, 2020

Cours Python en ligne

NumPy et Pandas sont des outils Python très complets, efficaces et flexibles pour la manipulation de données. Un concept important pour les utilisateurs compétents de ces deux bibliothèques est de comprendre comment les données sont référencées comme copies superficielles (vues) et copies profondes (ou juste copies). Les pandas émettent parfois un SettingWithCopyWarning pour avertir l'utilisateur d'une utilisation potentiellement inappropriée des vues et des copies.

Dans cet article, vous apprendrez:

  • Quoi vues et copies sont dans NumPy et Pandas
  • Comment travailler correctement avec des vues et des copies dans NumPy et Pandas
  • Pourquoi le SettingWithCopyWarning arrive dans les Pandas
  • Comment éviter d'avoir un SettingWithCopyWarning dans Pandas

Vous verrez d'abord une courte explication de ce que SettingWithCopyWarning est et comment l'éviter. Vous trouverez peut-être cela suffisant pour vos besoins, mais vous pouvez également approfondir un peu plus les détails de NumPy et Pandas pour en savoir plus sur les copies et les vues.

Conditions préalables

Pour suivre les exemples de cet article, vous aurez besoin de Python 3.7 ou 3.8, ainsi que des bibliothèques NumPy et Pandas. Cet article est écrit pour NumPy version 1.18.1 et Pandas version 1.0.3. Vous pouvez les installer avec pépin:

$ python -m pip install -U "numpy == 1.18. *" "pandas == 1.0. *"

Si vous préférez les distributions Anaconda ou Miniconda, vous pouvez utiliser le système de gestion de paquets conda. Pour en savoir plus sur cette approche, consultez Configuration de Python pour l'apprentissage automatique sous Windows. Pour l'instant, il suffira d'installer NumPy et Pandas dans votre environnement:

$ installation de conda engourdi=1.18. * pandas=1.0. *

Maintenant que NumPy et Pandas sont installés, vous pouvez les importer et vérifier leurs versions:

>>>

>>> importation engourdi comme np
>>> importation pandas comme pd

>>> np.__version__
«1.18.1»
>>> pd.__version__
«1.0.3»

C'est ça. Vous disposez de tous les prérequis pour cet article. Vos versions peuvent varier légèrement, mais les informations ci-dessous continueront de s'appliquer.

Vous êtes maintenant prêt à vous familiariser avec les vues, les copies et les SettingWithCopyWarning!

Exemple d'un SettingWithCopyWarning

Si vous travaillez avec Pandas, il est probable que vous ayez déjà vu un SettingWithCopyWarning en action. Cela peut être ennuyeux et parfois difficile à comprendre. Cependant, il a été émis pour une raison.

La première chose que vous devez savoir sur le SettingWithCopyWarning c'est que c'est ne pas une erreur. C’est un avertissement. Il vous avertit que vous avez probablement fait quelque chose qui entraînera un comportement indésirable dans votre code.

Voyons un exemple. Vous allez commencer par créer un Pandas DataFrame:

>>>

>>> Les données = "X": 2**np.arange(5),
...         "y": 3**np.arange(5),
...         "z": np.tableau([[[[45, 98, 24, 11, 64])

>>> indice = [[[["une", "b", "c", "ré", "e"]

>>> df = pd.Trame de données(Les données=Les données, indice=indice)
>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

Cet exemple crée un dictionnaire référencé par la variable Les données cela contient:

  • Les clés "X", "y", et "z", qui seront les libellés des colonnes du DataFrame
  • Trois tableaux NumPy qui contiennent les données du DataFrame

Vous créez les deux premiers tableaux avec la routine numpy.arange () et le dernier avec numpy.array (). En apprendre davantage sur arange (), consultez NumPy arange (): Comment utiliser np.arange ().

La liste attachée à la variable indice contient les chaînes "une", "b", "c", "ré", et "e", qui seront les étiquettes de ligne du DataFrame.

Enfin, vous initialisez le DataFrame df qui contient les informations de Les données et indice. Vous pouvez le visualiser comme ceci:

mmst-pandas-vc-01

Voici une ventilation des principales informations contenues dans le DataFrame:

  • Boîte violette: Les données
  • Boite bleue: Étiquettes de colonne
  • Boîte rouge: Étiquettes de ligne

Le DataFrame stocke des informations supplémentaires ou des métadonnées, notamment sa forme, les types de données, etc.

Maintenant que vous disposez d'un DataFrame avec lequel travailler, essayons d'obtenir un SettingWithCopyWarning. Vous prendrez toutes les valeurs de la colonne z qui sont moins de cinquante et les remplacer par des zéros. Vous pouvez commencer par créer un masque ou un filtre avec les opérateurs booléens Pandas:

>>>

>>> masque = df[[[["z"] < 50
>>> masque
une véritable
b Faux
c Vrai
d Vrai
e Faux
Nom: z, dtype: bool

>>> df[[[[masque]
            x y z
a 1 1 45
c 4 9 24
d 8 27 11

masque est une instance d'une série Pandas avec des données booléennes et les indices de df:

  • Vrai indique les lignes dans df dans lequel la valeur de z est inférieur à 50.
  • Faux indique les lignes dans df dans lequel la valeur de z est ne pas moins que 50.

df[mask] renvoie un DataFrame avec les lignes de df Pour qui masque est Vrai. Dans ce cas, vous obtenez des lignes une, c, et .

Si vous essayez de changer df en extrayant des lignes une, c, et en utilisant masque, vous obtiendrez un SettingWithCopyWarning, et df restera le même:

>>>

>>> df[[[[masque][[[["z"] = 0
__main __: 1: SettingWithCopyWarning:
Une valeur tente d'être définie sur une copie d'une tranche à partir d'un DataFrame.
Essayez d'utiliser .loc[row_indexer,col_indexer] = valeur à la place

Voir les mises en garde dans la documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

Comme vous pouvez le voir, l'affectation de zéros à la colonne z échoue. Cette image illustre l'ensemble du processus:

mmst-pandas-vc-02

Voici ce qui se passe dans l'exemple de code ci-dessus:

  • df[mask] renvoie un DataFrame complètement nouveau (indiqué en violet). Ce DataFrame contient une copie des données de df qui correspondent à Vrai valeurs de masque (surligné en vert).
  • df[mask]["z"] = 0 modifie la colonne z du nouveau DataFrame à zéros, laissant df intacte.

Habituellement, vous ne voulez pas ça! Vous souhaitez modifier df et non une structure de données intermédiaire qui n'est référencée par aucune variable. C’est pourquoi les Pandas émettent un SettingWithCopyWarning et vous met en garde contre cette possible erreur.

Dans ce cas, la bonne façon de modifier df est d'appliquer l'un des accesseurs .loc[], .iloc[], .à[], ou .iat[]:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)

>>> df.loc[[[[masque, "z"] = 0
>>> df
                x y z
a 1 1 0
b 2 3 98
c 4 9 0
d 8 27 0
e 16 81 64

Cette approche vous permet de fournir deux arguments, masque et "z", à la méthode unique qui attribue les valeurs au DataFrame.

Une autre façon de résoudre ce problème consiste à modifier l'ordre d'évaluation:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)

>>> df[[[["z"]
un 45
b 98
c 24
d 11
e 64
Nom: z, dtype: int64

>>> df[[[["z"][[[[masque] = 0
>>> df
                x y z
a 1 1 0
b 2 3 98
c 4 9 0
d 8 27 0
e 16 81 64

Cela marche! Vous avez modifié df. Voici à quoi ressemble ce processus:

mmst-pandas-vc-03

Voici une ventilation de l'image ::

  • df["z"] renvoie un Séries objet (souligné en violet) qui pointe vers le mêmes données comme colonne z dans df, pas sa copie.
  • df["z"][mask] = 0 modifie cela Séries objet en utilisant affectation enchaînée pour mettre à zéro les valeurs masquées (surlignées en vert).
  • df est également modifié depuis la Séries objet df["z"] contient les mêmes données que df.

Tu as vu ça df[mask] contient une copie des données, tandis que df["z"] pointe vers les mêmes données que df. Les règles utilisées par les Pandas pour déterminer si vous faites ou non une copie sont très complexes. Heureusement, il existe des moyens simples d'attribuer des valeurs aux DataFrames et d'éviter un SettingWithCopyWarning.

L'invocation d'accesseurs est généralement considérée comme une meilleure pratique que l'affectation en chaîne pour les raisons suivantes:

  1. L'intention de modifier df est plus clair pour Pandas lorsque vous utilisez une seule méthode.
  2. Le code est plus propre pour les lecteurs.
  3. Les accesseurs ont tendance à avoir de meilleures performances, même si vous ne le remarquerez pas dans la plupart des cas.

Cependant, l'utilisation d'accesseurs n'est parfois pas suffisante. Ils peuvent également retourner des copies, auquel cas vous pouvez obtenir un SettingWithCopyWarning:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)

>>> df.loc[[[[masque][[[["z"] = 0
__main __: 1: SettingWithCopyWarning:
Une valeur tente d'être définie sur une copie d'une tranche à partir d'un DataFrame.
Essayez d'utiliser .loc[row_indexer,col_indexer] = valeur à la place

Voir les mises en garde dans la documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

Dans cet exemple, comme dans le précédent, vous utilisez l'accesseur .loc[]. L'affectation échoue car df.loc[mask] renvoie un nouveau DataFrame avec une copie des données de df. alors df.loc[mask]["z"] = 0 modifie le nouveau DataFrame, pas df.

Généralement, pour éviter SettingWithCopyWarning dans Pandas, vous devez procéder comme suit:

  • Évitez les affectations enchaînées qui combinent deux ou plusieurs opérations d'indexation comme df["z"][mask] = 0 et df.loc[mask]["z"] = 0.
  • Appliquer des affectations uniques avec une seule opération d'indexation comme df.loc[mask, "z"] = 0. Cela peut (ou non) impliquer l'utilisation d'accesseurs, mais ils sont certainement très utiles et souvent préférables.

Avec ces connaissances, vous pouvez éviter avec succès SettingWithCopyWarning et tout comportement indésirable dans la plupart des cas. Cependant, si vous souhaitez approfondir NumPy, Pandas, les vues, les copies et les problèmes liés à la SettingWithCopyWarning, puis continuez avec le reste de l'article.

Vues et copies dans NumPy et Pandas

Comprendre les vues et les copies est un élément important pour savoir comment NumPy et Pandas manipulent les données. Il peut également vous aider à éviter les erreurs et les goulots d'étranglement des performances. Parfois, les données sont copiées d'une partie de la mémoire à une autre, mais dans d'autres cas, deux ou plusieurs objets peuvent partager les mêmes données, ce qui économise du temps et de la mémoire.

Comprendre les vues et les copies dans NumPy

Commençons par créer un tableau NumPy:

>>>

>>> arr = np.tableau([[[[1, 2, 4, 8, 16, 32])
>>> arr
tableau ([ 1,  2,  4,  8, 16, 32])

Maintenant que vous avez arr, vous pouvez l'utiliser pour créer d'autres tableaux. Extrayons d'abord les deuxième et quatrième éléments de arr (2 et 8) en tant que nouveau tableau. Il y a plusieurs moyens de le faire:

>>>

>>> arr[[[[1:4:2]
tableau ([2, 8])

>>> arr[[[[[[[[1, 3]]
tableau ([2, 8]))

Ne vous inquiétez pas si vous n'êtes pas familier avec l'indexation de tableaux. Vous en apprendrez plus sur ces déclarations et d'autres ultérieurement. Pour l'instant, il est important de noter que les deux déclarations renvoient tableau ([2, 8]). Cependant, ils ont un comportement différent sous la surface:

>>>

>>> arr[[[[1:4:2].base
tableau ([ 1,  2,  4,  8, 16, 32])
>>> arr[[[[1:4:2].drapeaux.owndata
Faux

>>> arr[[[[[[[[1, 3]].base
>>> arr[[[[[[[[1, 3]].drapeaux.owndata
Vrai

Cela peut sembler étrange à première vue. La différence réside dans le fait que arr[1:4:2] renvoie un copie superficielle, tandis que arr[[1, 3]] renvoie un copie en profondeur. Comprendre cette différence est essentiel non seulement pour faire face à la SettingWithCopyWarning mais aussi pour manipuler le big data avec NumPy et Pandas.

Dans les sections ci-dessous, vous en apprendrez plus sur les copies superficielles et profondes dans NumPy et Pandas.

Vues dans NumPy

UNE copie superficielle ou vue est un tableau NumPy qui n'a pas ses propres données. Il examine ou «visualise» les données contenues dans le tableau d'origine. Vous pouvez créer une vue d'un tableau avec .vue():

>>>

>>> view_of_arr = arr.vue()
>>> view_of_arr
tableau ([ 1,  2,  4,  8, 16, 32])

>>> view_of_arr.base
tableau ([ 1,  2,  4,  8, 16, 32])

>>> view_of_arr.base est arr
Vrai

Vous avez obtenu le tableau view_of_arr, qui est une vue ou une copie superficielle du tableau d'origine arr. L'attribut .base de view_of_arr est arr lui-même. En d'autres termes, view_of_arr ne possède aucune donnée – il utilise les données qui appartiennent à arr. Vous pouvez également vérifier cela avec l'attribut .flags:

>>>

>>> view_of_arr.drapeaux.owndata
Faux

Comme vous pouvez le voir, view_of_arr.flags.owndata est Faux. Cela signifie que view_of_arr ne possède pas de données et utilise ses .base pour obtenir les données:

mmst-pandas-vc-04

L'image ci-dessus montre que arr et view_of_arr pointer vers les mêmes valeurs de données.

Copies dans NumPy

UNE copie en profondeur d'un tableau NumPy, parfois appelé juste un copie, est un tableau NumPy distinct qui a ses propres données. Les données d'une copie complète sont obtenues en copiant les éléments du tableau d'origine dans le nouveau tableau. L'original et la copie sont deux instances distinctes. Vous pouvez créer une copie d'un tableau avec .copie():

>>>

>>> copy_of_arr = arr.copie()
>>> copy_of_arr
tableau ([ 1,  2,  4,  8, 16, 32])

>>> copy_of_arr.base est Aucun
Vrai

>>> copy_of_arr.drapeaux.owndata
Vrai

Comme vous pouvez le voir, copy_of_arr n'a pas .base. Pour être plus précis, la valeur de copy_of_arr.base est Aucun. L'attribut .flags.owndata est Vrai. Cela signifie que copy_of_arr possède des données:

mmst-pandas-vc-05

L'image ci-dessus montre que arr et copy_of_arr contiennent différentes instances de valeurs de données.

Différences entre les vues et les copies

Il existe deux différences très importantes entre les vues et les copies:

  1. Les vues n'ont pas besoin de stockage supplémentaire pour les données, mais les copies en ont besoin.
  2. La modification du tableau d'origine affecte ses vues et vice versa. Cependant, la modification du tableau d'origine ne pas affecter sa copie.

Pour illustrer la première différence entre les vues et les copies, comparons les tailles de arr, view_of_arr, et copy_of_arr. L'attribut .nbytes renvoie la mémoire consommée par les éléments du tableau:

>>>

>>> arr.nbytes
48
>>> view_of_arr.nbytes
48
>>> copy_of_arr.nbytes
48

La quantité de mémoire est la même pour toutes les baies: 48 octets. Chaque tableau examine six éléments entiers de 8 octets (64 bits) chacun. C'est 48 octets au total.

Cependant, si vous utilisez sys.getsizeof () pour obtenir la quantité de mémoire directement attribuée à chaque baie, vous verrez la différence:

>>>

>>> de sys importation getsizeof

>>> getsizeof(arr)
144
>>> getsizeof(view_of_arr)
96
>>> getsizeof(copy_of_arr)
144

arr et copy_of_arr contenir 144 octets chacun. Comme vous l'avez vu précédemment, 48 octets sur les 144 au total sont destinés aux éléments de données. Les 96 octets restants sont destinés à d'autres attributs. view_of_arr ne contient que ces 96 octets car il n'a pas ses propres éléments de données.

Pour illustrer la deuxième différence entre les vues et les copies, vous pouvez modifier n'importe quel élément du tableau d'origine:

>>>

>>> arr[[[[1] = 64
>>> arr
tableau ([ 1,  64,   4,   8,  16,  32])

>>> view_of_arr
tableau ([ 1,  64,   4,   8,  16,  32])

>>> copy_of_arr
tableau ([ 1,  2,  4,  8, 16, 32])

Comme vous pouvez le voir, la vue est également modifiée, mais la copie reste la même. Le code est illustré dans l'image ci-dessous:

mmst-pandas-vc-06

La vue est modifiée car elle examine les éléments de arr, et son .base est le tableau d'origine. La copie est inchangée car elle ne partage pas de données avec l'original, donc une modification de l'original ne l'affecte pas du tout.

Comprendre les vues et les copies dans Pandas

Pandas fait également une distinction entre les vues et les copies. Vous pouvez créer une vue ou une copie d'un DataFrame avec .copie(). Le paramètre Profond détermine si vous souhaitez une vue (deep = False) ou copier (deep = True). Profond est Vrai par défaut, vous pouvez donc l'omettre pour obtenir une copie:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)
>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

>>> view_of_df = df.copie(Profond=Faux)
>>> view_of_df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

>>> copy_of_df = df.copie()
>>> copy_of_df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

Au début, la vue et la copie de df ressemble. Si vous comparez leurs représentations NumPy, cependant, vous remarquerez peut-être cette subtile différence:

>>>

>>> view_of_df.to_numpy().base est df.to_numpy().base
Vrai
>>> copy_of_df.to_numpy().base est df.to_numpy().base
Faux

Ici, .to_numpy () renvoie le tableau NumPy qui contient les données des DataFrames. Tu peux voir ça df et view_of_df Avoir le même .base et partager les mêmes données. D'autre part, copy_of_df contient des données différentes.

Vous pouvez le vérifier en modifiant df:

>>>

>>> df[[[["z"] = 0
>>> df
                x y z
a 1 1 0
b 2 3 0
c 4 9 0
d 8 27 0
e 16 81 0

>>> view_of_df
                x y z
a 1 1 0
b 2 3 0
c 4 9 0
d 8 27 0
e 16 81 0

>>> copy_of_df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

Vous avez attribué des zéros à tous les éléments de la colonne z dans df. Cela provoque un changement de view_of_df, mais copy_of_df reste inchangé.

Les étiquettes de lignes et de colonnes présentent également le même comportement:

>>>

>>> view_of_df.indice est df.indice
Vrai
>>> view_of_df.Colonnes est df.Colonnes
Vrai

>>> copy_of_df.indice est df.indice
Faux
>>> copy_of_df.Colonnes est df.Colonnes
Faux

df et view_of_df partager les mêmes étiquettes de ligne et de colonne, copy_of_df a des instances d'index distinctes. N'oubliez pas que vous ne pouvez pas modifier des éléments particuliers de .indice et .Colonnes. Elles sont immuable objets.

Indices et tranches dans NumPy et Pandas

L'indexation et le découpage de base dans NumPy sont similaires à l'indexation et au découpage des listes et des tuples. Cependant, NumPy et Pandas fournissent des options supplémentaires pour référencer et affecter des valeurs aux objets et à leurs pièces.

Tableaux NumPy et objets Pandas (Trame de données et Séries) implémentez des méthodes spéciales qui permettent de référencer, d'affecter et de supprimer des valeurs dans un style similaire à celui des conteneurs:

Lorsque vous référencez, attribuez ou supprimez des données dans des objets de type conteneur Python, vous appelez souvent ces méthodes:

  • var = obj[key] est équivalent à var = obj .__ getitem __ (clé).
  • obj[key] = valeur est équivalent à obj .__ setitem __ (clé, valeur).
  • del obj[key] est équivalent à obj .__ delitem __ (clé).

L'argument clé représente l'index, qui peut être un entier, une tranche, un tuple, une liste, un tableau NumPy, etc.

Indexation dans NumPy: copies et vues

NumPy a un ensemble strict de règles liées aux copies et aux vues lors de l'indexation des tableaux. Que vous obteniez des vues ou des copies des données d'origine dépend de l'approche que vous utilisez pour indexer vos tableaux: découpage, indexation entière ou indexation booléenne.

Tableaux unidimensionnels

Le découpage est une opération bien connue en Python pour obtenir des données particulières à partir de tableaux, de listes ou de tuples. Lorsque vous découpez un tableau NumPy, vous obtenez une vue du tableau:

>>>

>>> arr = np.tableau([[[[1, 2, 4, 8, 16, 32])

>>> une = arr[[[[1:3]
>>> une
tableau ([2, 4])
>>> une.base
tableau ([ 1,  2,  4,  8, 16, 32])
>>> une.base est arr
Vrai
>>> une.drapeaux.owndata
Faux

>>> b = arr[[[[1:4:2]
>>> b
tableau ([2, 8])
>>> b.base
tableau ([ 1,  2,  4,  8, 16, 32])
>>> b.base est arr
Vrai
>>> b.drapeaux.owndata
Faux

Vous avez créé le tableau d'origine arr et coupé en tranches pour obtenir deux tableaux plus petits, une et b. Tous les deux une et b utilisation arr comme leurs bases et ni a ses propres données. Au lieu de cela, ils regardent les données de arr:

mmst-pandas-vc-07

Les indices verts de l'image ci-dessus sont pris par découpage. Tous les deux une et b regardez les éléments correspondants de arr dans les rectangles verts.

Bien que le découpage renvoie une vue, il existe d'autres cas où la création d'un tableau à partir d'un autre en fait une copie.

L'indexation d'un tableau avec une liste d'entiers renvoie une copie du tableau d'origine. La copie contient les éléments du tableau d'origine dont les indices sont présents dans la liste:

>>>

>>> c = arr[[[[[[[[1, 3]]
>>> c
tableau ([2, 8])
>>> c.base est Aucun
Vrai
>>> c.drapeaux.owndata
Vrai

Le tableau résultant c contient les éléments de arr avec les indices 1 et 3. Ces éléments ont les valeurs 2 et 8. Dans ce cas, c est une copie de arr, son .base est Aucun, et il possède ses propres données:

mmst-pandas-vc-08

Les éléments de arr avec les indices choisis 1 et 3 sont copiés dans le nouveau tableau c. Une fois la copie terminée, arr et c sont indépendants.

Vous pouvez également indexer des tableaux NumPy avec des tableaux ou des listes de masques. Les masques sont des tableaux booléens ou des listes de la même forme que l'original. Vous obtiendrez une copie du tableau d'origine qui ne contient que les éléments correspondant à la Vrai valeurs du masque:

>>>

>>> masque = [[[[Faux, Vrai, Faux, Vrai, Faux, Faux]
>>>  = arr[[[[masque]
>>> 
tableau ([2, 8])
>>> .base est Aucun
Vrai
>>> .drapeaux.owndata
Vrai

La liste masque a Vrai valeurs aux deuxième et quatrième positions. C'est pourquoi le tableau ne contient que les éléments des deuxième et quatrième positions de arr. Comme dans le cas de c, est une copie, son .base est Aucun, et il possède ses propres données:

mmst-pandas-vc-09

Les éléments de arr dans les rectangles verts correspondent à Vrai valeurs de masque. Ces éléments sont copiés dans le nouveau tableau . Après avoir copié, arr et sont indépendants.

Pour récapituler, voici les variables que vous avez créées jusqu'à présent et qui font référence arr:

# `arr` est le tableau d'origine:
arr = np.tableau([[[[1, 2, 4, 8, 16, 32])

# `a` et` b` sont des vues créées par découpage:
une = arr[[[[1:3]
b = arr[[[[1:4:2]

# `c` et` d` sont des copies créées par indexation entière et booléenne:
c = arr[[[[[[[[1, 3]]
 = arr[[[[[[[[Faux, Vrai, Faux, Vrai, Faux, Faux]]

N'oubliez pas que ces exemples montrent comment vous pouvez référence données dans un tableau. Le référencement des données renvoie des vues lors du découpage des tableaux et des copies lors de l'utilisation des tableaux d'index et de masque. Affectationsd'autre part, modifiez toujours les données d'origine du tableau.

Maintenant que vous disposez de tous ces tableaux, voyons ce qui se passe lorsque vous modifiez l'original:

>>>

>>> arr[[[[1] = 64
>>> arr
tableau ([  1, 64,   4,   8,  16,  32])
>>> une
tableau ([64,   4])
>>> b
tableau ([64,   8])
>>> c
tableau ([2, 8])
>>> 
tableau ([2, 8])

Vous avez modifié la deuxième valeur de arr de 2 à 64. La valeur 2 était également présent dans les tableaux dérivés une, b, c, et . Cependant, seules les vues une et b sont modifiés:

mmst-pandas-vc-10

Les vues une et b regardez les données de arr, y compris son deuxième élément. C’est pourquoi vous voyez le changement. Les copies c et restent inchangés car ils ne disposent pas de données communes avec arr. Ils sont indépendants de arr.

Indexation chaînée dans NumPy

Ce comportement avec une et b ressembler à tous les exemples précédents de Pandas? Cela pourrait, parce que le concept de indexation chaînée s'applique également dans NumPy:

>>>

>>> arr = np.tableau([[[[1, 2, 4, 8, 16, 32])
>>> arr[[[[1:4:2][[[[0] = 64
>>> arr
tableau ([ 1, 64,  4,  8, 16, 32])

>>> arr = np.tableau([[[[1, 2, 4, 8, 16, 32])
>>> arr[[[[[[[[1, 3]][[[[0] = 64
>>> arr
tableau ([ 1,  2,  4,  8, 16, 32])

Cet exemple illustre la différence entre les copies et les vues lors de l'utilisation de l'indexation chaînée dans NumPy.

Dans le premier cas, arr[1:4:2] renvoie une vue qui fait référence aux données de arr et contient les éléments 2 et 8. La déclaration arr[1:4:2][0] = 64 modifie le premier de ces éléments en 64. Le changement est visible dans les deux arr et la vue retournée par arr[1:4:2].

Dans le second cas, arr[[1, 3]] renvoie une copie qui contient également les éléments 2 et 8. Mais ce ne sont pas les mêmes éléments que dans arr. Ce sont de nouveaux. arr[[1, 3]][0] = 64 modifie la copie retournée par arr[[1, 3]] et laisse arr inchangé.

Il s'agit essentiellement du même comportement qui produit un SettingWithCopyWarning dans Pandas, mais cet avertissement n'existe pas dans NumPy.

Tableaux multidimensionnels

Le référencement de tableaux multidimensionnels suit les mêmes principes:

  • Le découpage des tableaux renvoie des vues.
  • L'utilisation des tableaux d'index et de masque renvoie des copies.

La combinaison de tableaux d'index et de masques avec le découpage est également possible. Dans de tels cas, vous obtenez des copies.

Voici quelques exemples:

>>>

>>> arr = np.tableau([[[[[[[[  1,   2,    4,    8],
...                 [[[[ 16,  32,   64,  128],
...                 [[[[256, 512, 1024, 2048]])
>>> arr
tableau ([[   1,    2,    4,    8],
       [  16,   32,   64,  128],
       [ 256,  512, 1024, 2048]])

>>> une = arr[:[:[:[: 1:3]  # Prenez les colonnes 1 et 2
>>> une
tableau ([[   2,    4],
       [  32,   64],
       [ 512, 1024]])
>>> une.base
tableau ([[   1,    2,    4,    8],
       [  16,   32,   64,  128],
       [ 256,  512, 1024, 2048]])
>>> une.base est arr
Vrai

>>> b = arr[:[:[:[: 1:4:2]  # Prenez les colonnes 1 et 3
>>> b
tableau ([[   2,    8],
       [  32,  128],
       [ 512, 2048]])
>>> b.base
tableau ([[   1,    2,    4,    8],
       [  16,   32,   64,  128],
       [ 256,  512, 1024, 2048]])
>>> b.base est arr
Vrai

>>> c = arr[:[:[:[: [[[[1, 3]]  # Prenez les colonnes 1 et 3
>>> c
tableau ([[   2,    8],
       [  32,  128],
       [ 512, 2048]])
>>> c.base
tableau ([[   2,   32,  512],
       [   8,  128, 2048]])
>>> c.base est arr
Faux

>>>  = arr[:[:[:[: [[[[Faux, Vrai, Faux, Vrai]]  # Prenez les colonnes 1 et 3
>>> 
tableau ([[   2,    8],
       [  32,  128],
       [ 512, 2048]])
>>> .base
tableau ([[   2,   32,  512],
       [   8,  128, 2048]])
>>> .base est arr
Faux

Dans cet exemple, vous partez du tableau à deux dimensions arr. Vous appliquez des tranches pour les lignes. Utilisation de la syntaxe deux-points (:), ce qui équivaut à tranche (aucune), signifie que vous souhaitez prendre toutes les lignes.

Lorsque vous travaillez avec les tranches 1: 3 et 1: 4: 2 pour les colonnes, les vues une et b sont retournés. Cependant, lorsque vous appliquez la liste [1, 3] et masque [False, True, False, True], vous obtenez les copies c et .

le .base des deux une et b est arr lui-même. Tous les deux c et ont leurs propres bases sans rapport avec arr.

Comme pour les tableaux unidimensionnels, lorsque vous modifiez l'original, les vues changent car elles voient les mêmes données, mais les copies restent les mêmes:

>>>

>>> arr[[[[0, 1] = 100
>>> arr
tableau ([[   1,  100,    4,    8],
       [  16,   32,   64,  128],
       [ 256,  512, 1024, 2048]])

>>> une
tableau ([[ 100,    4],
       [  32,   64],
       [ 512, 1024]])

>>> b
tableau ([[ 100,    8],
       [  32,  128],
       [ 512, 2048]])

>>> c
tableau ([[   2,    8],
       [  32,  128],
       [ 512, 2048]])

>>> 
tableau ([[   2,    8],
       [  32,  128],
       [ 512, 2048]])

Vous avez changé la valeur 2 dans arr à 100 et modifié les éléments correspondants des vues une et b. Les copies c et ne peut pas être modifié de cette façon.

Pour en savoir plus sur l'indexation des tableaux NumPy, vous pouvez consulter le didacticiel de démarrage rapide officiel et le didacticiel d'indexation.

Indexation dans Pandas: copies et vues

Vous avez appris comment utiliser différentes options d'indexation dans NumPy pour faire référence à des données réelles (une vue ou une copie superficielle) ou à des données nouvellement copiées (copie complète ou simplement copie). NumPy a un ensemble de règles strictes à ce sujet.

Pandas s'appuie fortement sur les tableaux NumPy mais offre des fonctionnalités et une flexibilité supplémentaires. Pour cette raison, les règles de retour des vues et des copies sont plus complexes et moins simples. Ils dépendent de la disposition des données, des types de données et d'autres détails. En fait, les Pandas ne garantissent souvent pas si une vue ou une copie sera référencée.

Dans cette section, vous verrez deux exemples de la façon dont Pandas se comporte de manière similaire à NumPy. Tout d'abord, vous pouvez voir que l'accès aux trois premières lignes de df avec une tranche renvoie une vue:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)

>>> df[[[["une":"c"]
            x y z
a 1 1 45
b 2 3 98
c 4 9 24

>>> df[[[["une":"c"].to_numpy().base
tableau ([[ 1,  2,  4,  8, 16],
       [ 1,  3,  9, 27, 81],
       [45, 98, 24, 11, 64]])

>>> df[[[["une":"c"].to_numpy().base est df.to_numpy().base
Vrai

Cette vue examine les mêmes données que df.

D'autre part, l'accès aux deux premières colonnes de df avec une liste d'étiquettes renvoie une copie:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)

>>> df[[[[[[[["X", "y"]]
                x y
a 1 1
b 2 3
c 4 9
d 8 27
e 16 81

>>> df[[[[[[[["X", "y"]].to_numpy().base
tableau ([[ 1,  2,  4,  8, 16],
       [ 1,  3,  9, 27, 81]])

>>> df[[[[[[[["X", "y"]].to_numpy().base est df.to_numpy().base
Faux

La copie a un autre .base que df.

Dans la section suivante, vous trouverez plus de détails sur l'indexation des DataFrames et le retour des vues et des copies. Vous verrez des cas où le comportement des Pandas devient plus complexe et diffère de NumPy.

Utilisation des vues et des copies dans les pandas

Comme vous l’avez déjà appris, les pandas peuvent émettre un SettingWithCopyWarning lorsque vous essayez de modifier la copie des données au lieu de l'original. Cela suit souvent l'indexation chaînée.

Dans cette section, vous verrez des cas spécifiques qui produisent un SettingWithCopyWarning. Vous identifierez les causes et apprendrez à les éviter en utilisant correctement les vues, les copies et les accesseurs.

Indexation chaînée et SettingWithCopyWarning

Vous avez déjà vu comment SettingWithCopyWarning fonctionne avec l'indexation chaînée dans le premier exemple. Développons un peu cela.

Vous avez créé le DataFrame et le masque Séries objet qui correspond à df["z"] <50:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)
>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

>>> masque = df[[[["z"] < 50
>>> masque
une véritable
b Faux
c Vrai
d Vrai
e Faux
Nom: z, dtype: bool

Vous savez déjà que la mission df[mask]["z"] = 0 échoue. Dans ce cas, vous obtenez un SettingWithCopyWarning:

>>>

>>> df[[[[masque][[[["z"] = 0
__main __: 1: SettingWithCopyWarning:
Une valeur tente d'être définie sur une copie d'une tranche à partir d'un DataFrame.
Essayez d'utiliser .loc[row_indexer,col_indexer] = valeur à la place

Voir les mises en garde dans la documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
                x y z
a 1 1 45
b 2 3 98
c 4 9 24
d 8 27 11
e 16 81 64

L'affectation échoue car df[mask] renvoie une copie. Pour être plus précis, la cession est faite sur la copie, et df n'est pas affecté.

Vous avez également vu que dans Pandas, l'ordre d'évaluation est important. Dans certains cas, vous pouvez changer l'ordre des opérations pour faire fonctionner le code:

>>>

>>> df[[[["z"][[[[masque] = 0
>>> df
                x y z
a 1 1 0
b 2 3 98
c 4 9 0
d 8 27 0
e 16 81 64

df["z"][mask] = 0 réussit et vous obtenez le modifié df sans un SettingWithCopyWarning.

L'utilisation des accesseurs est recommandée, mais vous pouvez également rencontrer des problèmes avec:

>>>

>>> df = pd.Trame de données(Les données=Les données, indice=indice)
>>> df.loc[[[[masque][[[["z"] = 0
__main __: 1: SettingWithCopyWarning:
Une valeur tente d'être définie sur une copie d'une tranche à partir d'un DataFrame.
Essayez d'utiliser .loc[row_indexer,col_indexer] = valeur à la place

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
>>> df
                x   y   z
a   1   1  45
b   2   3  98
c   4   9  24
d   8  27  11
e  16  81  64

Dans ce cas, df.loc[mask] returns a copy, the assignment fails, and Pandas correctly issues the warning.

In some cases, Pandas fails to detect the problem and the assignment on the copy passes without a SettingWithCopyWarning:

>>>

>>> df = pd.DataFrame(Les données=Les données, indice=indice)
>>> df.loc[[[[[[[["a", "c", "e"]][[[["z"] = 0  # Assignment fails, no warning
>>> df
                x   y   z
a   1   1  45
b   2   3  98
c   4   9  24
d   8  27  11
e  16  81  64

Here, you don’t receive a SettingWithCopyWarning et df isn’t changed because df.loc[["a", "c", "e"]] uses a list of indices and returns a copy, not a view.

There are some cases in which the code works, but Pandas issues the warning anyway:

>>>

>>> df = pd.DataFrame(Les données=Les données, indice=indice)
>>> df[:[:[:[:3][[[["z"] = 0  # Assignment succeeds, with warning
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
                x   y   z
a   1   1   0
b   2   3   0
c   4   9   0
d   8  27  11
e  16  81  64

>>> df = pd.DataFrame(Les données=Les données, indice=indice)
>>> df.loc[[[["a":"c"][[[["z"] = 0  # Assignment succeeds, with warning
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
>>> df
                x   y   z
a   1   1   0
b   2   3   0
c   4   9   0
d   8  27  11
e  16  81  64

In these two cases, you select the first three rows with slices and get views. The assignments succeed both on the views and on df. But you still receive a SettingWithCopyWarning.

The recommended way of performing such operations is to avoid chained indexing. Accessors can be of great help with that:

>>>

>>> df = pd.DataFrame(Les données=Les données, indice=indice)
>>> df.loc[[[[mask, "z"] = 0
>>> df
                x   y   z
a   1   1   0
b   2   3  98
c   4   9   0
d   8  27   0
e  16  81  64

This approach uses one method call, without chained indexing, and both the code and your intentions are clearer. As a bonus, this is a slightly more efficient way to assign data.

Impact of Data Types on Views, Copies, and the SettingWithCopyWarning

In Pandas, the difference between creating views and creating copies also depends on the data types used. When deciding if it’s going to return a view or copy, Pandas handles DataFrames that have a single data type differently from ones with multiple types.

Let’s focus on the data types in this example:

>>>

>>> df = pd.DataFrame(Les données=Les données, indice=indice)

>>> df
                x   y   z
a   1   1  45
b   2   3  98
c   4   9  24
d   8  27  11
e  16  81  64

>>> df.dtypes
x    int64
y    int64
z    int64
dtype: object

You’ve created the DataFrame with all integer columns. The fact that all three columns have the same data types is important here! In this case, you can select rows with a slice and get a view:

>>>

>>> df[[[["b":"d"][[[["z"] = 0
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
                x   y   z
a   1   1  45
b   2   3   0
c   4   9   0
d   8  27   0
e  16  81  64

This mirrors the behavior that you’ve seen in the article so far. df["b":"d"] returns a view and allows you to modify the original data. That’s why the assignment df["b":"d"]["z"] = 0 succeeds. Notice that in this case you get a SettingWithCopyWarning regardless of the successful change to df.

If your DataFrame contains columns of different types, then you might get a copy instead of a view, in which case the same assignment will fail:

>>>

>>> df = pd.DataFrame(Les données=Les données, indice=indice).astype(dtype="z": float)
>>> df
                x   y     z
a   1   1  45.0
b   2   3  98.0
c   4   9  24.0
d   8  27  11.0
e  16  81  64.0

>>> df.dtypes
x      int64
y      int64
z    float64
dtype: object

>>> df[[[["b":"d"][[[["z"] = 0
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
                x   y     z
a   1   1  45.0
b   2   3  98.0
c   4   9  24.0
d   8  27  11.0
e  16  81  64.0

In this case, you used .astype() to create a DataFrame that has two integer columns and one floating-point column. Contrary to the previous example, df["b":"d"] now returns a copy, so the assignment df["b":"d"]["z"] = 0 fails and df remains unchanged.

When in doubt, avoid the confusion and use the .loc[], .iloc[], .at[], et .iat[] access methods throughout your code!

Hierarchical Indexing and SettingWithCopyWarning

Hierarchical indexing, or MultiIndex, is a Pandas feature that enables you to organize your row or column indices on multiple levels according to a hierarchy. It’s a powerful feature that increases the flexibility of Pandas and enables working with data in more than two dimensions.

Hierarchical indices are created using tuples as row or column labels:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64]),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df
        powers     random
                            x   y      z
a      1   1     45
b      2   3     98
c      4   9     24
d      8  27     11
e     16  81     64

Now you have the DataFrame df with two-level column indices:

  1. The first level contains the labels powers et random.
  2. The second level has the labels X et y, which belong to powers, et z, which belongs to random.

The expression df["powers"] will return a DataFrame containing all columns below powers, which are the columns X et y. If you wanted to get just the column X, then you could pass both powers et X. The proper way to do this is with the expression df["powers", "x"]:

>>>

>>> df[[[["powers"]
                x   y
a   1   1
b   2   3
c   4   9
d   8  27
e  16  81

>>> df[[[["powers", "x"]
a     1
b     2
c     4
d     8
e    16
Name: (powers, x), dtype: int64

>>> df[[[["powers", "x"] = 0
>>> df
        powers     random
                            x   y      z
a      0   1     45
b      0   3     98
c      0   9     24
d      0  27     11
e      0  81     64

That’s one way to get and set columns in the case of multilevel column indices. You can also use accessors with multi-indexed DataFrames to get or modify the data:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64]),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df.loc[[[[[[[["a", "b"], "powers"]
            x  y
a  1  1
b  2  3

The example above uses .loc[] to return a DataFrame with the rows une et b and the columns X et y, which are below powers. You can get a particular column (or row) similarly:

>>>

>>> df.loc[[[[[[[["a", "b"], ("powers", "x")]
a    1
b    2
Name: (powers, x), dtype: int64

In this example, you specify that you want the intersection of the rows une et b with the column X, which is below powers. To get a single column, you pass the tuple of indices ("powers", "x") et obtenez un Séries object as the result.

You can use this approach to modify the elements of DataFrames with hierarchical indices:

>>>

>>> df.loc[[[[[[[["a", "b"], ("powers", "x")] = 0
>>> df
        powers     random
                            x   y      z
a      0   1     45
b      0   3     98
c      4   9     24
d      8  27     11
e     16  81     64

In the examples above, you avoid chained indexing both with accessors (df.loc[["a", "b"], ("powers", "x")]) and without them (df["powers", "x"]).

As you saw earlier, chained indexing can lead to a SettingWithCopyWarning:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64]),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df
        powers     random
                            x   y      z
a      1   1     45
b      2   3     98
c      4   9     24
d      8  27     11
e     16  81     64

>>> df[[[["powers"]
                x   y
a   1   1
b   2   3
c   4   9
d   8  27
e  16  81

>>> df[[[["powers"][[[["x"] = 0
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
        powers     random
                            x   y      z
a      0   1     45
b      0   3     98
c      0   9     24
d      0  27     11
e      0  81     64

Ici, df["powers"] returns a DataFrame with the columns X et y. This is just a view that points to the data from df, so the assignment is successful and df is modified. But Pandas still issues a SettingWithCopyWarning.

If you repeat the same code, but with different data types in the columns of df, then you’ll get a different behavior:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64], dtype=float),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df
        powers     random
                            x   y      z
a      1   1   45.0
b      2   3   98.0
c      4   9   24.0
d      8  27   11.0
e     16  81   64.0

>>> df[[[["powers"]
                x   y
a   1   1
b   2   3
c   4   9
d   8  27
e  16  81

>>> df[[[["powers"][[[["x"] = 0
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

>>> df
        powers     random
                            x   y      z
a      1   1   45.0
b      2   3   98.0
c      4   9   24.0
d      8  27   11.0
e     16  81   64.0

This time, df has more than one data type, so df["powers"] returns a copy, df["powers"]["x"] = 0 makes a change on this copy, and df remains unchanged, giving you a SettingWithCopyWarning.

The recommended way to modify df is to avoid chained assignment. You’ve learned that accessors can be very convenient, but they aren’t always needed:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64], dtype=float),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df[[[["powers", "x"] = 0
>>> df
        powers     random
                            x   y      z
a      0   1     45
b      0   3     98
c      0   9     24
d      0  27     11
e      0  81     64

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64], dtype=float),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> df.loc[:[:[:[: ("powers", "x")] = 0
>>> df
        powers     random
                            x   y      z
a      0   1   45.0
b      0   3   98.0
c      0   9   24.0
d      0  27   11.0
e      0  81   64.0

In both cases, you get the modified DataFrame df without a SettingWithCopyWarning.

Change the Default SettingWithCopyWarning Behavior

le SettingWithCopyWarning is a warning, not an error. Your code will still execute when it’s issued, even though it may not work as intended.

To change this behavior, you can modify the Pandas mode.chained_assignment option with pandas.set_option(). You can use the following settings:

  • pd.set_option("mode.chained_assignment", "raise") raises a SettingWithCopyException.
  • pd.set_option("mode.chained_assignment", "warn") issues a SettingWithCopyWarning. This is the default behavior.
  • pd.set_option("mode.chained_assignment", None) suppresses both the warning and the error.

For example, this code will raise a SettingWithCopyException instead of issuing a SettingWithCopyWarning:

>>>

>>> df = pd.DataFrame(
...     Les données=("powers", "x"): 2**np.arange(5),
...           ("powers", "y"): 3**np.arange(5),
...           ("random", "z"): np.tableau([[[[45, 98, 24, 11, 64], dtype=float),
...     indice=[[[["a", "b", "c", "d", "e"]
... )

>>> pd.set_option("mode.chained_assignment", "raise")

>>> df[[[["powers"][[[["x"] = 0

In addition to modifying the default behavior, you can use get_option() to retrieve the current setting related to mode.chained_assignment:

>>>

>>> pd.get_option("mode.chained_assignment")
'raise'

You get "raise" in this case because you changed the behavior with set_option(). Normalement, pd.get_option("mode.chained_assignment") returns "warn".

Although you can suppress it, keep in mind that the SettingWithCopyWarning can be very useful in notifying you about improper code.

Conclusion

In this article, you learned what views and copies are in NumPy and Pandas and what the differences are in their behavior. You also saw what a SettingWithCopyWarning is and how to avoid the subtle errors it points to.

In particular, you’ve learned the following:

  • Indexing-based assignments in NumPy and Pandas can return either views ou copies.
  • Both views and copies can be useful, but they have different behaviors.
  • Special care must be taken to avoid setting unwanted values on copies.
  • Accessors in Pandas are very useful objects for properly assigning and referencing data.

Understanding views and copies is an important requirement for using NumPy and Pandas properly, especially when you’re working with big data. Now that you have a solid grasp on these concepts, you’re ready to dive deeper into the exciting world of data science!

If you have questions or comments, then please put them in the comment section below.