Recentemente ho iniziato a studiare Julia codificando una semplice implementazione di Self Organizing Maps. Voglio che le dimensioni e le dimensioni della mappa siano specificate dall'utente, il che significa che non posso davvero usare i loop per lavorare sugli array di mappe perché non so in anticipo quanti strati di loop avrò bisogno. Quindi ho assolutamente bisogno di funzioni di broadcasting e slicing che funzionano su array di dimensioni arbitrarie.Slicing e broadcasting di array multidimensionali in Julia: esempio meshgrid
Al momento, ho bisogno di costruire una serie di indici della mappa. La mia mappa è definita da una serie di dimensioni mapsize = (5, 10, 15)
, ho bisogno di costruire un array indices
della dimensione (3, 5, 10, 15)
dove indices[:, a, b, c]
deve restituire [a, b, c]
.
io vengo da un background Python/NumPy, in cui la soluzione è già data da una "funzione" specifica, MGrid:
indices = numpy.mgrid[:5, :10, :15]
print indices.shape # gives (3, 5, 10, 15)
print indices[:, 1, 2, 3] gives [1, 2, 3]
non mi aspettavo Julia di avere una tale funzione sul get -solo, così ho iniziato a trasmettere. In NumPy, la trasmissione è basata su un insieme di regole che trovo abbastanza chiare e logiche. È possibile utilizzare array di dimensioni diverse nella stessa espressione fino a quando le dimensioni in ogni partita di quota o una parte di esso è 1:
(5, 10, 15) broadcasts to (5, 10, 15)
(10, 1)
(5, 1, 15) also broadcasts to (5, 10, 15)
(1, 10, 1)
per aiutare con questo, è anche possibile utilizzare numpy.newaxis o None per facilmente aggiungere nuove dimensioni per l'array:
array = numpy.zeros((5, 15))
array[:,None,:] has shape (5, 1, 15)
questo aiuta le matrici di trasmissione facilmente:
A = numpy.arange(5)
B = numpy.arange(10)
C = numpy.arange(15)
bA, bB, bC = numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:])
bA.shape == bB.shape == bC.shape = (5, 10, 15)
Usando questo, creando la matrice indices
è piuttosto straightfo rward:
indices = numpy.array(numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:]))
(indices == numpy.mgrid[:5,:10,:15]).all() returns True
Il caso generale è, naturalmente, un po 'più complicato, ma può essere lavorato in giro con la lista di comprensione e fette:
arrays = [ numpy.arange(i)[tuple([None if m!=n else slice(None) for m in range(len(mapsize))])] for n, i in enumerate(mapsize) ]
indices = numpy.array(numpy.broadcast_arrays(*arrays))
Ma torniamo a Julia. Ho provato ad applicare lo stesso tipo di motivazione e ho finito per ottenere l'equivalente della lista arrays
del codice sopra. Questo ha finito per essere piuttosto semplice rispetto alle NumPy controparte grazie alla sintassi delle espressioni composto:
arrays = [ (idx = ones(Int, length(mapsize)); idx[n] = i;reshape([1:i], tuple(idx...))) for (n,i)=enumerate(mapsize) ]
Ora mi sono bloccato qui, come io non so davvero come applicare la trasmissione alla mia lista di generare matrici qui ... Le funzioni broadcast[!]
richiedono una funzione f da applicare e io non ne ho. Ho provato ad utilizzare un ciclo for per provare a forzare il broadcasting:
indices = Array(Int, tuple(unshift!([i for i=mapsize], length(mapsize))...))
for i=1:length(mapsize)
A[i] = arrays[i]
end
Ma questo mi dà un errore: ERROR: convert has no method matching convert(::Type{Int64}, ::Array{Int64,3})
sto facendo questo il modo giusto? Ho trascurato qualcosa di importante? Qualsiasi aiuto è apprezzato.
Fantastico! Ho modificato il codice un po 'per ottenere il risultato a un tensore: 2a riga: 'X = Matrice (Int, tupla (unshift! ([I per i = dims], length (dims)) ...))'; 8a riga: 'X [d, cur_idx ...] = i' – Nathan