2013-09-05 16 views
10

Sto usando python2.7 e pandas 0.11.0.panda: riempire una colonna con alcuni array numpy

Provo a riempire una colonna di un dataframe utilizzando DataFrame.apply (func). La funzione func() dovrebbe restituire un array numpy (1x3).

import pandas as pd 
import numpy as np 

df= pd.DataFrame(np.random.randn(4, 3), columns=list('ABC')) 
print(df) 

       A   B   C 
    0 0.910142 0.788300 0.114164 
    1 -0.603282 -0.625895 2.843130 
    2 1.823752 -0.091736 -0.107781 
    3 0.447743 -0.163605 0.514052 

La funzione utilizzata a scopo di test:

def test(row): 
    # some complex calc here 
    # based on the values from different columns 
    return np.array((1,2,3)) 

df['D'] = df.apply(test, axis=1) 

[...] 
ValueError: Wrong number of items passed 1, indices imply 3 

Il divertente è che quando creo il dataframe da zero, funziona piuttosto bene, e ritorna come previsto:

dic = {'A': {0: 0.9, 1: -0.6, 2: 1.8, 3: 0.4}, 
    'C': {0: 0.1, 1: 2.8, 2: -0.1, 3: 0.5}, 
    'B': {0: 0.7, 1: -0.6, 2: -0.1, 3: -0.1}, 
    'D': {0:np.array((1,2,3)), 
      1:np.array((1,2,3)), 
      2:np.array((1,2,3)), 
      3:np.array((1,2,3))}} 

df= pd.DataFrame(dic) 
print(df) 
     A B C   D 
    0 0.9 0.7 0.1 [1, 2, 3] 
    1 -0.6 -0.6 2.8 [1, 2, 3] 
    2 1.8 -0.1 -0.1 [1, 2, 3] 
    3 0.4 -0.1 0.5 [1, 2, 3] 

Grazie in anticipo

+3

si dovrebbe evitare di utilizzare '' list's/tuple's in '' DataFrame's o Series '. Perché non avere solo 3 colonne in 'df' o un separato' DataFrame' con le tue colonne? –

+5

Suppongo che a volte la forma vettoriale sia più naturale per alcune quantità, ad esempio coordinate. 'df.endPoint-df.startPoint' è ovviamente più preferibile a' np.c_ [df.endX-df.startX, df.endY-df.startY, df.endZ-df.startZ] '. – herrlich10

risposta

11

Se si tenta di restituire più valori dalla funzione passata t o apply e il DataFrame chiamato apply ha lo stesso numero di elementi lungo l'asse (in questo caso colonne) come numero di valori restituiti, Pandas creerà un DataFrame dai valori di ritorno con le stesse etichette dell'originale dataframe. Si può vedere questo se lo farete:

>>> def test(row): 
     return [1, 2, 3] 
>>> df= pd.DataFrame(np.random.randn(4, 3), columns=list('ABC')) 
>>> df.apply(test, axis=1) 
    A B C 
0 1 2 3 
1 1 2 3 
2 1 2 3 
3 1 2 3 

, per questo si ottiene l'errore, dal momento che non è possibile assegnare un dataframe alla colonna di dataframe.

Se si restituisce qualsiasi altro numero di valori, verrà restituito solo un oggetto di serie, che può essere assegnato:

>>> def test(row): 
     return [1, 2] 
>>> df= pd.DataFrame(np.random.randn(4, 3), columns=list('ABC')) 
>>> df.apply(test, axis=1) 
0 [1, 2] 
1 [1, 2] 
2 [1, 2] 
3 [1, 2] 
>>> df['D'] = df.apply(test, axis=1) 
>>> df 
      A   B   C  D 
0 0.333535 0.209745 -0.972413 [1, 2] 
1 0.469590 0.107491 -1.248670 [1, 2] 
2 0.234444 0.093290 -0.853348 [1, 2] 
3 1.021356 0.092704 -0.406727 [1, 2] 

Io non sono sicuro perché Pandas fa questo, e perché lo fa solo quando il valore di ritorno è un list o un ndarray, dal momento che non lo farà se si torna un tuple:

>>> def test(row): 
     return (1, 2, 3) 
>>> df= pd.DataFrame(np.random.randn(4, 3), columns=list('ABC')) 
>>> df['D'] = df.apply(test, axis=1) 
>>> df 
      A   B   C   D 
0 0.121136 0.541198 -0.281972 (1, 2, 3) 
1 0.569091 0.944344 0.861057 (1, 2, 3) 
2 -1.742484 -0.077317 0.181656 (1, 2, 3) 
3 -1.541244 0.174428 0.66(1, 2, 3) 
+1

Ciao Viktor! grazie per la risposta. Quindi, se ti capisco correttamente, non c'è modo di passare una matrice numpy? – Nic

+1

@Nic Se la lunghezza della matrice numpy non è uguale al numero di colonne il codice funzionerà, ma non è destinato a essere utilizzato in questo modo. Come ha detto Phillip Cloud, dovresti evitare di inserire liste o array nella tua serie. Dovresti creare più serie (cioè più colonne nel tuo DataFrame). –

+0

Grazie ragazzi. Seguirò il tuo consiglio e andrò per 3 colonne. @Phillip: scusa ho perso il tuo commento in prima lettura. – Nic