是否有可能在Python中加速这个循环?

时间:2017-11-30 04:47:34

标签: python numpy

numpy.narray np.array[map(some_func,x)]vectorize(f)(x) dis_mat = np.zeros([feature_mat.shape[0], feature_mat.shape[0]]) for i in range(feature_mat.shape[0]): for j in range(i, feature_mat.shape[0]): dis_mat[i, j] = np.linalg.norm( feature_mat[i, :] - feature_mat[j, :] ) dis_mat[j, i] = dis_mat[i, j] 中映射函数的常规方法无法提供索引。 以下代码只是许多应用程序中常见的一个简单示例。

    from scipy.spatial.distance import pdist,squareform
    dis_mat = squareform(pdist(feature_mat))

有没有办法加快速度?

感谢您的帮助!使用@user2357112评论的函数来加速此代码的最快方法是:

feature_mat
如果feature_mat很小,那么

@Julienmethod也很好,但当import java.util.Scanner; import java.io.*; public class practice3 { public static void main(String[] args) throws IOException { int[] array = new int [99]; array = inputData(); for(int i=0; i<array.length; i++) System.out.printf("%d",array[i]); } public static int[] inputData() throws IOException { final int MAX= 100; int[] nums = new int[MAX]; int count = 0; Scanner kb = new Scanner(System.in); System.out.print("Enter input file name: "); String input = kb.nextLine(); File file = new File(input); if(!file.exists()) { System.out.println("The file entered is not found"); System.exit(0); } Scanner inputFile = new Scanner(file); while(inputFile.hasNext() && count < nums.length) { nums[count] = inputFile.nextInt(); count++; } inputFile.close(); return nums; } public static void printArray(int[] array, int counter) { System.out.println("Original array: "); System.out.printf("%,12\n", array); } } 在2000年时为1000时,它需要近40 GB的内存。< / p>

6 个答案:

答案 0 :(得分:16)

SciPy附带了一个专门用于计算您计算的成对距离类型的函数。它是scipy.spatial.distance.pdist,它以精简格式生成距离,基本上只存储距离矩阵的上三角形,但是您可以将结果转换为带有scipy.spatial.distance.squareform的方形:

from scipy.spatial.distance import pdist, squareform

distance_matrix = squareform(pdist(feature_mat))

这有利于避免直接矢量化解决方案所需的巨大中间阵列,因此速度更快,适用于更大的输入。但是它失去了an approach that uses algebraic manipulations to have dot handle the heavy lifting的时间。

pdist还支持各种备用距离指标,如果您决定要使用欧几里德距离以外的其他指标。

# Manhattan distance!
distance_matrix = squareform(pdist(feature_mat, 'cityblock'))

# Cosine distance!
distance_matrix = squareform(pdist(feature_mat, 'cosine'))

# Correlation distance!
distance_matrix = squareform(pdist(feature_mat, 'correlation'))

# And more! Check out the docs.

答案 1 :(得分:13)

您可以创建新轴并广播:

dis_mat = np.linalg.norm(feature_mat[:,None] - feature_mat, axis=-1)

定时:

feature_mat = np.random.rand(100,200)

def a():
    dis_mat = np.zeros([feature_mat.shape[0], feature_mat.shape[0]])
    for i in range(feature_mat.shape[0]):
        for j in range(i, feature_mat.shape[0]):
            dis_mat[i, j] = np.linalg.norm(
                feature_mat[i, :] - feature_mat[j, :]
            )
            dis_mat[j, i] = dis_mat[i, j]

def b():
    dis_mat = np.linalg.norm(feature_mat[:,None] - feature_mat, axis=-1)



%timeit a()
100 loops, best of 3: 20.5 ms per loop

%timeit b()
100 loops, best of 3: 11.8 ms per loop

答案 2 :(得分:8)

考虑可以做什么,并在np.dot矩阵上使用k x k优化,在小内存位置(kxk):

def c(m): 
    xy=np.dot(m,m.T) # O(k^3)
    x2=y2=(m*m).sum(1) #O(k^2)
    d2=np.add.outer(x2,y2)-2*xy  #O(k^2)
    d2.flat[::len(m)+1]=0 # Rounding issues
    return np.sqrt(d2)  # O (k^2)

为了比较:

def d(m):
   return  squareform(pdist(m))

以下是k * k初始矩阵的'时间(it)':

Enter image description here

这两个算法是O(k ^ 3),但c(m)通过np.dot得到作业的O(k ^ 3)部分,pdist是线性代数的关键节点,它受益于所有{ {3}}(多核等)。 pdist只是optimizations中的循环。

这解释了大数组的15倍因子,即使imagename_queue = tf.train.string_input_producer(images, shuffle=False) labelname_queue = tf.train.string_input_producer([csv_label], shuffle=False) # print(type(labelname_queue)) image_reader = tf.WholeFileReader() key_img, raw_img = image_reader.read(imagename_queue) csv_reader = tf.TextLineReader() key_txt, raw_txt = csv_reader.read(labelname_queue) jpg_image = tf.image.decode_jpeg(raw_img) csv_label = tf.decode_csv(raw_txt, record_defaults=[[0]]) jpg_image = tf.reduce_mean(jpg_image, axis=2) jpg_image = tf.reshape(jpg_image, [W_img, H_img, 1]) 仅通过计算一半的术语来利用矩阵的对称性。

答案 3 :(得分:2)

我想避免混用NumPy和for循环的一种方法是使用允许替换的版本of this index creator创建索引数组:

import numpy as np
from itertools import product, chain
from scipy.special import comb

def comb_index(n, k):
    count = comb(n, k, exact=True, repetition=True)
    index = np.fromiter(chain.from_iterable(product(range(n), repeat=k)),
                        int, count=count*k)
    return index.reshape(-1, k)

然后,我们简单地获取每个数组对,计算它们之间的差异,重新生成结果数组,并采用数组中每一行的范数:

reshape_mat = np.diff(feature_mat[comb_index(feature_mat.shape[0], 2), :], axis=1).reshape(-1, feature_mat.shape[1])
dis_list = np.linalg.norm(reshape_mat, axis=-1)

请注意,dis_list只是所有n*(n+1)/2可能norms的列表。这与他提供的feature_mat的其他答案的速度接近,并且在比较我们最大部分的字节大小时,

(feature_mat[:,None] - feature_mat).nbytes == 16000000

,而

np.diff(feature_mat[comb_index(feature_mat.shape[0], 2), :], axis=1).reshape(-1, feature_mat.shape[1]).nbytes == 8080000

对于大多数投入,我只使用了一半的存储:仍然不是最理想的,但是边际改善。

答案 4 :(得分:2)

基于func initiateCentralManager(){ manager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionRestoreIdentifierKey : "MyBLECurrentState"]) } func centralManagerDidUpdateState(_ central: CBCentralManager){ print("Received CBCentralManager state") peripheralArray.removeAll() if central.state == .poweredOn { print("poweredOn") } else if central.state == .poweredOff { print("poweredOff") } } ,如果你真的想用纯NumPy做这件事:

np.triu_indices

这种方法相对于广播的好处是你可以用块来做:

s = feature_mat.shape[0]
i, j = np.triu_indices(s, 1)         # All possible combinations of indices
dist_mat = np.empty((s, s))          # Don't waste time filling with zeros
np.einsum('ii->i', dist_mat)[:] = 0  # When you can just fill the diagonal
dist_mat[i, j] = dist_mat[j, i] = np.linalg.norm(feature_mat[i] - feature_mat[j], axis=-1)
                                     # Vectorized version of your original process

答案 5 :(得分:-1)

让我们从函数的重写开始:

dist(mat, i, j):
    return np.linalg.norm(mat[i, :] - mat[j, :])

size = feature_mat.shape[0]

for i in range(size):
    for j in range(size):
        dis_mat[i, j] = dist(feature_mat, i, j)

这可以用(稍微更多)矢量化形式重写为:

v = [dist(feature_map, i, j) for i in range(size) for j in range(size)]
dist_mat = np.array(v).reshape(size, size)

请注意,我们仍然依赖于Python而不是NumPy进行某些计算,但它是向量化的一步。还要注意dist(i, j)是对称的,因此我们可以进一步减少大约一半的计算量。也许正在考虑:

v = [dist(feature_map, i, j) for i in range(size) for j in range(i + 1)]

现在棘手的一点是将这些计算值分配给dist_mat中的正确元素。

此效果的速度取决于计算dist(i, j)的成本。对于较小的feature_mat,重新计算的成本不足以担心这一点。但是对于大型矩阵,你绝对不想重新计算。