我想将列表作为参数传递给 optimize.newton
.
我已经导入了一个 csv 并将每一行存储在一个数组中。代码如下:
with open('rand1.csv','rb') as f:
array=[]
for line in f:
array.append(line)
现在,如果我查看
array[1]
,看起来像:'2,6,76,45,78,1\r\n'
我将一个函数定义为:
def func(a,b,c,d,e,f):
return a*b*c-d*e-f
我正在运行牛顿方法:
res=[optimize.newton(func,5102,args=(x)) for x in array[0]]
但它给了我一个
TypeError
说": can only concatenate tuple (not "str") to tuple"
有人可以在这里帮助我吗?我知道元组元素必须用逗号分隔,我试过写
args=(x,)
也是,但它没有工作。
最佳答案
首先,请记住,在您的代码中,array
实际上不是一个 numpy 数组 - 它是一个普通的 Python list
的字符串。可以通过拆分字符串并将元素转换为整数来使用此列表,如 Anmol_uppal 的回答,但将 csv 文件的内容直接转换为 nrows x 6 numpy 数组要简单得多,例如使用 np.loadtxt
:
import numpy as np
data = np.loadtxt('rand1.csv', delimiter=',', dtype=np.int)
print(repr(data[0]))
# array([ 2, 6, 76, 45, 78, 1])
现在当您调用 optimize.newton
, args=
参数应该得到 6 个参数值的序列。您的原始代码不起作用,因为 array
中的每一行包含一个字符串,而不是 6 个数值。现在 data
* 是一个 nrows x 6 数组,每行将包含 6 个数值,所以你现在可以这样做:res = [optimize.newton(func, 5102, args=row) for row in data]
*请注意,我已将您的变量重命名为 array
至data
避免与 np.array
混淆类(class)更新
您的原始代码中还有另一个我最初没有发现的错误。查看
scipy.optimize.newton
的文档:func : function
The function whose zero is wanted. It must be a function of a single variable of the form f(x,a,b,c...), where a,b,c... are extra arguments that can be passed in the args parameter.
x0: float
An initial estimate of the zero that should be somewhere near the actual zero.
现在看看你的函数定义:def func(a,b,c,d,e,f): return a*b*c-d*e-f
func()
的第一个参数(你称之为a
)应该对应于 x 参数,那么只有 5 个额外的参数(根据你的定义是b ... f
)需要使用args=
传递.当你尝试打电话时发生的事情是 5102 被解释为optimize.newton(func, 5102, args=(422, 858, 129, 312, 79, 371))
x0
参数,并作为第一个参数传递给func()
.args=
中的 6 个值tuple 被视为额外参数,因此您的函数实际上总共有 7 个参数:显然,func(5102, 422, 858, 129, 312, 79, 371)
func()
被定义为接受 6 个参数,所以你会得到一个错误。解决此问题的正确方法取决于您如何解释函数的参数。newton
的目标是找到一个 x 的值,使得 f(x, a, b, c, ...) = 0。
您希望最小化 6 个参数中的哪一个func()
超过?
完整解释
一个稍微有趣的问题是,为什么当您将额外的参数作为数组(例如args=data[0]
)而不是元组传递时,您不会收到错误消息。答案有点复杂,但如果您有兴趣,请继续阅读。
如果你看看the source code forscipy.optimize.newton
您可以找到第一次调用您的函数的行:在这种情况下q0 = func(*((p0,) + args))
p0
和p1
将是x0
newton()
的参数, 和args
是一组额外的参数:q0 = func(*((5102,) + (422, 858, 129, 312, 79, 371)))
(p0,)
是一个元组,如果args
也是一个元组,然后+
运算符只需将这两个元组连接在一起:最后,q0 = func(*(5102, 422, 858, 129, 312, 79, 371))
*
解包元组以将参数传递给func
.最终调用如下所示:这将引发错误,因为 6 参数函数有 7 个参数。然而,当q0 = func(5102, 422, 858, 129, 312, 79, 371)
args
是np.array
:q0 = func(*(5102,) + array([422, 858, 129, 312, 79, 371]))
+
将增加值(value)p0
到args
中的每个元素:因为现在只有 6 个参数转到q0 = func(*(5524, 5960, 5231, 5414, 5181, 5473))
func()
调用会成功,但是newton
会收敛到错误的答案!
我认为这在 scipy 中不是特别好的设计 - 它让我感到震惊,因为在大多数其他情况下,任何类似数组的输入都可以,包括列表、元组、数组等。公平地说,它确实在newton
的文档中说那args=
应该是一个元组,但为了安全起见,我仍然会进行类型检查或将其显式转换为元组。我可以尝试在 scipy 中解决这个问题。
关于Python:在 scipy.optimize.newton 中将列表作为参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28091246/