在 python 中组合使用 max、xrange 和 lambda 函数

the use of combining max, xrange and lambda function in python

我找到了一个为 LU 分解旋转方阵的代码,但我无法理解其中的一些代码。

def pivotize(m):
    """Creates the pivoting matrix for m."""
    n = len(m)
    ID = [[float(i == j) for i in xrange(n)] for j in xrange(n)]
    for j in xrange(n):
        row = max(xrange(j, n), key=lambda i: abs(m[i][j]))
        if j != row:
            ID[j], ID[row] = ID[row], ID[j]
    return ID

首先,ID 行不就是单位矩阵吗?这样做有什么好处吗?

其次,我不能真正理解行的行。我知道 lambda 用于在文本中定义一个函数,一旦提供了 i 的值(j 的值取决于 for 循环),它只是 returns M_ij 的值,但我是什么?

而且 xrange 不是类似于 range 吗?但是这里 return 是什么意思?

当与函数 max 结合使用时,会发生什么?就是不知道max函数里面有什么东西在比较。

抱歉,如果这个问题听起来很愚蠢。我是编程新手

First, isn't the line for ID simply the identity matrix?

是的。

Second, I can't really understand the line for row....

See this 讨论 max/key/lambda 互动。要回答 "what is i?",它是 lambda 函数的参数,对于 fooi 等效于 x。 (为清楚起见,分别生成 abs(m[x][j])abs(m[foo][j]))。

And isn't xrange similar to range?

是的。在 Python 2 xrange returns 中,仅在需要时延迟计算下一个值的序列对象。 See this for more info。当完全循环时,rangexrange 将产生相同的结果,但实现不同。

But what does it return here?

第 5 行的 xrange(n) 将 return 从 0 到 (n-1) 的整数值,而第 6 行的 xrange(j, n) 将 return 从 j 到 ( n-1).

编辑

关于 lambda 的更多信息:

想一想如何将给定的数字序列加倍。首先定义一个将数字 x 和 return 加倍的函数。然后将该函数映射到序列的每个元素。

# Traditional
def double(x): return x*2
print map(double, [1,2,3,4])         # [2, 4, 6, 8]

您也可以使用匿名 (lambda) 函数来做同样的事情:

# Lambda
print map(lambda i: i*2, [1,2,3,4])  # [2, 4, 6, 8]

请注意,除了 double 函数的定义消失并且调用 map 中对该函数的引用被 "inline" lambda 替换之外,其他一切都是一样的功能。

编辑 2

And when combined with the function max, what happens?

这一行row = max(xrange(j, n), key=lambda i: abs(m[i][j]))可以分解如下:

  • xrange(j,n)生成从j(含)到n(不含)的整数序列。
  • 这些整数中的每一个然后 "passed" 作为键参数中函数的参数。换句话说,它们分别用作 lambda 函数中的 i。 lambda 函数 "returns" 第 i 行和 j 列的绝对值。[1]
  • 然后 max 函数找到这些 "lambda outputs" 的最大值并设置 row 等于它。

这也可以写成列表理解的最大值:

row = max( [abs(m[i][j]) for i in xrange(j,n)] )

或者正如 Dan D. 在他的评论中指出的那样,写成一个生成器表达式(不创建中间列表)简单地:

row = max( abs(m[i][j]) for i in xrange(j,n) )

备注:

[1] 这里有一些假设,但行列是表示矩阵的标准方式。

xrange 是一个 Python2 结构,用于处理 range 内存效率。 Beforerange 实际上创建了一个列表,然后 for 循环会 运行 通过它。 xrange 然而是一个生成器,这意味着它在被要求时一次吐出 1 个值,而不创建完整列表。

ID其实就是一个单位矩阵。你就在那里。这是一个巧妙的技巧,可以将布尔值转换为值 1.0.

的浮点数

然后代码段 运行 遍历所有剩余的行,并在原始矩阵 row = max(xrange(j, n), key=lambda i: abs(m[i][j])) 中找到该行的最大值。请注意,这里有第二个不错的技巧,max 可以对任何可迭代对象进行操作,包括生成器。该行中的 lambda 关键字表示所谓的 "anonymous function"。

更多详细信息:匿名函数是未绑定到标识符的函数。代码段中的 Lambda 函数接受 1 个值,i 和 return 是矩阵位置 m[i][j] 处的绝对值。作为函数输入发送的值由生成器 xrange(j, n) 提供。

max 然后将 lambda 函数的 return 值作为它实际比较的对象。例如,在 python3 中无法比较 2 种不同的类型。 IE。比较 string > int 会产生:TypeError: unorderable types: str() > int()。但是,如果我们确定该列表包含数字,只是格式不同,您可以执行以下操作:

>>> l = ["1", "2", 3, 4]
>>> max(l, key=lambda x: int(x))
4
>>> min(l, key=lambda x: int(x))
'1' #type 'str'

这只是表明,实际比较值是您的 key 函数的 return,但实际产生的值是您的原始输入值。

一旦它找到行最大值,它"rotates",通过替换ID[j], ID[row] = ID[row], ID[j],所有其他行,在单位矩阵,围绕它这样只有最大值留在对角线上。

这有助于防止在下一步的 LU 分解中除数过小。

您在 return 中得到的不是旋转后的原始矩阵,而是 1.0s 和 0.0s 的矩阵,即乘以original 将产生旋转矩阵。

这似乎是一个编写得很好的函数,可以节省内存并有助于 python 中的性能。希望我做对了。