web-dev-qa-db-fra.com

Python pandas applique la fonction si une valeur de colonne n'est pas NULL)

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!

21
ragesz

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.

20
Korem

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 :-)

enter image description here

3
Aziz Alto

J'avais une colonne contenant des listes et NaNs. Donc, le suivant a fonctionné pour moi.

df.C.map(lambda x: my_func(x) if type(x) == list else x)
3
coffman21

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

0
Andrew Monger