问题描述
我遇到了一个scipy函数,无论传递给它什么,它似乎都返回一个numpy数组.在我的应用程序中,我只需要能够传递标量和列表,因此唯一的问题"是当我将标量传递给函数时,将返回带有一个元素的数组(当我期望标量时).我应该忽略这种行为,还是修改函数以确保在传递标量时返回标量?
I'm encountering a scipy function that seems to return a numpy array no matter what's passed to it. In my application I need to be able to pass scalars and lists only, so the only "problem" is that when I pass a scalar to the function an array with one element is returned (when I would expect a scalar). Should I ignore this behaviour, or hack up the function to ensure that when a scalar is passed a scalar is returned?
示例代码:
#! /usr/bin/env python
import scipy
import scipy.optimize
from numpy import cos
# This a some function we want to compute the inverse of
def f(x):
y = x + 2*cos(x)
return y
# Given y, this returns x such that f(x)=y
def f_inverse(y):
# This will be zero if f(x)=y
def minimize_this(x):
return y-f(x)
# A guess for the solution is required
x_guess = y
x_optimized = scipy.optimize.fsolve(minimize_this, x_guess) # THE PROBLEM COMES FROM HERE
return x_optimized
# If I call f_inverse with a list, a numpy array is returned
print f_inverse([1.0, 2.0, 3.0])
print type( f_inverse([1.0, 2.0, 3.0]) )
# If I call f_inverse with a tuple, a numpy array is returned
print f_inverse((1.0, 2.0, 3.0))
print type( f_inverse((1.0, 2.0, 3.0)) )
# If I call f_inverse with a scalar, a numpy array is returned
print f_inverse(1.0)
print type( f_inverse(1.0) )
# This is the behaviour I expected (scalar passed, scalar returned).
# Adding [0] on the return value is a hackey solution (then thing would break if a list were actually passed).
print f_inverse(1.0)[0] # <- bad solution
print type( f_inverse(1.0)[0] )
在我的系统上,此输出为:
On my system the output of this is:
[ 2.23872989 1.10914418 4.1187546 ]
<type 'numpy.ndarray'>
[ 2.23872989 1.10914418 4.1187546 ]
<type 'numpy.ndarray'>
[ 2.23872989]
<type 'numpy.ndarray'>
2.23872989209
<type 'numpy.float64'>
我正在使用MacPorts提供的SciPy 0.10.1和Python 2.7.3.
I'm using SciPy 0.10.1 and Python 2.7.3 provided by MacPorts.
解决方案
阅读以下答案后,我决定采用以下解决方案.将f_inverse
中的返回行替换为:
After reading the answers below I settled on the following solution. Replace the return line in f_inverse
with:
if(type(y).__module__ == np.__name__):
return x_optimized
else:
return type(y)(x_optimized)
此处return type(y)(x_optimized)
使返回类型与调用该函数的类型相同.不幸的是,如果y是一个numpy类型,则此方法不起作用,因此if(type(y).__module__ == np.__name__)
用于,并将其排除在类型转换之外.
Here return type(y)(x_optimized)
causes the return type to be the same as the type the function was called with. Unfortunately this does not work if y is a numpy type, so if(type(y).__module__ == np.__name__)
is used to detect numpy types using the idea presented here and exclude them from the type conversion.
推荐答案
scipy.optimize.fsolve
中实现的第一行是:
x0 = array(x0, ndmin=1)
这意味着您的标量将变成1个元素的序列,而您的1个元素的序列将基本不变.
This means that your scalar will be turned into a 1-element sequence, and your 1-element sequence will be essentially unchanged.
看起来有效的事实是实现细节,我将重构您的代码以不允许将标量发送到fsolve
.我知道这似乎违背了鸭式输入法,但是该函数要求该参数使用ndarray
,因此您应该尊重该接口,以使其对实现的更改具有鲁棒性.但是,在包装函数中有条件地使用x_guess = array(y, ndmin=1)
将标量转换为ndarray
并在必要时将结果转换回标量,我看不到任何问题.
The fact that it seems to work is an implementation detail, and I would refactor your code to not allow sending a scalar into fsolve
. I know this might seem to go against duck-typing, but the function asks for an ndarray
for that argument, so you should respect the interface to be robust to changes in implementation. I don't, however, see any problem with conditionally using x_guess = array(y, ndmin=1)
for converting scalars into an ndarray
in your wrapper function and converting the result back to scalar when necessary.
这是fsolve
函数的文档字符串的相关部分:
Here is the relevant part of docstring of fsolve
function:
def fsolve(func, x0, args=(), fprime=None, full_output=0,
col_deriv=0, xtol=1.49012e-8, maxfev=0, band=None,
epsfcn=0.0, factor=100, diag=None):
"""
Find the roots of a function.
Return the roots of the (non-linear) equations defined by
``func(x) = 0`` given a starting estimate.
Parameters
----------
func : callable f(x, *args)
A function that takes at least one (possibly vector) argument.
x0 : ndarray
The starting estimate for the roots of ``func(x) = 0``.
----SNIP----
Returns
-------
x : ndarray
The solution (or the result of the last iteration for
an unsuccessful call).
----SNIP----
这篇关于scipy函数总是返回一个numpy数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!