2013-09-02 2 views
6

Я хочу умножить таблицу поиска (demand), приведенную для нескольких товаров (здесь: вода, Elec) и типов областей (Com, Ind, Res) с DataFrame (areas), который является таблицу областей для этих типов областей.Pandas: соединение с внешним продуктом

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 
    Com Ind 
0 1 4 
1 2 5 
2 3 6 

demand 
    Elec Water 
Com  8  4 
Ind  9  3 

После:

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

Моя попытка

Многословный и неполные; не работает для произвольного количества товаров.

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... 

Почти там:

 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 

Короче

Как присоединиться/умножать DataFrames areas и demand вместе в приличном образом?

ответ

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) 

дает

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

Как это работает:

Во-первых, обратите внимание на то, что происходит, когда мы называем areas.apply(foo). foo получает прошли колонны areas один за другим:

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 

Итак, пусть series одна такая колонка:

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

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

Мы можем muliply спрос этой серии так:

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

У этого есть половина чисел, которые мы хотим, но не в том виде, в котором мы хотим. Теперь apply необходимо вернуть Series, а не DataFrame. Один из способов превратить DataFrame в Series - использовать stack. Посмотрите, что произойдет, если мы получим stack этот DataFrame. Столбцы стать новым уровнем индекса:

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 

Таким образом, используя это в качестве возвращаемого значения multiply_by_demand, получу:

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 

Теперь мы хотим, чтобы первый уровень индекса стать столбцами ,Это может быть сделано с 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 

За просьбу в комментариях, вот pivot_table решение:

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

Я думаю, с помощью pivot_table означает, что вам не нужно, чтобы удалить область (и я думаю, что лучше читать) 'both.pivot_table (values ​​= ['Elec', 'Water'], rows = 'Edge', cols = 'Type')' –

+0

Спасибо, Энди! Я все еще пытаюсь освоить все эти команды ... – unutbu

+0

'del' +' pivot' оказывается в этом случае быстрее, чем 'pivot_table'. Возможно, причина 'pivot' существует в том, что она быстрее, чем' pivot_table' для тех случаев, когда она применима (например, когда вам не нужна агрегация). – unutbu

Смежные вопросы