[PYTHON] Soyez prudent lorsque vous attribuez une série en tant que colonne aux pandas.

Si vous essayez d'ajouter une série à une trame de données pandas, elle se comporte comme une jointure, alors soyez prudent.

Avant

Lors du traitement de données avec des pandas, le processus d'ajout de colonnes à une trame de données est fréquent. Il existe deux méthodes principales pour ajouter des colonnes à un dayframe.

  1. Ajoutez une colonne en spécifiant le nom de la colonne
  2. Ajouter avec la méthode pd.DataFrame.assign

** 1. Ajoutez une colonne en spécifiant le nom de la colonne **

df['new_col'] = data

** 2. Ajouter une colonne à l'aide de la méthode assign **

df.assign(new_col=data)

Dans les deux cas, vous pouvez transmettre une liste de valeurs égales, de tailles, np.array, pd.Series, etc.

Comportement intuitif qui se produit lors de la substitution d'une série

Préparez une série avec le même nombre d'enregistrements que n'importe quelle trame de données.

df = pd.DataFrame(
    [[1,2,3], [4,5,6], [7,8,9]],
    columns=['a', 'b', 'c'],
    index=[1,2,3]
)
sr = pd.Series([-1, -2, -3])

df
#   	a 	b 	c
# 1 	1 	2 	3
# 2 	4 	5 	6
# 3 	7 	8 	9

sr
# 0   -1
# 1   -2
# 2   -3
# dtype: int64

Si vous voulez ajouter les données de sr en tant que nouvelle colonne'd' à df, procédez comme suit.

df = df.assign(d=sr)

J'espère qu'une telle table sera créée.

a b c d
1 1 2 3 -1
2 4 5 6 -2
3 7 8 9 -3

Cependant, en réalité, une telle trame de données est renvoyée.

a b c d
1 1 2 3 -2
2 4 5 6 -3
3 7 8 9 NaN

Que se passe-t-il

Lorsque vous comparez à nouveau le bloc de données et la série, les index des deux ne correspondent pas. Avec de telles données, vous pouvez voir que même dans le cas d'une affectation, cela se comporte comme une jointure.

solution de contournement

Cela peut être évité en le passant comme np.array.

df.assign(new_col=new_series.values)

Remarque: En ce qui concerne le Document officiel, la méthode to_numpy est utilisée plutôt que la méthode values. Il est recommandé de le faire. Cela ressemble à ceci pour distinguer clairement l''Extension Arary 'ajoutée dans 0.24 des pandas.

Pourquoi cela arrive

Tout d'abord, la méthode pd.DataFrame.assign est uniquement appelée en interne pour le processus 1 affiché au début si la valeur passée n'est pas appelable. Par conséquent, un phénomène comme celui-ci se produit dans les deux méthodes.

(Au fait, "la valeur passée est appelable" correspond au cas de l'appel de la colonne du bloc de données lui-même avec une expression lambda etc.) [^ callable]

Si vous essayez d'affecter quelque chose comme df ['X'] = hogehoge,pd.DataFrame .__ setitem__ ()sera appelé. En suivant le code, j'ai trouvé la docstring suivante. [^ setitem]

        """
        Add series to DataFrame in specified column.
        If series is a numpy-array (not a Series/TimeSeries), it must be the
        same length as the DataFrames index or an error will be thrown.
        Series/TimeSeries will be conformed to the DataFrames index to
        ensure homogeneity.
        """

En d'autres termes, les données transmises sont

Il est indiqué qu'il sera traité de cette manière. Si vous suivez le code plus loin, vous pouvez voir que les données sont triées selon l'index du bloc de données avant d'être ajoutées. [^ réindexer]

Ce phénomène a été causé en pensant à la série de la même manière qu'un tableau. Comme vous pouvez le voir ci-dessous, nous avons également constaté que la taille de la série ne devait même pas correspondre à l'enregistrement dans le bloc de données à ajouter, elle était complètement différente de la liste ou du tableau.

df.assign(
    x=pd.Series([3], index=[2])
)
#  	 	a 	b 	c 	x
# 1 	1 	2 	3 	NaN
# 2 	4 	5 	6 	3.0
# 3 	7 	8 	9 	NaN

Résumé

N'ajoutez pas de données unidimensionnelles de même taille à un bloc de données comme une liste ou un tableau. Lors de l'affectation d'une série à une colonne d'une trame de données, le processus se déroule sans erreur même si la taille est différente, il semble donc que le risque de créer un bogue sans s'en apercevoir augmente. J'ai toujours averti que je le convertirais en numpy-array et effectuerais le processus d'attribution.

Recommended Posts

Soyez prudent lorsque vous attribuez une série en tant que colonne aux pandas.
Soyez prudent lors de l'ajout d'un tableau à un tableau
Remarque Python: lors de l'attribution d'une valeur à une chaîne
Soyez prudent lors de la différenciation des vecteurs propres d'une matrice
Que faire lorsque des séries booléennes non alignables sont fournies comme indexeur
Soyez prudent lorsque vous spécifiez la valeur d'argument par défaut dans la série Python 3
Que faire lorsqu'une vidéo ne peut pas être lue par cv2.VideoCapture
Comment bien définir Jupytext lors de la gestion du code en équipe
[Python] Soyez prudent lorsque vous utilisez print
Choses à prendre en compte lors de la création d'un système de recommandation avec Item2Vec
Lorsque vous souhaitez remplacer une colonne par une valeur manquante (NaN) colonne par colonne
[Mémo Python] Soyez prudent lors de la création d'un tableau à deux dimensions (liste de listes)
Dans pandas.DataFrame, même lors de l'attribution d'une seule colonne spécifique, si l'index est attaché, vous n'avez pas à vous soucier de l'ordre des données
Soyez prudent lorsque vous exécutez CakePHP3 avec PHP7.2
[Linux] [module noyau] Comment passer des paramètres comme arguments lors du chargement d'un module noyau chargeable
Comment gérer les arguments lors de l'implémentation d'un script Python en tant qu'outil de ligne de commande