使用多指数的二次 n 项方程
Quadratic n term equation using multiindex
我有两个 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 是与 a 和 b 的 Tn 索引相关的索引和列空间。
设置 - 编辑动态 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
实际上我想使用 df1 中的索引 Tn 对每个 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
此模式将根据每个 Q 中 tn 项的数量重复,因此它应该足够稳健以根据需要处理尽可能多的 Tn 项(在示例中我使用 3,但它可能多达 100 或更多)。
每个结果都应该保存在一个新的 DF 中 Index = [I, Q]
当 n
的值增加时,解决方案也不应该比 excel 慢。
提前致谢
一种方法可能是首先 reindex
您的数据框 df1
与列表 I
、Q
和 Tn
的所有可能组合与 pd.MultiIndex.from_product
,用0填充'V'列中的缺失值。该列然后有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
...
注意:如果您确定T
的每个元素在df1
的最后一级至少出现一次,则ar
可以使用unstack
如ar=df1.unstack(fill_value=0).values
得到。但我建议使用上面的 reindex
方法来防止任何错误
我有两个 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 是与 a 和 b 的 Tn 索引相关的索引和列空间。
设置 - 编辑动态 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
实际上我想使用 df1 中的索引 Tn 对每个 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
此模式将根据每个 Q 中 tn 项的数量重复,因此它应该足够稳健以根据需要处理尽可能多的 Tn 项(在示例中我使用 3,但它可能多达 100 或更多)。
每个结果都应该保存在一个新的 DF 中 Index = [I, Q]
当 n
的值增加时,解决方案也不应该比 excel 慢。
提前致谢
一种方法可能是首先 reindex
您的数据框 df1
与列表 I
、Q
和 Tn
的所有可能组合与 pd.MultiIndex.from_product
,用0填充'V'列中的缺失值。该列然后有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
...
注意:如果您确定T
的每个元素在df1
的最后一级至少出现一次,则ar
可以使用unstack
如ar=df1.unstack(fill_value=0).values
得到。但我建议使用上面的 reindex
方法来防止任何错误