2016-11-14 2 views
3

Ich beantrage qcut auf groupby Ergebnisse, eine vereinfachte Version meines Problems ist folgende:Fortsetzung von qcut für die nächste groupby-Gruppe, falls fehlgeschlagen?

a = pd.DataFrame({'A':[1,1,1,1,2,2,2,2], 
        'B': [0,0,0,0,2,3,7,6]}) 
a.groupby(['A'])['B'].apply(lambda x: pd.qcut(x, 2)) 

Das Problem ist, ein Teil der Gruppe wirft Valueerror weil

raise ValueError('Bin edges must be unique: %s' % repr(bins)) 
ValueError: Bin edges must be unique: array([ 0., 0., 0.]) 

Was ich erreichen möchte ist, Wenn qcut fehlschlägt, überspringe (oder übergebe 0 als Ergebnis) und führe die qcut für die nächste Gruppe fort. irgendwelche Vorschläge?

Antwort

2

Kleine Variation @ JohnE Antwort auf uns erlauben, die apply Syntax zu halten.

def try_qcut(x,n): 
    try: 
     return pd.qcut(x,n) 
    except ValueError: 
     return x*np.nan 

a.groupby('A')['B'].apply(lambda x: try_qcut(x, 2)) 

0   NaN 
1   NaN 
2   NaN 
3   NaN 
4 [2, 4.5] 
5 [2, 4.5] 
6 (4.5, 7] 
7 (4.5, 7] 
Name: B, dtype: object 
+0

Schön! Ich werde meine Antwort verlassen, um die +1 zu speichern, aber das ist viel besser. – JohnE

+0

nein Ihre Antwort ist auch gut, ich mag, wie Sie 'Join' so verwenden, um die Null-Werte zu füllen. vielleicht könntest du mit 'ser = ser.append (pd.qcut (g, 2))' (nur mein persönlicher Geschmack) ein wenig prägnanter sein, auch solltest du besser '.astype (str)' hinzufügen, sonst wird es nicht funktionieren mit mehr als einer nicht fehlerhaften Gruppe – maxymoo

+0

Ja, guter Punkt, append ist sauberer. Aber 'qcut' scheint bereits einen String zurückzugeben, so dass ich nicht weiß, ob der'astype (str)' benötigt wird. Ich habe mit einigen Beispielen herumgespielt und konnte keinen Unterschied sehen. – JohnE

1

Sie können dies tun, um das Problem zu vermeiden und Ihre Frage zu beantworten. Allerdings bin ich mir nicht sicher, ob dies wirklich das Ergebnis ist, das Sie suchen:

a.groupby(['A'])['B'].apply(lambda x: pd.qcut(x, 2) if len(x.unique())>1 else x) 
+0

Ich sehe, was du meinst, dank – Boud

+0

dieses Recht noch nicht ganz, es funktioniert nur, weil das Beispiel Datenrahmen alle Nullen in der ersten Gruppe enthält, 'x * np.nan' funktioniert tho – maxymoo

+0

auch' len (x.unique())> 1 'ist eine notwendige, aber nicht hinreichende Bedingung für den qcut, sie schlägt immer noch mit 'pd.qcut ([0,0,0,1], 2)' – maxymoo

1

Nicht wirklich kompakt, aber ich denke, das funktioniert?

ser = pd.Series() 
for i,g in a.groupby('A')['B']: 
    try: 
     ser = ser.append(pd.qcut(g,2)) 
    except: 
     pass 
a.join(ser.rename('qcut')) 

    A B  qcut 
0 1 0  NaN 
1 1 0  NaN 
2 1 0  NaN 
3 1 0  NaN 
4 2 2 [2, 4.5] 
5 2 3 [2, 4.5] 
6 2 7 (4.5, 7] 
7 2 6 (4.5, 7] 

Wenn Sie es vorziehen, "0" auf "NaN", ersetzen Sie "Pass" mit:

ser = ser.append(pd.Series([0]*len(g))) 
+0

scheint die Kategorie Info von qcut verloren einmal mit einem? – Lisa

+0

Nun, das ist anstatt zu stürzen, was Sie wollten, oder? Es wird nur mit qcut-Ergebnissen für die Gruppen gefüllt, in denen es nicht abstürzt. Siehe die Notiz, die ich hinzugefügt habe, wenn Sie es vorziehen, mit "0" anstelle von "NaN" zu füllen, oder Sie könnten nur mit "fillna (0)" beheben. – JohnE

Verwandte Themen