我正在尝试将双重求和公式转换为代码,但是无法找出正确的矩阵/矢量表示形式。
第一个求和是i到n,第二个求和是j> i到n。
我猜想有一种更高效,更Python化的方式来编写此代码?
我求助于嵌套循环以使其正常运行,但是,正如预期的那样,它在大型数据集下运行非常缓慢:
def wapc_denom(weights, vols):
x = []
y = []
for i, wi in enumerate(weights):
for j, wj in enumerate(weights):
if j > i:
x.append(wi * wj * vols[i] * vols[j])
y.append(np.sum(x))
return np.sum(y)
编辑:
使用smci答案中的指导,我认为我有一个潜在的解决方案:
def wapc_denom2(weights, vols):
return np.sum(np.tril(np.outer(weights, vols.T)**2, k=-1))
答案 0 :(得分:3)
假设您只希望对每一项进行计数(为此您必须将x = []
移到外循环中),那么一种便宜的计算总和的方法就是
创建模拟数据
weights = np.random.random(10)
vols = np.random.random(10)
进行计算
wv = weights * vols
result = (wv.sum()**2 - wv@wv) / 2
检查是否相同
def wapc_denom(weights, vols):
y = []
for i, wi in enumerate(weights):
x = []
for j, wj in enumerate(weights):
if j > i:
x.append(wi * wj * vols[i] * vols[j])
y.append(np.sum(x))
return np.sum(y)
assert np.allclose(result, wapc_denom(weights, vols))
为什么起作用?
我们正在做的是计算完整矩阵的总和,减去对角线并除以2。这很便宜,因为很容易验证外部乘积的总和是否是总和的乘积。
答案 1 :(得分:1)
wi * wj * vols[i] * vols[j]
是一个故事。 vols
是另一个向量,因此首先要计算向量wv = w * vols
(wj * vols[j]) * (wi * vols[i])
= wv^T * wv
是您的(矩阵外部乘积)表达式;那是列向量*行向量。但是实际上,您只想要总和。因此,我认为无需构造向量y.append(np.sum(x))
,您只需要对向量np.sum(y)
进行求和if j > i
部分也意味着您只需要下三角部分的总和,而不包括对角线。
答案 2 :(得分:0)
您可以在numpy中使用三角剖分,请选中np.triu
和np.meshgrid
。做:
np.product(np.triu(np.meshgrid(weights,weights), 1) * np.triu(np.meshgrid(vols,vols), 1),0).sum(1).cumsum().sum()
示例:
w = np.arange(4) +1
v = np.array([1,3,2,2])
print(np.triu(np.meshgrid(w,w), k=1))
>>array([[[0, 2, 3, 4],
[0, 0, 3, 4],
[0, 0, 0, 4],
[0, 0, 0, 0]],
[[0, 1, 1, 1],
[0, 0, 2, 2],
[0, 0, 0, 3],
[0, 0, 0, 0]]])
# example of product + triu + meshgrid (your x values):
print(np.product(np.triu(np.meshgrid(w,w), 1) * np.triu(np.meshgrid(v,v), 1),0))
>>array([[ 0, 6, 6, 8],
[ 0, 0, 36, 48],
[ 0, 0, 0, 48],
[ 0, 0, 0, 0]])
print(np.product(np.triu(np.meshgrid(w,w), 1) * np.triu(np.meshgrid(v,v), 1),0).sum(1).cumsum().sum())
>> 428
print(wapc_denom(w, v))
>> 428