2017-02-11 4 views
2

Wenn Aufruf einer Funktion mit groupby + apply, die ich von einem DataFrame zu einem Series groupby Objekt gehen wollen, eine Funktion, die jeder Gruppe anwenden, die eine Series als Eingabe und gibt eine Series als Ausgabe, und dann die Ausgabe von der groupby + apply Anruf als ein Feld in der DataFrame zuweisen. Das Standardverhalten besteht darin, dass die Ausgabe von groupby + apply durch die Gruppierungsfelder indiziert wird, wodurch verhindert wird, dass ich sie sauber dem DataFrame zuordnet. Ich würde bevorzugen, dass die Funktion, die ich mit anrufe, eine Series als Eingabe nehmen und eine Series als Ausgabe zurückgeben; Ich denke, es ist ein bisschen sauberer als DataFrame zu DataFrame. (Dies ist nicht der beste Weg, in diesem Beispiel auf das Ergebnis bekommen, die reale Anwendung recht unterschiedlich ist.)beibehalten Dataframe-Index bei der Serie erzeugen groupby gelten mit

import pandas as pd 
df = pd.DataFrame({ 
'A': [999, 999, 111, 111], 
'B': [1, 2, 3, 4], 
'C': [1, 3, 1, 3] 
}) 
def less_than_two(series): 
    # Intended for series of length 1 in this case 
    # But not intended for many-to-one generally 
    return series.iloc[0] < 2 
output = df.groupby(['A', 'B'])['C'].apply(less_than_two) 

ich den Index will auf output die gleichen wie df sein, sonst kann ich nicht zuordnen zu df (sauber):

df['Less_Than_Two'] = output 

So etwas wie output.index = df.index zu hässlich scheint, und das group_keys Argument scheint nicht zu funktionieren:

output = df.groupby(['A', 'B'], group_keys = False)['C'].apply(less_than_two) 
df['Less_Than_Two'] = output 

Antwort

1

transform gibt die Ergebnisse mit dem Original index zurück, genau wie Sie es verlangt haben. Es wird das gleiche Ergebnis über alle Elemente einer Gruppe übertragen. Bedenken Sie, passen Sie auf, dass die dtype davon abgeleitet werden kann, etwas anderes zu sein. Sie müssen es möglicherweise selbst werfen.

In diesem Fall wird, um eine weitere Spalte hinzufügen, würde ich assign

df.assign(
    Less_Than_Two=df.groupby(['A', 'B'])['C'].transform(less_than_two).astype(bool)) 

    A B C Less_Than_Two 
0 999 1 1   True 
1 999 2 3   False 
2 111 3 1   True 
3 111 4 3   False 
+0

Sieht so aus, als würde "transform" den gleichen "dtype" wie das Eingabefeld behalten. Ich mag es, dass 'transform' das ursprüngliche' Index' behält, obwohl ich nicht unbedingt aussehe, um hier zu senden, was ich denke, ist egal, weil die Ergebnisse von Länge 1 sind. Diese Antwort ist die beste im Geist, obwohl in der Das vollständige Problem 'transform' konvertiert' boolean' in 'datetime', welches nicht in' boolean' zurückkonvertiert werden kann. Von R kommend, habe ich das Gefühl, dass der Index ein zweischneidiges Schwert ist, und "dtypes" sind irgendwie schwierig, aber ich mag viele andere Dinge. –

0

Angenommen, Ihre groupby ist notwendig (und das resultierende groupby-Objekt wird weniger Zeilen als Ihr DataFrame haben - dies ist nicht der Fall mit den Beispieldaten), dann wird die Zuordnung der Serie zu der 'Is.Even'-Spalte führen NaN-Werte (da der Index zu output kürzer ist als der Index zu df).

Stattdessen basiert auf den Beispieldaten wird der einfachste Ansatz output zu verschmelzen - als Datenrahmen - mit df, etwa so:

output = df.groupby(['A','B'])['C'].agg({'C':is_even}).reset_index() # reset_index restores 'A' and 'B' from indices to columns 
output.columns = ['A','B','Is_Even'] #rename target column prior to merging 
df.merge(output, how='left', on=['A','B']) # this will support a many-to-one relationship between combinations of 'A' & 'B' and 'Is_Even' 
# and will thus properly map aggregated values to unaggregated values 

Auch sollte ich beachten Sie, dass Sie besser sind Aus Unterstriche als Punkte in Variablennamen deaktivieren; Im Gegensatz zu R fungieren Punkte beispielsweise als Operatoren für den Zugriff auf Objekteigenschaften, und ihre Verwendung in Variablennamen kann daher die Funktionalität blockieren/Verwirrung erzeugen.

+0

Dank @cmaher verwenden. Mein Beispiel war nicht großartig; gerade aktualisiert. Die Absicht zu verwenden, verwenden Sie dataframe.groupby [Feldname] .apply für Serie zu Serie mit demselben Index, wobei das Ergebnis die gleiche Form wie die Eingabe-Serie für Viele-zu-viele-Anwendungen haben wird. –

+0

Kein Problem. Es ist immer noch unklar, warum du überhaupt ein 'groupby' benötigst; basierend auf Ihrer Beschreibung und dem Beispielcode könnten Sie die 'Less_Than_Two' Spalte mit' df.loc [:, 'Less_Than_Two'] = df.C.apply (less_than_two) ' – cmaher

+0

erstellen Ich bin ein großer Fan von Split- apply-combine und 'DataFrame' zu' DataFrame' in 'pandas' ist ziemlich intuitiv.Im Prinzip verwende ich die einfachste Datenstruktur, die ich kann, also möchte ich 'Series' zu' Series' machen, aber die Handhabung von 'Index' wirft mich irgendwie um. Wenn dieses Beispiel in der realen Welt auftauchen würde, würde ich wahrscheinlich 'df.C <2 'machen, aber das Problem, an dem ich arbeite, ist ein bisschen anders. –

Verwandte Themen