Python 列表中的映射

3 投票
3 回答
994 浏览
提问于 2025-04-17 15:01

我有一个存储在元组列表中的索引列表:

index=[(0,0), (0,1), (1,0), (1,1) ....]

这些索引将用于根据以下公式计算图像 im 的能量(im 是一个 numpy 数组):

(1-im[0,0])^2+(1-im[0,1])^2+....

这里的 im 是一个二维的 numpy 数组。以下是 im 的一个示例:

im=Image.open('lena_noisy.png')
im=numpy.array(im)
print im

[[168 133 131 ..., 127 213 107]
 [174 151 111 ..., 191  88 122]
 [197 173 143 ..., 182 153 125]
 ..., 
 [ 34  15   6 ..., 111  95 104]
 [ 37  15  57 ..., 121 133 134]
 [ 49  39  58 ..., 115  74 107]]

如何使用列表的 map 函数来进行这个计算呢?

3 个回答

2

像这样,使用生成器表达式:

sum((1-im[i][j])**2 for i, j in index)

也就是说,假设 im 是一个二维列表,而 index 是一个在 im 中的坐标列表。需要注意的是,在Python中,访问二维列表的方式是这样的:m[i][j],而不是这样:m[i,j]

4

如果你把 index 拆分成两个元组,分别叫 xidxyidx,那么你就可以用一种叫做“花式索引”的方法来一次性获取所有的 im 值,并把它们放到一个 numpy 数组里。

这样一来,计算就变得简单多了,而且比用 Python 的循环(或者列表推导式)要快。

import numpy as np
xidx, yidx = zip(*index)
print(((1-im[xidx, yidx])**2).sum())

import numpy as np
import scipy.misc as misc

im = misc.lena()
n = min(im.shape)
index = np.random.randint(n, size = (10000,2)).tolist()

def using_fancy_indexing(index, im):
    xidx, yidx = zip(*index)
    return (((1-im[xidx, yidx])**2).sum())

def using_generator_expression(index, im):
    return sum(((1 - im[i[0], i[1]]) ** 2) for i in index)

这里有一个用 timeit 进行的比较:

In [27]: %timeit using_generator_expression(index, im)
100 loops, best of 3: 17.9 ms per loop

In [28]: %timeit using_fancy_indexing(index, im)
100 loops, best of 3: 2.07 ms per loop

所以,根据 index 的大小,使用花式索引可能比使用生成器表达式快 8 倍。

1

使用 sum 和生成器表达式:

sum(((1 - im[i[0], i[1]]) ** 2) for i in index)

如果索引也是一个 numpy 数组,你可以直接用这个数组作为索引:

sum(((1 - im[i]) ** 2) for i in index)

撰写回答