2015-05-04 40 views
19

Ho un frame di dati panda mydf che ha due colonne e entrambe le colonne sono tipi di dati datetime: mydate e mytime. Voglio aggiungere altre tre colonne: hour, weekday e weeknum.Aggiungere più colonne a Pandas Dataframe dalla funzione

def getH(t): #gives the hour 
    return t.hour 
def getW(d): #gives the week number 
    return d.isocalendar()[1] 
def getD(d): #gives the weekday 
    return d.weekday() # 0 for Monday, 6 for Sunday 

mydf["hour"] = mydf.apply(lambda row:getH(row["mytime"]), axis=1) 
mydf["weekday"] = mydf.apply(lambda row:getD(row["mydate"]), axis=1) 
mydf["weeknum"] = mydf.apply(lambda row:getW(row["mydate"]), axis=1) 

Il frammento funziona, ma non è computazionalmente efficiente come scorre il frame di dati almeno tre volte. Vorrei solo sapere se c'è un modo più veloce e/o più ottimale per farlo. Ad esempio, utilizzando zip o merge? Se, ad esempio, creo solo una funzione che restituisca tre elementi, come dovrei implementarla? Per illustrare la funzione sarebbe:

def getHWd(d,t): 
    return t.hour, d.isocalendar()[1], d.weekday() 
+0

Eventuali duplicati di [? E 'possibile aggiungere più colonne in una sola volta a un dataframe panda] (http : //stackoverflow.com/questions/19866377/is-it-possible-to-add-several-columns-at-once-to-a-pandas-dataframe) – geekazoid

risposta

9

Per completare John Galt's answer:

seconda del compito che viene eseguita da lambdafunc , potresti riscontrare un po 'di velocità memorizzando il risultato di apply in un nuovo DataFrame un d poi unirsi con l'originale:

lambdafunc = lambda x: pd.Series([x['mytime'].hour, 
            x['mydate'].isocalendar()[1], 
            x['mydate'].weekday()]) 

newcols = df.apply(lambdafunc, axis=1) 
newcols.columns = ['hour', 'weekday', 'weeknum'] 
newdf = df.join(newcols) 

Anche se non si vede un miglioramento della velocità, mi consiglia di utilizzare il join. Sarete in grado di evitare la (sempre fastidioso) SettingWithCopyWarning che possono pop-up quando si assegna direttamente sulle colonne:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame. 
Try using .loc[row_indexer,col_indexer] = value instead 
19

Ecco il metodo per farlo utilizzando uno apply

Say, df è come

In [64]: df 
Out[64]: 
     mydate  mytime 
0 2011-01-01 2011-11-14 
1 2011-01-02 2011-11-15 
2 2011-01-03 2011-11-16 
3 2011-01-04 2011-11-17 
4 2011-01-05 2011-11-18 
5 2011-01-06 2011-11-19 
6 2011-01-07 2011-11-20 
7 2011-01-08 2011-11-21 
8 2011-01-09 2011-11-22 
9 2011-01-10 2011-11-23 
10 2011-01-11 2011-11-24 
11 2011-01-12 2011-11-25 

prenderemo la funzione lambda fuori per separare linea per leggibilità e definirla come

In [65]: lambdafunc = lambda x: pd.Series([x['mytime'].hour, 
              x['mydate'].isocalendar()[1], 
              x['mydate'].weekday()]) 

E, apply e memorizzare il risultato di df[['hour', 'weekday', 'weeknum']]

In [66]: df[['hour', 'weekday', 'weeknum']] = df.apply(lambdafunc, axis=1) 

E, l'uscita è come

In [67]: df 
Out[67]: 
     mydate  mytime hour weekday weeknum 
0 2011-01-01 2011-11-14  0  52  5 
1 2011-01-02 2011-11-15  0  52  6 
2 2011-01-03 2011-11-16  0  1  0 
3 2011-01-04 2011-11-17  0  1  1 
4 2011-01-05 2011-11-18  0  1  2 
5 2011-01-06 2011-11-19  0  1  3 
6 2011-01-07 2011-11-20  0  1  4 
7 2011-01-08 2011-11-21  0  1  5 
8 2011-01-09 2011-11-22  0  1  6 
9 2011-01-10 2011-11-23  0  2  0 
10 2011-01-11 2011-11-24  0  2  1 
11 2011-01-12 2011-11-25  0  2  2 
+0

Grazie, John. Sembra buono. Questo approccio è stato eseguito più velocemente di quello nel post originale. Per un frame di dati con ~ 500 righe, la prestazione media per il tuo approccio era 0,1446926 secondi, mentre quella originale ha richiesto 0,15949020 secondi, in media (10 esecuzioni). – EFL

2
def getWd(d): 
    d.isocalendar()[1], d.weekday() 
def getH(t): 
    return t.hour 
mydf["hour"] = zip(*df["mytime"].map(getH)) 
mydf["weekday"], mydf["weeknum"] = zip(*df["mydate"].map(getWd)) 
+0

Venkat, ciao. Lo snippet restituisce un errore TypeE: l'argomento # 1 zip deve supportare l'iterazione – EFL

Problemi correlati