1

渡されたものに関係なく、numpy 配列を返すように見える scipy 関数に遭遇しました。私のアプリケーションでは、スカラーとリストのみを渡すことができる必要があるため、唯一の「問題」は、関数にスカラーを渡すと、1 つの要素を持つ配列が返されることです (スカラーが必要な場合)。この動作を無視するか、関数をハックして、スカラーが渡されたときにスカラーが返されるようにする必要がありますか?

コード例:

#! /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] )

私のシステムでは、これの出力は次のとおりです。

[ 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 を使用しています。

解決

以下の回答を読んだ後、次の解決策に落ち着きました。の戻り行を次のように置き換えますf_inverse

if(type(y).__module__ == np.__name__):
    return x_optimized
else:
    return type(y)(x_optimized)

ここでreturn type(y)(x_optimized)は、戻り値の型が、関数が呼び出された型と同じになります。残念ながら、これは y が numpy 型の場合は機能しないため、ここで提示されたアイデアを使用して numpy 型を検出し、型変換から除外するためif(type(y).__module__ == np.__name__)に使用されます。

4

4 に答える 4

3

の実装の最初の行scipy.optimize.fsolveは次のとおりです。

x0 = array(x0, ndmin=1)

これは、スカラーが 1 要素のシーケンスに変換され、1 要素のシーケンスが本質的に変更されないことを意味します。

それが機能しているように見えるという事実は実装の詳細であり、スカラーを に送信できないようにコードをリファクタリングしますfsolve。これはダックタイピングに反するように見えるかもしれませんが、関数はndarrayその引数を要求するため、実装の変更に対して堅牢であるインターフェイスを尊重する必要があります。ただし、ラッパー関数でx_guess = array(y, ndmin=1)スカラーを に変換するために条件付きで使用し、必要に応じて結果をスカラーに戻すことに問題はありません。ndarray

fsolve関数のドキュメント文字列の関連部分は次のとおりです。

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----
于 2012-09-24T13:21:05.523 に答える
2

Numpy 配列をリストに、Numpy スカラーを Python スカラーに変換する方法は次のとおりです。

>>> x = np.float32(42)
>>> type(x)
<type 'numpy.float32'>
>>> x.tolist()
42.0

つまり、toliston のメソッドnp.ndarrayはスカラーを特別に処理します。

それでも単一要素のリストが残りますが、それらは通常の方法で簡単に処理できます。

于 2012-09-24T15:04:51.357 に答える
1

As @wim pointed out, fsolve transforms your scalar into a ndarray of shape (1,) and returns an array of shape (1,).

If you really want to get a scalar as output, you could try to put the following at the end of your function:

if solution.size == 1:
    return solution.item()
return solution

(The item method copies an element of an array and return a standard Python scalar)

于 2012-09-24T14:29:40.933 に答える
1

私はウィムの答えがすでにほとんどそれを言っていると思いますが、おそらくこれは違いをより明確にします。

numpy によって返されるスカラーは、array[0](ほぼ?) 標準の python float と完全に互換性があるはずです:

a = np.ones(2, dtype=float)
isinstance(a[0], float) == True # even this is true.

ほとんどの場合、サイズが 1 の配列はスカラーとリストの両方と互換性がありますが、たとえば float は可変オブジェクトではありません。

a = np.ones(1, dtype=float)
import math
math.exp(a) # works
# it is not isinstance though
isinstance(a, float) == False
# The 1-sized array works sometimes more like number:
bool(np.zeros(1)) == bool(np.asscalar(np.zeros(1)))
# While lists would be always True if they have more then one element.
bool([0]) != bool(np.zeros(1))

# And being in place might create confusion:
a = np.ones(1); c = a; c += 3
b = 1.; c = b; c += 3
a != b

したがって、ユーザーがそれを知らなければ、前者は問題なく、後者は危険だと思います。

np.asscalar(result)サイズ 1 の配列 (任意の次元) を正しい python スカラーに変換するために使用することもできます。

[29]: type(np.asscalar(a[0])) アウト[29]: float

numpy について知らないはずのユーザーに驚きがないようにしたい場合は、スカラーが渡された場合、少なくとも 0 の要素を取得する必要があります。ユーザーが numpy を認識している必要がある場合は、ドキュメントだけがおそらく同じくらい良いです。

于 2012-09-24T14:19:34.417 に答える