Modification d'un sous-ensemble de lignes dans un DataFrame pandas

Supposons que j'ai un DataFrame pandas avec deux colonnes, A et B. Je voudrais modifier ce DataFrame (ou créer une copie) de sorte que B soit toujours NaN chaque fois que A est 0. Comment pourrais-je y parvenir?

J'ai essayé ce qui suit

df['A'==0]['B'] = np.nan

Et

df['A'==0]['B'].values.fill(np.nan)

Sans succès.

99
demandé sur Arthur B. 2012-09-06 23:32:25

5 réponses

Mise à Jour

ix est obsolète, utilisez .loc pour l'étiquette de l'indexation en fonction de

df.loc[df.A==0, 'B'] = np.nan

, Essayez ceci:

df.ix[df.A==0, 'B'] = np.nan

L'expression df.A==0 crée une série booléenne qui indexe les lignes, 'B' sélectionne la colonne. Vous pouvez également l'utiliser pour transformer un sous-ensemble d'une colonne, par exemple:

df.ix[df.A==0, 'B'] = df.ix[df.A==0, 'B'] / 2

Je n'en sais pas assez sur les internes des pandas pour savoir exactement pourquoi cela fonctionne, mais le problème de base est que parfois l'indexation dans un DataFrame renvoie une copie du résultat, et parfois, il renvoie une vue sur l'objet d'origine. Selon la documentation ici, ce comportement dépend du comportement numpy sous-jacent. J'ai trouvé que l'accès à tout en une seule opération (plutôt que [un] [deux]) est plus susceptible de fonctionner pour le réglage.

182
répondu BrenBarn 2018-07-04 23:35:49

Ici est de pandas docs sur l'indexation avancée:

La section vous expliquera exactement ce dont vous avez besoin! S'avère df.loc (comme .ix a été déprécié - comme beaucoup l'ont souligné ci-dessous) peut être utilisé pour refroidir le découpage/découpage d'un dataframe. Et. Il peut également être utilisé pour définir les choses.

df.loc[selection criteria, columns I want] = value

, de Sorte Bren réponse est de dire " trouvez-moi tous les endroits où df.A == 0, sélectionnez la colonne B et réglez - np.nan'

67
répondu badgley 2017-09-15 18:52:21

À partir de pandas 0.20 ix est obsolète. La bonne façon est d'utiliser loc

Voici un exemple de travail

>>> import pandas as pd 
>>> import numpy as np 
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN
>>> 

Explication:

, Comme expliqué dans la doc ici, .loc est principalement label, mais peut également être utilisé avec un booléen tableau.

Donc, ce que nous faisons ci-dessus s'applique df.loc[row_index, column_index] par:

  • exploiter le fait que loc peut prendre un tableau booléen comme un masque qui indique aux pandas quel sous-ensemble de lignes nous voulons changer dans row_index
  • L'exploitation du fait loc est également basée sur l'étiquette pour sélectionner la colonne en utilisant l'étiquette 'B' dans le column_index

Nous pouvons utiliser logical, condition ou n'importe quelle opération qui renvoie une série de booléens pour construire le tableau de booléens. Dans l'exemple ci-dessus, nous voulons tout rows qui contiennent un 0, pour que nous puissions utiliser df.A == 0, comme vous pouvez le voir dans l'exemple ci-dessous, cela renvoie à une série de valeurs booléennes.

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df 
   A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0 
0     True
1    False
2     True
Name: A, dtype: bool
>>> 

Ensuite, nous utilisons le tableau ci-dessus de booléens pour sélectionner et modifier les lignes nécessaires:

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN

Pour plus d'informations, consultez la documentation d'indexation avancée ici.

22
répondu MedAli 2018-05-24 06:06:45

Pour une augmentation massive de la vitesse, Utilisez la fonction Where de NumPy.

Configuration

Créez un DataFrame à deux colonnes avec 100 000 lignes avec quelques zéros.

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

Solution Rapide avec numpy.where

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

Timings

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy's where est environ 4 fois plus rapide

2
répondu Ted Petrou 2017-11-02 23:18:25

Pour remplacer les colonnes multiples convertir en tableau numpy en utilisant .values:

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
1
répondu Adrien Renaud 2017-10-25 04:22:16