2016-07-20 10 views
3

Ich verstehe ich eine Spalte zu einem Datenrahmen hinzufügen und ihre Werte auf die Werte aus einer Funktion, wie diese zurück aktualisieren:Wie man durch eine Spalte im Datenrahmen iteriert und zwei neue Spalten gleichzeitig aktualisiert?

df=pd.DataFrame({'x':[1,2,3,4]}) 

def square(x): 
    return x*x 

df['x_squared'] = [square(i) for i in df['x']] 

Allerdings habe ich ein Problem bin vor, dass die eigentliche Funktion zwei Elemente zurückgibt, und ich möchte diese zwei Elemente in zwei verschiedene neue Spalten setzen. Ich schrieb hier ein Pseudo-Code mein Problem deutlicher zu beschreiben:

df=pd.DataFrame({'x':[1,2,3,4]}) 

def squareAndCube(x): 
    return x*x, x*x*x 

#below is a pseudo-code 
df['x_squared'], df['x_cubed'] = [squareAndCube(i) for i in df['x']] 

Above Codes geben Sie mir eine Fehlermeldung „zu viele Werte entpacken“ sagen. Also, wie soll ich das beheben?

Antwort

3

Sie in einem vektorisierten Mode tun könnte, wie so -

df['x_squared'], df['x_cubed'] = df.x**2,df.x**3 

Oder mit dieser benutzerdefinierten Funktion, wie so -

df['x_squared'], df['x_cubed'] = squareAndCube(df.x) 

Zurück zu Ihrem loopy Fall auf der rechten Seite Seite der Aufgabe, die Sie hatten:

In [101]: [squareAndCube(i) for i in df['x']] 
Out[101]: [(1, 1), (4, 8), (9, 27), (16, 64)] 

Jetzt hatten Sie auf der linken Seite df['x_squared'], df['x_cubed'] =. Daher erwartet es die quadrierten Zahlen aller Zeilen als erste Eingabezuweisung. Aus der obigen Liste ist das erste Element nicht das, sondern das Quadrat und der Würfel der ersten Zeile. Die Lösung besteht also darin, diese Liste zu transponieren und als neue Spalten zuzuordnen. Somit würde die fix sein -

In [102]: L = [squareAndCube(i) for i in df['x']] 

In [103]: map(list, zip(*L)) # Transposed list 
Out[103]: [[1, 4, 9, 16], [1, 8, 27, 64]] 

In [104]: df['x_squared'], df['x_cubed'] = map(list, zip(*L)) 

Für die Liebe NumPy broadcasting!

df['x_squared'], df['x_cubed'] = (df.x.values[:,None]**[2,3]).T 
+0

große Antwort @Divakar, +1 – piRSquared

+0

btw die Ausstrahlung ist WAY1 !! 1 schneller als meine log_dot Lösung. – piRSquared

+0

Das ist eine wirklich gute Antwort! Ich habe diese 'squareAndCube()' -Funktion verwendet, um mein Problem einfach zu lösen. Mein wirkliches Problem ist, dass ich eine Adresse als Eingabe verwenden muss und den Breiten- und Längengrad zurückgeben muss. So wählte ich schließlich die 'map'- und' zip'-Methode.Aber es ist wirklich großartig zu wissen, dass es mehrere andere Methoden gibt! Danke @Divakar. – user3768495

0

über Wie df.loc wie folgt aus:

df=pd.DataFrame({'x':[1,2,3,4]}) 

def square(x): 
    return x*x 

df['x_squared'] = df['x_cubed'] = None 
df.loc[:, ['x_squared', 'x_cubed']] = [squareAndCube(i) for i in df['x']] 

gibt

x x_squared x_cubed 
0 1   1  1 
1 2   4  8 
2 3   9  27 
3 4   16  64 

Dies ist sehr nahe, was man hatte, aber die Spalten müssen existieren für df.loc zu arbeiten .

Für die Uneingeweihten, df.loc nimmt zwei Parameter, eine Liste der Zeilen, die Sie arbeiten möchten - in diesem Fall : die alle von ihnen, und eine Liste der Spalten bedeutet - ['x_squared', 'x_cubed'].

1

Dies funktioniert für positive Zahlen. Denken, wie man verallgemeinert, aber die Kürze dieser Lösung hat mich abgelenkt.

df = pd.DataFrame(range(1, 10)) 
a = np.arange(1, 4).reshape(1, -1) 

np.exp(np.log(df).dot(a)) 

enter image description here

+0

Inspiriert von diesem fügte einen anderen Ansatz mit Rundfunk! :) – Divakar

+0

@Divakar Ich wusste, du würdest sein :-) Ich wollte dich um Hilfe bitten, aber ich war abgelenkt von etwas anderem. – piRSquared

Verwandte Themen