J'ai une trame de données (en Python 2.7, pandas 0.15.0):
df=
A B C
0 NaN 11 NaN
1 two NaN ['foo', 'bar']
2 three 33 NaN
Je veux appliquer une fonction simple pour les lignes qui ne contiennent pas de valeurs NULL dans une colonne spécifique. Ma fonction est aussi simple que possible:
def my_func(row):
print row
Et mon code d'application est le suivant:
df[['A','B']].apply(lambda x: my_func(x) if(pd.notnull(x[0])) else x, axis = 1)
Cela fonctionne parfaitement. Si je veux vérifier la colonne 'B' pour les valeurs NULL, la pd.notnull()
fonctionne aussi parfaitement. Mais si je sélectionne la colonne 'C' qui contient des objets de liste:
df[['A','C']].apply(lambda x: my_func(x) if(pd.notnull(x[1])) else x, axis = 1)
alors j'obtiens le message d'erreur suivant: ValueError: ('The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()', u'occurred at index 1')
Est-ce que quelqu'un sait pourquoi pd.notnull()
ne fonctionne que pour les colonnes entières et chaînes mais pas pour les "colonnes de liste"?
Et existe-t-il une meilleure façon de vérifier les valeurs NULL dans la colonne 'C' au lieu de cela:
df[['A','C']].apply(lambda x: my_func(x) if(str(x[1]) != 'nan') else x, axis = 1)
Merci!
Le problème est que pd.notnull(['foo', 'bar'])
fonctionne par élément et renvoie array([ True, True], dtype=bool)
. Votre condition if essaie de convertir cela en booléen, et c'est là que vous obtenez l'exception.
Pour le corriger, vous pouvez simplement envelopper l'instruction isnull avec np.all
:
df[['A','C']].apply(lambda x: my_func(x) if(np.all(pd.notnull(x[1]))) else x, axis = 1)
Vous allez maintenant voir que np.all(pd.notnull(['foo', 'bar']))
est bien True
.
Une autre façon est également d'utiliser simplement row.notnull().all()
(sans numpy
), voici un exemple:
df.apply(lambda row: func1(row) if row.notnull().all() else func2(row), axis=1)
Voici un exemple complet sur votre df:
>>> d = {'A': [None, 2, 3, 4], 'B': [11, None, 33, 4], 'C': [None, ['a','b'], None, 4]}
>>> df = pd.DataFrame(d)
>>> df
A B C
0 NaN 11.0 None
1 2.0 NaN [a, b]
2 3.0 33.0 None
3 4.0 4.0 4
>>> def func1(r):
... return 'No'
...
>>> def func2(r):
... return 'Yes'
...
>>> df.apply(lambda row: func1(row) if row.notnull().all() else func2(row), axis=1)
0 Yes
1 Yes
2 Yes
3 No
Et une capture d'écran plus conviviale :-)
J'avais une colonne contenant des listes et NaN
s. Donc, le suivant a fonctionné pour moi.
df.C.map(lambda x: my_func(x) if type(x) == list else x)
Essayer...
df['a'] = df['a'].apply(lambda x: x.replace(',','\,') if x != None else x)
cet exemple ajoute simplement un caractère d'échappement à une virgule si la valeur n'est pas None