【问题标题】:Replace double for loop (with indexing into other arrays) over numpy array在 numpy 数组上替换双 for 循环(索引到其他数组)
【发布时间】:2021-04-09 04:56:34
【问题描述】:

这是我正在处理的示例:

 processed_data = np.empty_like(data)
 min_per_col = np.amin(data, axis=0) # axis0 for col, axis1 for row
 max_per_col = np.amax(data, axis=0) # axis0 for col, axis1 for row
 for row_idx, row in enumerate(data):
     for col_idx, val in enumerate(row):
         processed_data[row_idx][col_idx] = (val - min_per_col[col_idx]) / (max_per_col[col_idx] - min_per_col[col_idx])

data 定义为 2d numpy 数组。我实际上是在尝试使用min_per_colmax_per_col 中的相关值对data 中的每个元素执行一些操作。

我似乎无法弄清楚要采取的方法。从theseposts 看来,答案是重塑数组以便广播工作。

直观地说,我认为广播的工作方式是:

# Results of min_per_col: 
#     [min1 min2 min3 min4 min5]

# Transformation to (call this 2d_min_per_col):
#     [[min1 min2 min3 min4 min5],
#      [min1 min2 min3 min4 min5],
#      [min1 min2 min3 min4 min5]
#      ...
#      [min1 min2 min3 min4 min5]]
# which basically duplicates min_per_col into a 2d array form.

# Do the same for max (2d_max_per_col)

# processed_data = (data - 2d_min_per_col) / (2d_max_per_col - 2d_min_per_col)

这种方法有意义吗?或者对于如何处理这样的事情还有其他答案吗?

请让我知道是否有任何其他内容对这篇文章有帮助!谢谢。

编辑:感谢疯狂物理学家的帮助!尝试后:

processed_data = np.empty_like(data)
min_per_col = np.amin(data, axis=0) # axis0 for col, axis1 for row
max_per_col = np.amax(data, axis=0) # axis0 for col, axis1 for row
for row_idx, row in enumerate(data):
    for col_idx, val in enumerate(row):
        processed_data[row_idx, col_idx] = (val - min_per_col[col_idx]) / (max_per_col[col_idx] - min_per_col[col_idx])
print("version 1\n", processed_data)

processed_data = (data - min_per_col) / (max_per_col - min_per_col)
print("version 2\n", processed_data)

return processed_data

它的工作原理相同,而且速度更快!

version 1
 [[0.25333333 0.13793103 0.14285714]
 [0.32       0.79310345 0.92857143]
 [0.13333333 0.48275862 0.51785714]
 ...
 [0.28       0.4137931  0.125     ]
 [0.01333333 0.24137931 0.75      ]
 [0.08       0.20689655 0.23214286]]
version 2
 [[0.25333333 0.13793103 0.14285714]
 [0.32       0.79310345 0.92857143]
 [0.13333333 0.48275862 0.51785714]
 ...
 [0.28       0.4137931  0.125     ]
 [0.01333333 0.24137931 0.75      ]
 [0.08       0.20689655 0.23214286]]

感谢您的快速帮助:D

【问题讨论】:

  • 永远不要将一个 numpy 数组索引为[index1][index2],除非你知道你在做什么。始终使用[index1, index2]
  • 你试过广播的方式吗?它是否有效(与循环结果相同)?
  • 另外,广播的重点是你只需要min/max_per_col的第一行,而不是整个扩展数组。
  • 啊酷 - 从这个 numpy 文档numpy.org/devdocs/user/basics.indexing.html 看来原因是因为 [index1][index2] 在内存中创建了一个临时数组,而 [index1, index2] 直接访问元素没有介于两者之间,使 [index1, index2] 更优化。感谢您的提示!
  • 这是一个临时数组对象,但如果幸运的话,不会复制任何内存并获得视图,如本例所示。但是对于更复杂的索引,尤其是非切片索引,你只会遇到麻烦。很高兴你能找到它。

标签: python arrays numpy optimization array-broadcasting


【解决方案1】:

你有它的要点,但广播的全部意义在于你不需要扩展数组来对它们进行操作:形状在右边排列。例如,假设 data.shape(M, N) 您的数组形状在数学运算中看起来像这样:

data:           (M, N)
processed_data: (M, N)
min_per_col:       (N,)
max_per_col:       (N,)

请注意,min_per_colmax_per_col 按应有的方式完美排列。这意味着你的整个循环变得简单

processed_data = (data - min_per_col) / (max_per_col - min_per_col)
#                    (M, N)                         (N,)
#                                   (M, N)

每个算子下的 cmets 显示广播输出的形状。

顺便说一句,您可以使用np.ptp 一步计算分母:

processed_data = (data - np.min(data, axis=0)) / np.ptp(data, axis=0)

【讨论】:

  • 完美运行!非常感谢你的快速帮助,我确实学到了一些新东西——你的解释很有帮助:)
猜你喜欢
  • 1970-01-01
  • 2015-03-15
  • 2023-03-31
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 2023-01-09
  • 2020-11-20
相关资源
最近更新 更多