这是使我的函数(以前预期的列表)与所有iterables一起工作的好方法吗?

2024-04-23 18:40:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经写了下面的函数来做两个参数的线性回归(它背后的实际数学与这个问题无关)。它有两个函数,f1f2,和两个列表xsys

def lr2par(f1, f2, xs, ys):
    c11 = sum(map(lambda x: (f1(x))**2, xs))
    c12 = sum(map(lambda x: f1(x) * f2(x), xs))
    c22 = sum(map(lambda x: (f2(x))**2, xs))
    d1 = sum(map(lambda x, y: y*f1(x), xs,ys))
    d2 = sum(map(lambda x, y: y*f2(x), xs,ys))

    a1 = -(c22*d1 - c12*d2)/(c12*c12 - c11*c22)
    a2 = (c12*d1 - c11*d2)/(c12*c12 - c11*c22)

    return (c11, c12, c22, d1, d2, a1, a2)

只要xsys是列表,它就可以正常工作。但是,正如您所看到的,它是以一种非常函数化的风格编写的,所以我当然希望能够在函数代码中优雅地使用这个函数。这包括在我将一个函数输入到函数之前,在一个列表上调用一个函数,如map,如本例中的ys参数:

lr2par(lambda x: x, lambda x: 1, [1, 3, 5, 7], map(math.log, [130, 150, 175, 210]))

对我来说,这看起来很自然,我希望它能工作(尽管我是一个python noob)。事实证明不是。我很确定问题是ys参数现在不再是一个列表,而是一个迭代器(在python中使用函数工具时,它似乎是主要类型),只能迭代一次,所以当它涉及到行时

d2 = sum(map(lambda x, y: y*f2(x), xs,ys))

ys只是空的。我想用惯用的功能性python方法来解决这个问题。我目前的解决方案是添加行

xs = list(xs)
ys = list(ys)

到函数体的开头。这是可行的,但这是解决问题的好方法吗?我是否必须将这些行添加到几乎所有使用对象集合的函数中,并希望这些函数能够很好地与mapfilterzip等函数配合使用?你知道吗


Tags: lambda函数map列表参数f2f1d2
1条回答
网友
1楼 · 发布于 2024-04-23 18:40:15

一般来说,不能对iterable进行两次迭代。如果需要,必须首先将其转换为序列,就像对list所做的那样,这实际上是一个非常标准的解决方案。你知道吗

主要的问题是它可能效率低下,因为它会复制任何传入的列表或元组,因此您可能需要检查这些列表或元组,并用以下helper函数替换list

from collections import Sequence  # ABC for lists and tuples

def tosequence(it):
    """Convert iterable to sequence, avoiding unnecessary copies."""
    return it if isinstance(it, Sequence) else list(it)

(作为站点注释,如果用生成器理解替换maplambda,代码的可读性会提高很多;如果重写为使用NumPy,代码的可读性也会提高很多,我建议在Python中使用NumPy)

相关问题 更多 >