本文介绍了scipy函数总是返回一个numpy数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个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数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 07:50