【问题标题】:How can I improve the efficiency of my algorithm, while I use two loops inside?当我在内部使用两个循环时,如何提高算法的效率?
【发布时间】:2021-08-07 06:23:18
【问题描述】:

各位有经验的朋友,我提出了一种解决算法问题的方法。但是,我发现当数据量增加时,我的方法变得非常耗时。请问有没有更好的方法来解决这个问题?是否可以使用矩阵操作?

问题

  • 假设我们有 1 个score-matrix 和 3 个value-matrix
  • 每个都是square matrix,大小相同(N*N)
  • score-matrix 中的元素表示两个实体之间的weights。例如,S12 表示entity 1entity 2 之间的分数。 (权重仅在大于 0 时才有意义。)
  • value-matrix 中的元素表示两个实体之间的values。例如,V12 表示entity 1entity 2 之间的值。因为我们有 3 个value-matrix,所以我们有 3 个不同的V12

目标是:我想将values与对应的weights相乘,这样我最终可以输出一个(Nx3)矩阵。

我的解决方案:我解决了这个问题如下。但是,我在这里使用了两个 for 循环,这使得我的程序变得非常耗时。 (例如,当N 很大或3 变为100 时)请问有什么办法可以改进这段代码吗?任何建议或提示将不胜感激。提前谢谢!

# generate sample data
import numpy as np
score_mat = np.random.randint(low=0, high=4, size=(2,2))
value_mat = np.random.randn(3,2,2)

# solve problem
# init the output info
output = np.zeros((2, 3))

# update the output info
for entity_1 in range(2):

    # consider meaningful score
    entity_others_list = np.where(score_mat[entity_1,:]>0)[0].tolist()

    # iterate every other entity
    for entity_2 in entity_others_list:

        vec = value_mat[:,entity_1,entity_2].copy()

        vec *= score_mat[entity_1,entity_2]

        output[entity_1] += vec

【问题讨论】:

  • 也许您可以将值和分数拆分为矩阵,然后使用矩阵乘法(numpy)?
  • 你能跳过 np.where 吗?乘以零比选择非零值更便宜
  • 嗨@Stefan。谢谢你们的cmets。我考虑了您的建议,但即使我不使用 np.where,我仍然需要迭代所有列索引。虽然并非所有这些都是非零的。我猜 np.where 限制了范围并提高了效率。如果我做错了什么,请告诉我。

标签: python python-3.x algorithm numpy matrix


【解决方案1】:

您不需要手动迭代它们,只需将score_mat 乘以value_mat,然后在axis=2 上调用sum,在axis=1 上再次调用sum

正如您所提到的,score 仅在大于零时才有意义,如果是这种情况,您可以首先将非正值替换为 1,因为将某些值乘以 1 保持不变:

>>> score_mat[score_mat<=0] = 1
>>> (score_mat*value_mat).sum(axis=2).sum(axis=1)
array([-0.58826032, -3.08093186, 10.47858256])

分解:

# This is what the randomly generated numpy arrays look like:
>>> score_mat
array([[3, 3],
       [1, 3]])
>>> value_mat
array([[[ 0.81935985,  0.92228075],
        [ 1.07754964, -2.29691059]],
       [[ 0.12355602, -0.36182607],
        [ 0.49918847, -0.95510339]],
       [[ 2.43514089,  1.17296263],
        [-0.81233976,  0.15553725]]])

# When you multiply the matcrices, each inner matrices in value_mat will be multiplied
# element-wise by score_mat
>>> score_mat*value_mat
array([[[ 2.45807955,  2.76684225],
        [ 1.07754964, -6.89073177]],
       [[ 0.37066806, -1.08547821],
        [ 0.49918847, -2.86531018]],
       [[ 7.30542266,  3.51888789],
        [-0.81233976,  0.46661176]]])

# Now calling sum on axis=2, will give the sum of each rows in the inner-most matrices
>>> (score_mat*value_mat).sum(axis=2)
array([[ 5.22492181, -5.81318213],
       [-0.71481015, -2.36612171],
       [10.82431055, -0.34572799]])

# Finally calling sum on axis=1, will again sum the row values
>>> (score_mat*value_mat).sum(axis=2).sum(axis=1)
array([-0.58826032, -3.08093186, 10.47858256])

【讨论】:

  • 非常感谢您的帮助!我只是尝试您的代码并将其与我的输出进行比较。但是,我发现它变成了False。但是你提到的很有启发性。我正在尝试了解每个步骤并将其实施到我的身上。谢谢!
  • 您能否从实际数据中添加一个小样本以及它的预期输出,而不是使用随机数。我添加的代码完全符合您在问题中提到的内容,每个部分也有一些解释
  • 嗨@ThePyGuy,我的代码中的output 是预期的输出。我已经手动验证了它。我的实际数据比样本大得多,其中N 是2000,value-matrix 的数量是21。所以我试图找到一种更有效的方法来解决它。
  • 好的,试试这个:(score_mat*value_mat).sum(axis=-1).T
  • 哇!哇!你完美解决了这个问题!唯一的事情是score_mat[score_mat&lt;=0] 应该是0,因为我们要丢弃无意义的分数。非常感谢@ThePyGuy!
猜你喜欢
  • 2019-03-29
  • 2021-04-05
  • 1970-01-01
  • 2015-10-08
  • 2012-01-04
  • 1970-01-01
  • 2019-12-05
  • 2019-11-06
  • 2015-09-12
相关资源
最近更新 更多