Квадратичное n-членное уравнение с использованием мультииндекс - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть два DF, которые я хотел бы использовать для вычисления следующего:

w(ti,ti)*a(ti)^2 + w(tj,tj)*b(sj,tj)^2 + 2*w(si,tj)*a(ti)*b(tj)

Выше используются два термина (a, b).w - вес df, где i и j - индексы и пространства столбцов, относящиеся к индексу Tn для a и b.

Настройка - Редактировать динамический W

import pandas as pd
import numpy as np

I = ['i'+ str(i) for i in range(4)]
Q = ['q' + str(i) for i in range(5)]
T = ['t' + str(i) for i in range(3)]
n = 100

df1 = pd.DataFrame({'I': [I[np.random.randint(len(I))] for i in range(n)],
                    'Q': [Q[np.random.randint(len(Q))] for i in range(n)],
                    'Tn': [T[np.random.randint(len(T))] for i in range(n)],
                    'V': np.random.rand(n)}).groupby(['I','Q','Tn']).sum()

df1.head(5)
I  Q  Tn  V        
i0 q0 t0  1.626799
      t2  1.725374
   q1 t0  2.155340
      t1  0.479741
      t2  1.039178

w = np.random.randn(len(T),len(T))
w = (w*w.T)/2
np.fill_diagonal(w,1)
W = pd.DataFrame(w, columns = T, index = T)

W
          t0        t1        t2
t0  1.000000  0.029174 -0.045754
t1  0.029174  1.000000  0.233330
t2 -0.045754  0.233330  1.000000

По сути, я хотел бы использовать индекс Tn в df1, чтобы использовать вышеприведенное уравнение для каждого I и Q.

Конечный результат для df1.loc['i0','q0'] в приведенном выше примере должен быть:

  W(t0,t0) * V(t0)^2 
+ W(t2,t2) * V(t2)^2
+ 2 * W(t0,t2) * V(t0) * V(t2) 
=     
  1.0 * 1.626799**2 
+ 1.0 * 1.725374**2 
+ (-0.045754) * 1.626799 * 1.725374

Конечный результат для df1.loc['i0','q1'] в приведенном выше примере должен быть:

  W(t0,t0) * V(t0)^2 
+ W(t1,t1) * V(t1)^2
+ W(t2,t2) * V(t2)^2
+ 2 * W(t0,t1) * V(t0) * V(t1)
+ 2 * W(t0,t2) * V(t0) * V(t2)
+ 2 * W(t2,t1) * V(t1) * V(t2)
=     
  1.0 * 2.155340**2 
+ 1.0 * 0.479741**2
+ 1.0 * 1.039178**2
+ 0.029174 * 2.155340 * 0.479741 * 1
+ (-0.045754) * 2.155340 * 1.039178 * 1
+ 0.233330 * 0.479741 * 1.039178 * 1

Этот шаблон будет повторяться в зависимости от количества членов tn в каждом Q, следовательно, он должен быть достаточно устойчивым, чтобы обрабатывать столько Tnтермины по мере необходимости (в примере я использую 3, но это может быть целых 100 или более).

Каждый результат должен быть сохранен в новом DF с Index = [I, Q] Решение также не должно быть медленнеечем превосходить, когда n увеличивается в стоимости.

Заранее спасибо

1 Ответ

0 голосов
/ 23 ноября 2018

Один путь может быть первым reindex ваш фрейм данных df1 со всеми возможными комбинациями списков I, Q и Tn с pd.MultiIndex.from_product, заполняя пропущенное значение в столбце 'V'с 0. Тогда столбец содержит len(I)*len(Q)*len(T) элементов.Затем вы можете reshape values получить каждую строку, относящуюся к одной комбинации на I и Q, такую ​​как:

ar = (df1.reindex(pd.MultiIndex.from_product([I,Q,T], names=['I','Q','Tn']),fill_value=0)
         .values.reshape(-1,len(T)))

Чтобы увидеть связь между моими входными данными df1 и ar, вот несколько связанных строк

print (df1.head(6))
                 V
I  Q  Tn          
i0 q0 t1  1.123666
   q1 t0  0.538610
      t1  2.943206
   q2 t0  0.570990
      t1  0.617524
      t2  1.413926
print (ar[:3])
[[0.         1.1236656  0.        ]
 [0.53861027 2.94320574 0.        ]
 [0.57099049 0.61752408 1.4139263 ]]

Теперь, чтобы выполнить умножение с элементом W, можно создать внешний продукт ar с самим собой, но построчнополучить для каждой строки матрицу len(T)*len(T).Например, для второй строки:

[0.53861027 2.94320574 0.        ]

становится

[[0.29010102, 1.58524083, 0.        ], #0.29010102 = 0.53861027**2, 1.58524083 = 0.53861027*2.94320574 ...
 [1.58524083, 8.66246003, 0.        ],
 [0.        , 0.        , 0.        ]]

Возможны несколько методов, например ar[:,:,None]*ar[:,None,:] или np.einsum с правым индексом: np.einsum('ij,ik->ijk',ar,ar).Оба дают одинаковый результат.

Следующий шаг можно выполнить с помощью tensordot и указать правильное значение axes.Таким образом, используя ar и W в качестве входа, вы делаете:

print (np.tensordot(np.einsum('ij,ik->ijk',ar,ar),W.values,axes=([1,2],[0,1])))
array([ 1.26262437, 15.29352438, 15.94605435, ...

Чтобы проверить здесь второе значение, 1*0.29010102 + 1*8.66246003 + 2.*2*1.58524083 == 15.29352438 (где 1 - W(t0,t0) и W(t1,t1), 2 - этоW(t0,t1))

Наконец, чтобы создать фрейм данных, как ожидается, снова используйте pd.MultiIndex.from_product:

new_df = pd.DataFrame({'col1': np.tensordot(np.einsum('ij,ik->ijk',ar,ar),
                                            W.values,axes=([1,2],[0,1]))},
                      index=pd.MultiIndex.from_product([I,Q], names=['I','Q']))

print (new_df.head(3))
            col1
I  Q            
i0 q0   1.262624
   q1  15.293524
   q2  15.946054
...

Примечание: если вы SURE , то каждый элементT - хотя бы один раз на последнем уровне df1, ar можно получить с помощью unstack, например ar=df1.unstack(fill_value=0).values.Но я бы предложил использовать метод reindex, описанный выше, чтобы предотвратить любую ошибку

...