Frage

Ich versuche zu laufen und lief über die Parameter Raum, der von einer 6-parameter-Funktion, um es zu studieren die numerische Verhalten, bevor Sie versuchen, etwas zu tun-Komplex, so dass ich bin auf der Suche nach einem effizienten Weg, dies zu tun.

Meine Funktion nimmt float-Werte bei einer 6-dim-numpy-array als Eingabe.Was ich versuchte zu tun, war zunächst dies:

Zuerst erstellte ich eine Funktion, die 2 arrays und erstellen Sie ein array mit allen Kombinationen von Werten aus den beiden arrays

from numpy import *
def comb(a,b):
    c = []
    for i in a:
        for j in b:
            c.append(r_[i,j])
    return c

Dann habe ich verwendet reduce() zu gelten, dass m Kopien des gleichen array:

def combs(a,m):
    return reduce(comb,[a]*m)

Und dann bewerte ich meine Funktion wie folgt:

values = combs(np.arange(0,1,0.1),6)
for val in values:
    print F(val)

Dies funktioniert, aber es ist viiiiel zu langsam.Ich weiß, der Raum der Parameter ist riesig, aber dies sollte nicht so langsam.Ich habe Sie nur abgetastet 106 (eine Millionen) Punkte in diesem Beispiel, und es dauerte mehr als 15 Sekunden lang, um das array erstellen values.

Kennen Sie eine effizientere Möglichkeit, dies zu tun mit numpy?

Kann ich ändern die Art und Weise der Funktion F braucht es Argumente, wenn es notwendig ist.

War es hilfreich?

Lösung

In neuerer Version von numpy (> 1.8.x), numpy.meshgrid() bietet eine viel schnellere Implementierung:

@ pv-Lösung

In [113]:

%timeit cartesian(([1, 2, 3], [4, 5], [6, 7]))
10000 loops, best of 3: 135 µs per loop
In [114]:

cartesian(([1, 2, 3], [4, 5], [6, 7]))

Out[114]:
array([[1, 4, 6],
       [1, 4, 7],
       [1, 5, 6],
       [1, 5, 7],
       [2, 4, 6],
       [2, 4, 7],
       [2, 5, 6],
       [2, 5, 7],
       [3, 4, 6],
       [3, 4, 7],
       [3, 5, 6],
       [3, 5, 7]])

numpy.meshgrid() 2D verwenden nur zu sein, jetzt es ist in der Lage ND. In diesem Fall 3D:

In [115]:

%timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)
10000 loops, best of 3: 74.1 µs per loop
In [116]:

np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)

Out[116]:
array([[1, 4, 6],
       [1, 5, 6],
       [2, 4, 6],
       [2, 5, 6],
       [3, 4, 6],
       [3, 5, 6],
       [1, 4, 7],
       [1, 5, 7],
       [2, 4, 7],
       [2, 5, 7],
       [3, 4, 7],
       [3, 5, 7]])

Beachten Sie, dass die Reihenfolge der endgültigen resultierend etwas anders.

Andere Tipps

Hier ist eine rein numpy Umsetzung. Es ist ca. 5 x schneller als itertools verwendet wird.


import numpy as np

def cartesian(arrays, out=None):
    """
    Generate a cartesian product of input arrays.

    Parameters
    ----------
    arrays : list of array-like
        1-D arrays to form the cartesian product of.
    out : ndarray
        Array to place the cartesian product in.

    Returns
    -------
    out : ndarray
        2-D array of shape (M, len(arrays)) containing cartesian products
        formed of input arrays.

    Examples
    --------
    >>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
    array([[1, 4, 6],
           [1, 4, 7],
           [1, 5, 6],
           [1, 5, 7],
           [2, 4, 6],
           [2, 4, 7],
           [2, 5, 6],
           [2, 5, 7],
           [3, 4, 6],
           [3, 4, 7],
           [3, 5, 6],
           [3, 5, 7]])

    """

    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    m = n / arrays[0].size
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m,1:])
        for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m,1:] = out[0:m,1:]
    return out

itertools.combinations ist in der Regel der schnellste Weg, Kombinationen zu erhalten aus einem Python-Containern (wenn Sie tatsächlich tun wollen Kombinationen, dh Vereinbarungen ohne Wiederholungen und unabhängig von Ordnung, das ist nicht das, was Ihr Code zu tun scheint, aber ich kann nicht sagen, ob das ist, weil Ihr Code Buggy oder weil Sie ist‘ re die falsche Terminologie).

Wenn Sie etwas wollen, anders als Kombinationen vielleicht andere Iteratoren in itertools, product oder permutations, könnten Sie besser dienen. Zum Beispiel, es sieht aus wie der Code in etwa die gleiche wie:

for val in itertools.product(np.arange(0, 1, 0.1), repeat=6):
    print F(val)

Alle diese Iteratoren Tupeln ergeben, keine Listen oder numpy Arrays, also, wenn Ihr F pingelig ist über speziell ein numpy Array erhalten werden Sie den zusätzlichen Aufwand für den Bau oder das Clearing und die Wieder Füllen eines an jedem Schritt in Kauf nehmen.

Die folgende numpy Implementierung sollte ca. 2x die Geschwindigkeit der gegebenen Antwort:

def cartesian2(arrays):
    arrays = [np.asarray(a) for a in arrays]
    shape = (len(x) for x in arrays)

    ix = np.indices(shape, dtype=int)
    ix = ix.reshape(len(arrays), -1).T

    for n, arr in enumerate(arrays):
        ix[:, n] = arrays[n][ix[:, n]]

    return ix

Es sieht aus wie Sie möchten, ein raster für die Bewertung Ihrer Funktion, in diesem Fall können Sie Sie nutzen numpy.ogrid (open) oder numpy.mgrid (ausgearbeitet):

import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]

Sie können etwas tun

import numpy as np

def cartesian_coord(*arrays):
    grid = np.meshgrid(*arrays)        
    coord_list = [entry.ravel() for entry in grid]
    points = np.vstack(coord_list).T
    return points

a = np.arange(4)  # fake data
print(cartesian_coord(*6*[a])

das gibt

array([[0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 2],
   ..., 
   [3, 3, 3, 3, 3, 1],
   [3, 3, 3, 3, 3, 2],
   [3, 3, 3, 3, 3, 3]])

Sie verwenden können np.array(itertools.product(a, b))

Hier ist noch eine weitere Möglichkeit, mit reinem NumPy, keine Rekursion, keine Liste Verständnis und keine explizite für Schleifen. Es ist etwa 20% langsamer als die ursprüngliche Antwort, und es basiert auf np.meshgrid.

def cartesian(*arrays):
    mesh = np.meshgrid(*arrays)  # standard numpy meshgrid
    dim = len(mesh)  # number of dimensions
    elements = mesh[0].size  # number of elements, any index will do
    flat = np.concatenate(mesh).ravel()  # flatten the whole meshgrid
    reshape = np.reshape(flat, (dim, elements)).T  # reshape and transpose
    return reshape

Beispiel:

x = np.arange(3)
a = cartesian(x, x, x, x, x)
print(a)

gibt

[[0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 2]
 ..., 
 [2 2 2 2 0]
 [2 2 2 2 1]
 [2 2 2 2 2]]

Für eine reine numpy Umsetzung kartesischen Produkts von 1D-Arrays (oder flacher Python-Listen), nur meshgrid() verwenden rollt die Achsen mit transpose() und Umformen auf die gewünschte ouput:

 def cartprod(*arrays):
     N = len(arrays)
     return transpose(meshgrid(*arrays, indexing='ij'), 
                      roll(arange(N + 1), -1)).reshape(-1, N)

Hinweis: Dies ist die Konvention der letzten Achse schnellsten ( "C-Stil" oder "row-major") zu ändern.

In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4])
Out[88]: 
array([[  1,   4, 100,  -5],
       [  1,   4, 100,  -4],
       [  1,   4, 200,  -5],
       [  1,   4, 200,  -4],
       [  1,   4, 300,  -5],
       [  1,   4, 300,  -4],
       [  1,   4, 400,  -5],
       [  1,   4, 400,  -4],
       [  1,   8, 100,  -5],
       [  1,   8, 100,  -4],
       [  1,   8, 200,  -5],
       [  1,   8, 200,  -4],
       [  1,   8, 300,  -5],
       [  1,   8, 300,  -4],
       [  1,   8, 400,  -5],
       [  1,   8, 400,  -4],
       [  2,   4, 100,  -5],
       [  2,   4, 100,  -4],
       [  2,   4, 200,  -5],
       [  2,   4, 200,  -4],
       [  2,   4, 300,  -5],
       [  2,   4, 300,  -4],
       [  2,   4, 400,  -5],
       [  2,   4, 400,  -4],
       [  2,   8, 100,  -5],
       [  2,   8, 100,  -4],
       [  2,   8, 200,  -5],
       [  2,   8, 200,  -4],
       [  2,   8, 300,  -5],
       [  2,   8, 300,  -4],
       [  2,   8, 400,  -5],
       [  2,   8, 400,  -4],
       [  3,   4, 100,  -5],
       [  3,   4, 100,  -4],
       [  3,   4, 200,  -5],
       [  3,   4, 200,  -4],
       [  3,   4, 300,  -5],
       [  3,   4, 300,  -4],
       [  3,   4, 400,  -5],
       [  3,   4, 400,  -4],
       [  3,   8, 100,  -5],
       [  3,   8, 100,  -4],
       [  3,   8, 200,  -5],
       [  3,   8, 200,  -4],
       [  3,   8, 300,  -5],
       [  3,   8, 300,  -4],
       [  3,   8, 400,  -5],
       [  3,   8, 400,  -4]])

Wenn Sie ändern möchten die erste Achse am schnellsten ( "Fortran-Stil" oder "column-major"), sondern nur die order Parameter reshape() ändern wie folgt aus: reshape((-1, N), order='F')

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top