2015-12-17 28 views
5

Chciałbym połączyć dziewięć ramek danych Pandy razem w jedną ramkę danych, wykonując łączenie na dwóch kolumnach, kontrolując nazwy kolumn. czy to możliwe?Pandy: scalanie wielu ramek danych i nazw kolumn kontrolnych?

Mam dziewięć zestawów danych. Wszystkie z nich posiadają następujące kolumny:

org, name, items,spend 

Chcę połączyć je w jeden dataframe z następującymi kolumnami:

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

Czytałem dokumentację na merging and joining. Mogę obecnie scalić dwa zbiory danych razem tak:

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

Działa to doskonale, robiąc print list(aggregate_data.columns.values) pokazuje mi następujące kolumny:

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

Ale jak mogę to zrobić dla dziewięciu kolumnach? merge wydaje się akceptować tylko dwa naraz i jeśli zrobię to sekwencyjnie, moje nazwy kolumn będą bardzo nieładne.

+0

Właśnie znalazłem ten http://stackoverflow.com/questions/24853762/pandas-merging-multiple-dataframes, ale nie jestem pewien, czy działa na mój przykład - chyba muszę połączyć, a następnie scalić w jakiś sposób? Chcę napisać moje dane wyjściowe do tabeli BigQuery, więc nie wiem, czy hierarchiczne ramki danych będą działać dla mnie. – Richard

+0

Znaleźliśmy http://stackoverflow.com/questions/23668427/pandas-joining-multiple-dataframes-on-columns?rq=1, co jest bardziej obiecujące, ale nie wyjaśnia sposobu kontrolowania nazw kolumn. – Richard

Odpowiedz

5

Można użyć functools.reduce iteracyjnie stosuje pd.merge do każdego z DataFrames:

result = functools.reduce(merge, dfs) 

Jest to równoważne to

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

Aby zdać on=['org', 'name'] argumentu można użyć functools.partial zdefiniować funkcję scalania:

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

Ponieważ określenie parametru suffixes w functools.partial pozwoliłby tylko jeden stały wybór przyrostka, a ponieważ tutaj musimy inna przyrostek dla każdego pd.merge rozmowy, myślę, że byłoby najłatwiej przygotować kolumnę DataFrames nazwy przed wywołaniem 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) 

Na przykład

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()) 

daje

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

To jest świetne! Dziękuję Ci bardzo! To niestety jest wewnętrznym złączem jednak, jak poradzisz sobie z zewnętrznym złączeniem? – jeangelj

+0

@jeangelj: Możesz dodać 'how = 'outer'' do połączenia' functools.partial': np. 'merge = functools.partial (pd.merge, on = ['org', 'name'], how = 'outer')'. – unutbu

0

Czy wykonanie dużej pd.concat(), a następnie zmiana nazwy wszystkich kolumn będzie dla ciebie odpowiednia? Coś jak:

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 

To powinno dać kolumny jak:

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

0

Chciałem to również czasami, ale byli w stanie znaleźć wbudowany pand sposób to robić.Oto moja sugestia (i mój plan na następny raz, kiedy tego potrzebuję):

  1. Utwórz pusty słownik, merge_dict.
  2. Przeprowadź pętlę w żądanym indeksie dla każdej z ramek danych i dodaj żądane wartości do słownika z indeksem jako kluczem. Wygeneruj nowy indeks jako sorted(merge_dict).
  3. Wygeneruj nową listę danych dla każdej kolumny, wykonując pętlę przez merge_dict.items().
  4. Utwórz nową ramkę danych za pomocą index=sorted(merge_dict) i kolumn utworzonych w poprzednim kroku.

Zasadniczo jest to trochę jak sprzężenie hash w SQL. Wydaje się, że jest to najbardziej efektywny sposób, jaki mogę wymyślić i nie powinno to zająć zbyt długo, aby się zakodować.

Powodzenia.

Powiązane problemy