Python循环中的v-stacking

时间:2015-12-01 17:25:25

标签: python performance numpy append concatenation

我在这个计算机视觉book中经历了一个例子,对代码感到有些惊讶:

descr = []
descr.append(sift.read_features_from_file(featurefiles[0])[1])
descriptors = descr[0] #stack all features for k-means
for i in arange(1,nbr_images):
  descr.append(sift.read_features_from_file(featurefiles[i])[1])
  descriptors = vstack((descriptors,descr[i]))

对我来说,这似乎是一遍又一遍地复制数组,更有效的实现方式是:

descr = []
descr.append(sift.read_features_from_file(featurefiles[0])[1])
for i in arange(1,nbr_images):
  descr.append(sift.read_features_from_file(featurefiles[i])[1])
descriptors = vstack((descr))

或者我在这里遗漏了一些东西,这两个代码并不相同。我做了一个小测试:

print("ATTENTION")
print(descriptors.shape)
print("ATTENTION")
print(descriptors[1:10])

似乎列表不同了?

enter image description here

1 个答案:

答案 0 :(得分:1)

你是绝对正确的 - 在循环中反复连接numpy数组极其效率低下。连接始终会生成一个副本,随着您的数组在循环内变得越来越大,这会变得越来越昂贵。

相反,做两件事之一:

  1. 正如您所做的那样,将中间值存储在常规Python list中并将其转换为循环外的numpy数组。附加到list的是 O(1),而连接np.ndarray的是 O(n + k)

  2. 如果您知道最终数组的提前量,您可以预先分配它,然后填写for循环内的行,例如:

    descr = np.empty((nbr_images, nbr_features), dtype=my_dtype)
    for i in range(nbr_image):
        descr[i] = sift.read_features_from_file(featurefiles[i])[1]
    
  3. 另一种变体是使用np.fromiter从可迭代对象延迟生成数组,例如在this recent question中。