Scipy-Funktion gibt immer ein numpy Array zurück

Ich begegne einer scipy-Funktion, die scheint, ein numpy Array zurückzugeben, egal was an sie weitergegeben wird. In meiner Bewerbung muss ich nur Skalare und Listen abgeben können, also das einzige "Problem" ist, dass wenn ich einen Skalar an die Funktion übergehe, ein Array mit einem Element zurückgegeben wird (wenn ich einen Skalar erwarten würde). Soll ich dieses Verhalten ignorieren oder die Funktion hacken, um sicherzustellen, dass bei einem Skalar ein Skalar zurückgegeben wird?

Beispielcode:

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

Auf meinem System ist die Ausgabe davon:

 [ 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'> 

Ich verwende SciPy 0.10.1 und Python 2.7.3 von MacPorts zur Verfügung gestellt.

LÖSUNG

Nachdem ich die Antworten gelesen hatte, setzte ich mich auf die folgende Lösung ein. Ersetzen Sie die Rücklaufleitung in f_inverse mit:

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

Hier gibt der return type(y)(x_optimized) den Rückgabetyp als der Typ, mit dem die Funktion aufgerufen wurde. Leider funktioniert das nicht, wenn y ein numpy-Typ ist, also if(type(y).__module__ == np.__name__) verwendet wird, um numpy-Typen mit der hier vorgestellten Idee zu erkennen und sie von der Typumwandlung auszuschließen.

4 Solutions collect form web for “Scipy-Funktion gibt immer ein numpy Array zurück”

Die erste Zeile der Implementierung in scipy.optimize.fsolve ist:

x0 = array(x0, ndmin=1)

Dies bedeutet, dass Ihr Skalar in eine 1-Element-Sequenz umgewandelt wird und Ihre 1-Element-Sequenz im Wesentlichen unverändert bleibt.

Die Tatsache, dass es zu funktionieren scheint, ist ein Implementierungsdetail, und ich würde Ihren Code umgestalten, um nicht zu erlauben, einen Skalar in fsolve zu fsolve . Ich weiß, dass dies scheinen, gegen Ente-Typing zu gehen, aber die Funktion fragt nach einem ndarray für dieses Argument, also sollten Sie die Schnittstelle respektieren, um robust zu Änderungen in der Implementierung zu sein. Ich sehe jedoch kein Problem mit der bedingten Verwendung von x_guess = array(y, ndmin=1) zum Konvertieren von Skalaren in ein ndarray in deiner Wrapper-Funktion und das Umwandeln des Ergebnisses zurück zu Skalar, wenn nötig.

Hier ist der relevante Teil des docstrings der fsolve Funktion:

 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---- 

Hier kannst du Numpy Arrays zu Listen und Numpy Skalaren zu Python Skalaren umwandeln:

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

Mit anderen Worten, die tolist Methode auf np.ndarray behandelt Skalare speziell.

Das verlässt dich immer noch mit Einzelelementen, aber das ist einfach genug, um in der üblichen Weise zu handeln.

Ich vermute, Wims Antwort wirklich schon sagt es meistens, aber vielleicht macht das die Unterschiede klarer.

Der Skalar, der von numpy zurückgegeben wird, sollte mit array[0] (fast?) Voll kompatibel zum Standard-Python-Float sein:

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

Zum größten Teil ist bereits das 1-stellige Array kompatibel zu einem Skalar und einer Liste, obwohl es zB ein veränderliches Objekt ist, während der Float nicht:

 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 

Also, wenn der Benutzer es nicht wissen sollte, ich denke, das erste ist gut das zweite ist es gefährlich.

Sie können auch np.asscalar(result) , um ein Array der Größe 1 (beliebiger Dimension) in den richtigen Python-Skalar zu konvertieren:

In [29]: Typ (np.asscalar (a [0])) Aus [29]: float

Wenn Sie sicherstellen möchten, dass es keine Überraschungen für einen Benutzer gibt, der nicht über numpy wissen soll, müssen Sie zumindest das Element der 0 erhalten, wenn ein Skalar eingegangen wäre. Wenn der Benutzer numpy bewusst sein sollte, ist nur die Dokumentation Wahrscheinlich so gut

Wie @wim darauf hingewiesen hat, verwandelt fsolve Ihren Skalar in ein ndarray (1,) und gibt ein Array von Form (1,) .

Wenn du wirklich einen Skalar als Ausgang bekommen möchtest, kannst du versuchen, am Ende deiner Funktion folgendes zu setzen:

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

(Die Elementmethode kopiert ein Element eines Arrays und gibt einen Standard-Python-Skalar zurück)

  • Einstellen von Abstand zwischen gruppierten Stabplots in Matplotlib
  • Schätzung eines Bereichs eines Bildes, das durch einen Satz von Punkten erzeugt wird (Alpha-Formen ??)
  • Broadcasting einer Python-Funktion auf numpy Arrays
  • Python: Memory-effiziente Matrix-Erstellung für Sätze von 1's, -1 und 0s, um von scipy kleinsten Quadraten optimiert zu werden
  • Segmentierungsfehler in Scipy _fitpack fprank_ ()
  • Installieren von SciPy mit Pip
  • Instabiles Ergebnis von scipy.cluster.kmeans
  • Scipy.optimize.fmin_bfgs optimierung gibt aus einfachem Funktionsaufruf unterschiedliche Ergebnisse
  • Effizient subtrahieren Vektor von Matrix (Scipy)
  • Verstehen von Datenformat in scikit-learn
  • Anpassung einer Weibull-Verteilung mit Scipy
  • Python ist die beste Programmiersprache der Welt.