2015-12-17 46 views
5

Vorrei unire nove dataframes Pandas insieme in un singolo dataframe, facendo un join su due colonne, controllando i nomi delle colonne. È possibile?Panda: unire più dataframes e controllare i nomi delle colonne?

Ho nove serie di dati. Tutti loro hanno le seguenti colonne:

org, name, items,spend 

voglio di unirsi a loro in un unico dataframe con le seguenti colonne:

org, name, items_df1, spend_df1, items_df2, spend_df2, items_df3... 

Ho letto la documentazione su merging and joining. Posso attualmente unire due insiemi di dati insieme in questo modo:

ad = pd.DataFrame.merge(df_presents, df_trees, 
         on=['practice', 'name'], 
         suffixes=['_presents', '_trees']) 

Questa grande opera, facendo print list(aggregate_data.columns.values) mi mostra le seguenti colonne:

[org', u'name', u'spend_presents', u'items_presents', u'spend_trees', u'items_trees'...] 

Ma come posso fare questo per nove colonne? merge sembra solo accettarne due alla volta, e se lo faccio in sequenza, i nomi delle mie colonne finiranno per essere molto disordinati.

+0

Ho appena trovato questo http://stackoverflow.com/questions/24853762/pandas-merging-multiple-dataframes ma non sono sicuro che funzioni per il mio esempio: suppongo di dover concatenare, quindi unire in qualche modo? Voglio scrivere il mio output su una tabella BigQuery, quindi non so se i dataframer gerarchici funzioneranno per me. – Richard

+0

Trovato questo http://stackoverflow.com/questions/23668427/pandas-joining-multiple-dataframes-on-columns?rq=1 che è più promettente, ma non spiega come controllare i nomi delle colonne. – Richard

risposta

5

si potrebbe usare functools.reduce per applicare iterativamente pd.merge a ciascuno dei DataFrames:

result = functools.reduce(merge, dfs) 

Ciò equivale a

result = dfs[0] 
for df in dfs[1:]: 
    result = merge(result, df) 

Per passare l'argomento on=['org', 'name'], è possibile utilizzare functools.partial definire la funzione di fusione:

merge = functools.partial(pd.merge, on=['org', 'name']) 

Dal specificando il parametro suffixes in functools.partial permetterebbe solo una scelta fissa di suffissi, e dal momento che qui abbiamo bisogno di un diverso suffisso per ogni chiamata pd.merge, penso che sarebbe stato più semplice per preparare la colonna DataFrames nomi prima di chiamare pd.merge:

for i, df in enumerate(dfs, start=1): 
    df.rename(columns={col:'{}_df{}'.format(col, i) for col in ('items', 'spend')}, 
       inplace=True) 

Per esempio,

import pandas as pd 
import numpy as np 
import functools 
np.random.seed(2015) 

N = 50 
dfs = [pd.DataFrame(np.random.randint(5, size=(N,4)), 
        columns=['org', 'name', 'items', 'spend']) for i in range(9)] 
for i, df in enumerate(dfs, start=1): 
    df.rename(columns={col:'{}_df{}'.format(col, i) for col in ('items', 'spend')}, 
       inplace=True) 
merge = functools.partial(pd.merge, on=['org', 'name']) 
result = functools.reduce(merge, dfs) 
print(result.head()) 

cede

org name items_df1 spend_df1 items_df2 spend_df2 items_df3 \ 
0 2  4   4   2   3   0   1 
1 2  4   4   2   3   0   1 
2 2  4   4   2   3   0   1 
3 2  4   4   2   3   0   1 
4 2  4   4   2   3   0   1 

    spend_df3 items_df4 spend_df4 items_df5 spend_df5 items_df6 \ 
0   3   1   0   1   0   4 
1   3   1   0   1   0   4 
2   3   1   0   1   0   4 
3   3   1   0   1   0   4 
4   3   1   0   1   0   4 

    spend_df6 items_df7 spend_df7 items_df8 spend_df8 items_df9 spend_df9 
0   3   4   1   3   0   1   2 
1   3   4   1   3   0   0   3 
2   3   4   1   3   0   0   0 
3   3   3   1   3   0   1   2 
4   3   3   1   3   0   0   3 
+0

Questo è fantastico! Grazie mille! Sfortunatamente è un join interno, comunque, come faresti con un join esterno? – jeangelj

+0

@jeangelj: puoi aggiungere 'how = 'outer'' alla chiamata' functools.partial': ad es. 'merge = functools.partial (pd.merge, on = ['org', 'name'], how = 'outer')'. – unutbu

0

Farebbe un grande pd.concat() e quindi rinominare tutte le colonne funzionano per te? Qualcosa di simile:

desired_columns = ['items', 'spend'] 
big_df = pd.concat([df1, df2[desired_columns], ..., dfN[desired_columns]], axis=1) 


new_columns = ['org', 'name'] 
for i in range(num_dataframes): 
    new_columns.extend(['spend_df%i' % i, 'items_df%i' % i]) 

bid_df.columns = new_columns 

Questo dovrebbe dare colonne come:

org, name, spend_df0, items_df0, spend_df1, items_df1, ..., spend_df8, items_df8

0

Ho voluto questo pure a volte, ma stato in grado di trovare un modo integrato panda di farlo.Ecco il mio suggerimento (e il mio piano per la prossima volta che ne ho bisogno):

  1. Creare un dizionario vuoto, merge_dict.
  2. Fai scorrere l'indice che desideri per ciascun frame di dati e aggiungi i valori desiderati al dizionario con l'indice come chiave.
  3. Generare un nuovo indice come sorted(merge_dict).
  4. Generare un nuovo elenco di dati per ogni colonna eseguendo il ciclo attraverso merge_dict.items().
  5. Creare un nuovo frame di dati con index=sorted(merge_dict) e le colonne create nel passaggio precedente.

Fondamentalmente, questo è un po 'come un hash join in SQL. Sembra il modo più efficiente a cui possa pensare e non dovrebbe impiegare troppo tempo per la codifica.

Buona fortuna.

Problemi correlati