1

我想将列表作为参数传递给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,),但没有奏效。

4

2 回答 2

1

首先,请记住,在您的代码中,array它实际上不是一个 numpy 数组 - 它是一个普通list的 Python 字符串。可以通过拆分字符串并将元素转换为整数来使用此列表,如 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]

*请注意,我已重命名您的变量arraydata避免与np.array类混淆


更新

您的原始代码中还有另一个我最初没有发现的错误。查看以下文档scipy.optimize.newton

函数:函数

想要零的函数。它必须是f(x,a,b,c...) 形式的单个变量的函数,其中 a,b,c... 是可以在 args 参数中传递的额外参数。

x0:浮动

零的初始估计应该在实际零附近的某个地方。

现在看看你的函数定义:

def func(a,b,c,d,e,f):
    return a*b*c-d*e-f

(您调用的)的第一个参数应该对应于x参数,然后只有5 个额外的参数(根据您的定义)需要使用. 当你尝试打电话时func()ab ... fargs=

optimize.newton(func, 5102, args=(422, 858, 129, 312, 79, 371))

发生的情况是 5102 被解释为x0参数,并作为第一个参数传递给func(). 元组中的6 个args=被视为额外参数,因此您的函数实际上总共获得7 个参数:

func(5102, 422, 858, 129, 312, 79, 371)

显然,func()被定义为接受 6 个参数,所以你会得到一个错误。解决此问题的正确方法取决于您如何解释函数的参数。的目标newton是找到x的值,使得f(x, a, b, c, ...) = 0

您希望最小化 6 个参数中的哪一个func()


完整解释

一个稍微有趣的问题是,为什么当您将额外的参数作为数组(例如args=data[0])而不是元组传递时,您不会收到错误消息。答案有点复杂,但如果您有兴趣,请继续阅读。

如果您查看源代码,scipy.optimize.newton您可以找到第一次调用函数的行:

q0 = func(*((p0,) + args))

在这种情况下p0, andp1将是 , 的x0参数newton(),并且args是一组额外的参数:

q0 = func(*((5102,) + (422, 858, 129, 312, 79, 371)))

(p0,)是一个元组,如果args也是一个元组,那么+运算符只需将这两个元组连接在一起:

q0 = func(*(5102, 422, 858, 129, 312, 79, 371))

最后,*解包元组以将参数传递给func. 最终调用如下所示:

q0 = func(5102, 422, 858, 129, 312, 79, 371)

这将引发错误,因为 6 参数函数有 7 个参数。但是,什么时候argsnp.array

q0 = func(*(5102,) +  array([422, 858, 129, 312, 79, 371]))

+将为中的每个元素添加值:p0args

q0 = func(*(5524, 5960, 5231, 5414, 5181, 5473))

由于现在只有6 个参数func()调用会成功,但newton会收敛到错误的答案!

我认为这在 scipy 中不是特别好的设计 - 它让我感到震惊,因为在大多数其他情况下,任何类似数组的输入都可以,包括列表、元组、数组等。公平地说,它确实在文档中newtonargs=应该是一个元组,但为了安全起见,我仍然会进行类型检查或将其显式转换为元组。我可以尝试在 scipy 中解决这个问题。

于 2015-01-23T11:22:58.957 回答
0

首先,您需要删除该尾随'\r', '\t',为此您可以使用.strip(),现在您有一个字符串,其中所需的元素用逗号分隔,在这里您可以使用.split()方法并传递要在给定字符串上拆分的字符。最后我们使用了 map() 函数,该函数将函数作为第一个参数(在本例中为 int ),第二个参数是一个列表或元组,并将该元组列表的每个元素与作为第一个参数传递的函数进行映射。

line = '2,6,76,45,78,1\r\n'
line_stripped = line.strip()
print line_stripped
>>> '2,6,76,45,78,1'

line_splitted = line_stripped.split(",")
print line_splitted
>>> '2' ,'6', '76', '45', '78', '1'

line_integers = map(int,line_splitted)
print line_integers
>>> [2, 6, 76, 45, 78, 1]

结合上述所有步骤,我们可以干净地将其写为:

with open('rand1.csv','rb') as f:
    array=[]
    for line in f:
        array.append(map(int,line.strip().split(',')))
于 2015-01-22T14:41:38.647 回答