如何在Python中向量化数组操作

3

我正在用Python编写一个k最近邻分类器。但是我遇到了一个问题,就是数组操作太慢了。

def classify(k, train_data, target):
    num_rows = train_data.shape[0]
    num_cols = train_data.shape[1]
    distances = []
    candidates = [0] * 10

    for i, row in enumerate(train_data):
        dist = euclidean_dist(target[:num_cols - 1], row[:num_cols - 1]) #slow
        distances.append((dist, row[num_cols - 1]))

    distances.sort(key=lambda tup: tup[0])
    distances = distances[:k]

    for i, d in enumerate(distances):
        candidates[d[1]] += 1

    return candidates.index(max(candidates))

def euclidean_dist(x1, x2):
    assert(len(x1) == len(x2))
    result = 0

    pdb.set_trace()
    for i in range(len(x1)): #culprit, x1 and x2 are both 256 length lists
        result += math.pow(x1[i] - x2[i], 2)
    result = math.sqrt(result)

    return result

我在上面的代码中添加了注释,显示出问题发生的位置。欢迎提出任何使其更快的建议。


看一下np.vectorize - Anton Protopopov
1
你可能有很好的理由来实现自己的分类器(编程练习、非常特定、棘手、数据),但是这里有经过充分测试和广泛使用的scikit-learn库,其中包含各种神经网络算法和分类器。 - user707650
@AntonProtopopov: 做法不好。正如文档所说,“vectorize”函数主要是为了方便,而非性能。其实现本质上就是一个for循环。它只是对于那些不需要关注性能的代码提供了一种快速且简单的解决方案。当你真正需要NumPy的速度优势时,“np.vectorize”就没用了。 - user2357112
1个回答

2

看起来您只是想要欧几里得距离/2范数,您可以通过numpy(作为np导入)相当高效地获得:

def euclidean_dist2(x1, x2):
    assert(len(x1) == len(x2))

    x1 = np.array(x1)
    x2 = np.array(x2)

    norm = np.linalg.norm(x1-x2)

    return norm

print euclidean_dist2([1,2],[4,7])

这将给你5.83095189485,与你之前的函数相同,但进行了矢量化处理。

简单来说,您只需取元素差值,将所得向量相乘(平方),求和,然后开方即可:

def euclidean_dist3(x1, x2):
    assert(len(x1) == len(x2))

    x1 = np.array(x1)
    x2 = np.array(x2)

    diff = x1 - x2

    squared = np.transpose(diff) * diff

    summed = sum(squared)

    norm = np.sqrt(summed)

    return norm

换句话说,你只需将差向量与自身进行点积即可:

def euclidean_dist4(x1, x2):
    assert(len(x1) == len(x2))

    x1 = np.array(x1)
    x2 = np.array(x2)

    diff = x1 - x2

    dot = np.dot(diff, diff)

    norm = np.sqrt(dot)

    return norm

实现同一目标的不同方法

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接