Supposons que j’ai un pandas _ DataFrame avec deux colonnes, A et B. Je souhaite modifier ce DataFrame (ou en créer une copie) afin que B soit toujours NaN chaque fois que A est égal à 0. Comment y arriverais-je? ?
J'ai essayé le suivant
df['A'==0]['B'] = np.nan
et
df['A'==0]['B'].values.fill(np.nan)
sans succès.
Utilisez .loc
pour l'indexation basée sur une étiquette:
_df.loc[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.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2
_
Je ne connais pas suffisamment les pandas internals pour savoir exactement pourquoi cela fonctionne, mais le problème fondamental est que, parfois, l'indexation dans un DataFrame renvoie une copie du résultat et renvoie parfois une vue sur l'objet d'origine. . Selon la documentation ici , ce comportement dépend du comportement sous-jacent de numpy. J'ai constaté que tout accéder à une seule opération (plutôt que [un] [deux]) est plus susceptible de fonctionner pour le réglage.
Ici provient de pandas docs sur l'indexation avancée:
La section expliquera exactement ce dont vous avez besoin! Il s'avère que df.loc
(comme .ix est obsolète - comme beaucoup l'ont souligné ci-dessous) peut être utilisé pour découper/découper à froid une trame de données. Et. Il peut également être utilisé pour régler les choses.
df.loc[selection criteria, columns I want] = value
La réponse de Bren est donc la suivante: "Trouvez-moi tous les endroits où df.A == 0
, sélectionnez la colonne B
et réglez-le sur np.nan
'
À partir de pandas 0.20 ix est obsolète . La bonne façon est d'utiliser df.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
>>>
Comme expliqué dans la doc ici , .loc
est principalement basé sur des étiquettes, mais peut également être utilisé avec un tableau booléen .
Donc, ce que nous faisons ci-dessus applique df.loc[row_index, column_index]
en:
loc
peut prendre un tableau booléen comme masque qui indique à pandas quel sous-ensemble de lignes nous voulons modifier dans row_index
loc
est également basé sur une étiquette pour sélectionner la colonne en utilisant l’étiquette 'B'
dans le column_index
Nous pouvons utiliser une opération logique, conditionnelle ou toute opération renvoyant une série de booléens pour construire le tableau de booléens. Dans l'exemple ci-dessus, nous voulons que toute rows
contenant un 0
, pour cela, nous pouvons utiliser df.A == 0
, comme vous pouvez le voir dans l'exemple ci-dessous, cela retourne une série de booléens.
>>> 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 de booléens ci-dessus 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 de vitesse massive, utilisez la fonction où de NumPy's.
Créez un DataFrame à deux colonnes avec 100 000 lignes avec des zéros.
df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))
numpy.where
df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
%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 4x plus rapide
Pour remplacer plusieurs colonnes, convertissez-les en tableau numpy à l’aide de .values
:
df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2