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.
Remarque: Cet article vous oblige à avoir une connaissance préalable des Pandas. Vous aurez également besoin d'une certaine connaissance de NumPy pour les sections suivantes.
Pour actualiser vos compétences NumPy, vous pouvez consulter les ressources suivantes:
Pour vous souvenir des Pandas, vous pouvez lire ce qui suit:
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:
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 dansdf
dans lequel la valeur dez
est inférieur à50
.Faux
indique les lignes dansdf
dans lequel la valeur dez
est ne pas moins que50
.
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 ré
.
Si vous essayez de changer df
en extrayant des lignes une
, c
, et ré
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:
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 dedf
qui correspondent àVrai
valeurs demasque
(surligné en vert).df[mask]["z"] = 0
modifie la colonnez
du nouveau DataFrame à zéros, laissantdf
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:
Voici une ventilation de l'image ::
df["z"]
renvoie unSéries
objet (souligné en violet) qui pointe vers le mêmes données comme colonnez
dansdf
, pas sa copie.df["z"][mask] = 0
modifie celaSé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 laSéries
objetdf["z"]
contient les mêmes données quedf
.
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:
- L'intention de modifier
df
est plus clair pour Pandas lorsque vous utilisez une seule méthode. - Le code est plus propre pour les lecteurs.
- 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
etdf.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:
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:
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:
- Les vues n'ont pas besoin de stockage supplémentaire pour les données, mais les copies en ont besoin.
- 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:
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
:
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.
Remarque: Lorsque vous avez un grand tableau d'origine et que vous n'en avez besoin que d'une petite partie, vous pouvez appeler .copie()
après avoir coupé et supprimé la variable qui pointe vers l'original avec un del
déclaration. De cette façon, vous conservez la copie et supprimez la matrice d'origine de la mémoire.
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:
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]
>>> ré = arr[[[[masque]
>>> ré
tableau ([2, 8])
>>> ré.base est Aucun
Vrai
>>> ré.drapeaux.owndata
Vrai
La liste masque
a Vrai
valeurs aux deuxième et quatrième positions. C'est pourquoi le tableau ré
ne contient que les éléments des deuxième et quatrième positions de arr
. Comme dans le cas de c
, ré
est une copie, son .base
est Aucun
, et il possède ses propres données:
Les éléments de arr
dans les rectangles verts correspondent à Vrai
valeurs de masque
. Ces éléments sont copiés dans le nouveau tableau ré
. Après avoir copié, arr
et ré
sont indépendants.
Remarque: Au lieu d'une liste, vous pouvez utiliser un autre tableau NumPy d'entiers, mais ne pas un tuple.
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]]
ré = 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])
>>> ré
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 ré
. Cependant, seules les vues une
et b
sont modifiés:
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 ré
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
>>> ré = arr[:[:[:[: [[[[Faux, Vrai, Faux, Vrai]] # Prenez les colonnes 1 et 3
>>> ré
tableau ([[ 2, 8],
[ 32, 128],
[ 512, 2048]])
>>> ré.base
tableau ([[ 2, 32, 512],
[ 8, 128, 2048]])
>>> ré.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 ré
.
le .base
des deux une
et b
est arr
lui-même. Tous les deux c
et ré
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]])
>>> ré
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 ré
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:
- The first level contains the labels
powers
etrandom
. - The second level has the labels
X
ety
, which belong topowers
, etz
, which belongs torandom
.
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 aSettingWithCopyException
.pd.set_option("mode.chained_assignment", "warn")
issues aSettingWithCopyWarning
. 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.
[ad_2]