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.
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.
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
'
À 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 dansrow_index
- L'exploitation du fait
loc
est également basée sur l'étiquette pour sélectionner la colonne en utilisant l'étiquette'B'
dans lecolumn_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.
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
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