2013-09-02 7 views
6

Chcę pomnożyć tabelę odnośników (demand), podaną dla wielu towarów (tutaj: Woda, Elec) i typów obszarów (Com, Ind, Res) z DataFrame (areas), która jest tabela obszarów dla tych typów obszarów.Pandy: łącz z zewnętrznym produktem

import pandas as pd 
areas = pd.DataFrame({'Com':[1,2,3], 'Ind':[4,5,6]}) 
demand = pd.DataFrame({'Water':[4,3], 
         'Elec':[8,9]}, index=['Com', 'Ind']) 

Przed:

areas 
    Com Ind 
0 1 4 
1 2 5 
2 3 6 

demand 
    Elec Water 
Com  8  4 
Ind  9  3 

Po:

area_demands     
    Com   Ind   
    Elec Water Elec Water 
0  8  4 36  12 
1  16  8 45  15 
2  24  12 54  18 

Moja próba

gadatliwy i niekompletne; nie działa dla dowolnej liczby towarów.

areas = pd.DataFrame({'area': areas.stack()}) 
areas.index.names = ['Edge', 'Type'] 
both = areas.reset_index(1).join(demand, on='Type') 
both['Elec'] = both['Elec'] * both['area'] 
both['Water'] = both['Water'] * both['area'] 
del both['area'] 
# almost there; it must be late, I fail to make 'Type' a hierarchical column... 

Prawie tam:

 Type Elec Water 
Edge 
0  Com  8  4 
0  Ind 36  12 
1  Com 16  8 
1  Ind 45  15 
2  Com 24  12 
2  Ind 54  18 

W skrócie

Jak dołączyć/pomnożyć DataFrames areas i demand razem w przyzwoity sposób?

Odpowiedz

4
import pandas as pd 
areas = pd.DataFrame({'Com':[1,2,3], 'Ind':[4,5,6]}) 
demand = pd.DataFrame({'Water':[4,3], 
         'Elec':[8,9]}, index=['Com', 'Ind']) 

def multiply_by_demand(series): 
    return demand.ix[series.name].apply(lambda x: x*series).stack() 
df = areas.apply(multiply_by_demand).unstack(0) 
print(df) 

daje

Com   Ind  
    Elec Water Elec Water 
0  8  4 36  12 
1 16  8 45  15 
2 24  12 54  18 

Jak to działa:

pierwsze, patrzeć na to, co się dzieje, gdy wzywamy areas.apply(foo). foo dostaje przeszły kolumny areas jeden po drugim:

def foo(series): 
    print(series) 

In [226]: areas.apply(foo) 
0 1 
1 2 
2 3 
Name: Com, dtype: int64 
0 4 
1 5 
2 6 
Name: Ind, dtype: int64 

Więc załóżmy series jest jednym z takich kolumna:

In [230]: series = areas['Com'] 

In [231]: series 
Out[231]: 
0 1 
1 2 
2 3 
Name: Com, dtype: int64 

Możemy odpowiednio pomnożyć popyt o tej serii w ten sposób:

In [229]: demand.ix['Com'].apply(lambda x: x*series) 
Out[229]: 
     0 1 2 
Elec 8 16 24 
Water 4 8 12 

To ma połowę liczb, które chcemy, ale nie w takiej formie, w jakiej chcemy. Teraz apply musi zwrócić Series, a nie DataFrame. Jednym ze sposobów przekształcenia DataFrame w Series jest użycie stack. Zobacz, co się stanie, jeśli zmienimy DataFrame na stack. Kolumny stać się nowy poziom indeksu:

In [232]: demand.ix['Com'].apply(lambda x: x*areas['Com']).stack() 
Out[232]: 
Elec 0  8 
     1 16 
     2 24 
Water 0  4 
     1  8 
     2 12 
dtype: int64 

Więc używając tego jako wartości zwracanej multiply_by_demand, otrzymujemy:

In [235]: areas.apply(multiply_by_demand) 
Out[235]: 
     Com Ind 
Elec 0 8 36 
     1 16 45 
     2 24 54 
Water 0 4 12 
     1 8 15 
     2 12 18 

Teraz chcemy pierwszy poziom indeksu stać kolumny .Można to zrobić z unstack:

In [236]: areas.apply(multiply_by_demand).unstack(0) 
Out[236]: 
    Com   Ind  
    Elec Water Elec Water 
0  8  4 36  12 
1 16  8 45  15 
2 24  12 54  18 

Na żądanie w komentarzach, tutaj jest pivot_table rozwiązanie:

import pandas as pd 
areas = pd.DataFrame({'Com':[1,2,3], 'Ind':[4,5,6]}) 
demand = pd.DataFrame({'Water':[4,3], 
         'Elec':[8,9]}, index=['Com', 'Ind']) 

areas = pd.DataFrame({'area': areas.stack()}) 
areas.index.names = ['Edge', 'Type'] 
both = areas.reset_index(1).join(demand, on='Type') 
both['Elec'] = both['Elec'] * both['area'] 
both['Water'] = both['Water'] * both['area'] 
both.reset_index(inplace=True) 
both = both.pivot_table(values=['Elec', 'Water'], rows='Edge', cols='Type') 
both = both.reorder_levels([1,0], axis=1) 
both = both.reindex(columns=both.columns[[0,2,1,3]]) 
print(both) 
+0

myślę użyciu pivot_table oznacza, że ​​nie ma potrzeby, aby usunąć obszar (i myślę, że jest ładniej czytać) 'both.pivot_table (values ​​= ['Elec', 'Water'], rows = 'Edge', cols = 'Type')' –

+0

Dzięki, Andy! Nadal staram się opanować wszystkie te polecenia ... – unutbu

+0

'del' +' pivot' okazuje się w tym przypadku szybszym niż 'pivot_table'. Być może przyczyną 'pivot' jest to, że jest szybsza niż' pivot_table' dla tych przypadków, w których ma zastosowanie (np. Kiedy nie potrzebujesz agregacji). – unutbu

Powiązane problemy