2017-09-14 2 views
1

Je veux utiliser unique en groupby agrégation, mais je ne veux pas nan dans le résultat unique.Python pandas valeur unique ignorer NaN

Un exemple dataframe:

df = pd.DataFrame({'a': [1, 2, 1, 1, pd.np.nan, 3, 3], 'b': [0,0,1,1,1,1,1], 
    'c': ['foo', pd.np.nan, 'bar', 'foo', 'baz', 'foo', 'bar']}) 

     a b c 
0 1.0000 0 foo 
1 2.0000 0 NaN 
2 1.0000 1 bar 
3 1.0000 1 foo 
4 nan 1 baz 
5 3.0000 1 foo 
6 3.0000 1 bar 

Et le groupby:

df.groupby('b').agg({'a': ['min', 'max', 'unique'], 'c': ['first', 'last', 'unique']}) 

Il en résulte est:

 a        c      
    min max   unique first last   unique 
b               
0 1.0000 2.0000  [1.0, 2.0] foo foo  [foo, nan] 
1 1.0000 3.0000 [1.0, nan, 3.0] bar bar [bar, foo, baz] 

Mais je veux sans nan:

 a      c      
    min max  unique first last   unique 
b               
0 1.0000 2.0000 [1.0, 2.0] foo foo   [foo] 
1 1.0000 3.0000 [1.0, 3.0] bar bar [bar, foo, baz] 

Comment puis-je faire cela? Bien sûr, j'ai plusieurs colonnes à agréger et chaque colonne a besoin de différentes fonctions d'agrégation, donc je ne veux pas faire les agrégations unique une par une et séparément des autres agrégations.

Merci!

Répondre

4

est-ce que ffill aidera?

df.ffill().groupby('b').agg({'a': ['min', 'max', 'unique'], 'c': ['first', 'last', 'unique']}) 
 
     c       a     
    first last   unique min max  unique 
b             
0 foo foo   [foo] 1.0 2.0 [1.0, 2.0] 
1 bar bar [bar, foo, baz] 1.0 3.0 [1.0, 3.0] 

Il y a des chances que vous pourriez avoir Nan dans la première rangée. Dans ce cas, le simple ffill() ne suffit pas, donc vous pourriez aussi avoir besoin de bfill(). i.e

df.bfill().ffill().groupby('b').agg({'a': ['min', 'max', 'unique'], 'c': ['first', 'last', 'unique']}) 

Comme indiqué par @ T.C. Proctor ffill() ne fonctionnera pas si les valeurs de chaque groupe sont uniques et qu'il existe un nan dans la première ligne de certains groupes. Donc, soit vous devez aller pour pour chaque groupe ou laisser tomber les nans comme suggéré par @IanS. Un exemple cas:

df = pd.DataFrame({'a': [1, 2, 1, 1, pd.np.nan, 3, 3], 'b': [0,0,1,1,1,1,1], 
'c': [np.nan, 'damn', np.nan, 'foo', 'baz', 'foo', 'bar']}) 

df = df.groupby('b').ffill().bfill() 
df.groupby('b').agg({'a': ['min', 'max', 'unique'], 'c': ['first', 'last', 'unique']}) 
 

    a      c      
    min max  unique first last   unique 
b             
0 1.0 2.0 [1.0, 2.0] damn damn   [damn] 
1 1.0 3.0 [1.0, 3.0] foo bar [foo, baz, bar] 

+2

Merci à vous tous, je pense que [Bharath shetty] (https://stackoverflow.com/users/4800652/bharath-shetty) a la solution la plus simple et pythonique. Merci encore!! – ragesz

+0

C'est une solution terrible. C'est tout simplement faux. Il arrive seulement de travailler pour cet exemple parce que les valeurs au-dessus des NaN se trouvent dans ce groupe. –

+0

@ T.C.Proctor oui la solution mise à jour va-t-elle passer d'une solution terrible à une solution Ohk? – Dark

4

Définition d'une fonction:

def unique_non_null(s): 
    return s.dropna().unique() 

utiliser ensuite dans l'agrégation:

df.groupby('b').agg({ 
    'a': ['min', 'max', unique_non_null], 
    'c': ['first', 'last', unique_non_null] 
}) 
4

Cela fonctionne pour ce dont vous avez besoin:

df.fillna(method='ffill').groupby('b').agg({'a': ['min', 'max', 'unique'], 'c': ['first', 'last', 'unique']}) 

Parce que vous utilisez min, max et unique les valeurs répétées ne vous concernent pas.

+0

aussi 'df.ffill() ..' – Zero

+0

@Bharathshetty Pour être honnête, j'ai vu la réponse de zipa apparaître en premier. Parfois, le moment auquel les réponses apparaissent est un peu aléatoire. – IanS

+0

@Bharathshetty Je ne l'ai pas vu, mais maintenant que je t'ai eu un +1 :) – zipa