Una cosa su cui non potrei mai pensare è come funziona Flatten
quando fornito con una matrice come secondo argomento, e laiuto di Mathematica non è particolarmente valido su questo argomento.
Tratto da Flatten
Mathematica documentazione:
Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}]
Appiattisce
list
combinando tutti i livelli $ s_ {ij} $ per rendere ogni livello $ i $ nel risultato.
Qualcuno potrebbe spiegare cosa significa / fa effettivamente?
Risposta
Uno un modo conveniente per pensare a Flatten
con il secondo argomento è che esegue qualcosa come Transpose
per elenchi irregolari (irregolari). Ecco un semplice esempio:
In[63]:= Flatten[{{1,2,3},{4,5},{6,7},{8,9,10}},{{2},{1}}] Out[63]= {{1,4,6,8},{2,5,7,9},{3,10}}
Ciò che accade sono gli elementi che costituiscono Il livello 1
nellelenco originale sono ora componenti al livello 2
nel risultato e viceversa. Questo è esattamente ciò che fa Transpose
, ma fatto per elenchi irregolari. Tieni presente, tuttavia, che alcune informazioni sulle posizioni vengono perse qui, quindi non possiamo invertire direttamente loperazione:
In[65]:= Flatten[{{1,4,6,8},{2,5,7,9},{3,10}},{{2},{1}}] Out[65]= {{1,2,3},{4,5,10},{6,7},{8,9}}
Per invertirla correttamente, avremmo “dovuto per fare qualcosa del genere:
In[67]:= Flatten/@Flatten[{{1,4,6,8},{2,5,7,9},{3,{},{},10}},{{2},{1}}] Out[67]= {{1,2,3},{4,5},{6,7},{8,9,10}}
Un esempio più interessante è quando abbiamo una nidificazione più profonda:
In[68]:= Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{2},{1},{3}}] Out[68]= {{{1,2,3},{6,7}},{{4,5},{8,9,10}}}
Anche qui, possiamo vedere che Flatten
ha funzionato efficacemente come (generalizzato) Transpose
, scambiando pezzi ai primi 2 livelli Sarà più difficile capire quanto segue:
In[69]:= Flatten[{{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9, 10}}}, {{3}, {1}, {2}}] Out[69]= {{{1, 4}, {6, 8}}, {{2, 5}, {7, 9}}, {{3}, {10}}}
Limmagine seguente illustra questa trasposizione generalizzata:
Possiamo farlo in due fasi consecutive:
In[72]:= step1 = Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{1},{3},{2}}] Out[72]= {{{1,4},{2,5},{3}},{{6,8},{7,9},{10}}} In[73]:= step2 = Flatten[step1,{{2},{1},{3}}] Out[73]= {{{1,4},{6,8}},{{2,5},{7,9}},{{3},{10}}}
Poiché la permutazione {3,1,2}
può essere ottenuto come {1,3,2}
seguito da {2,1,3}
. Un altro modo per vedere come funziona è usa i numeri wh ich indicare la posizione nella struttura della lista:
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *)
Da qui si può vedere che nella lista più esterna (primo livello), il terzo indice (corrispondente al terzo livello della lista originale) cresce, in ogni lista membri (secondo livello) il primo elemento cresce per elemento (corrispondente al primo livello della lista originale), e infine nelle liste più interne (terzo livello) cresce il secondo indice , corrispondente al secondo livello nellelenco originale. In genere, se lelemento k-esimo della lista passato come secondo elemento è {n}
, aumentare lindice k-esimo nella struttura dellelenco risultante corrisponde ad aumentare lindice n-esimo nella struttura originale.
Infine, è possibile combinare diversi livelli per appiattire efficacemente i sottolivelli, in questo modo:
In[74]:= Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{2},{1,3}}] Out[74]= {{1,2,3,6,7},{4,5,8,9,10}}
Commenti
Risposta
Un secondo argomento dellelenco a Flatten
serve due scopi. Innanzitutto, specifica lordine in cui gli indici verranno iterati durante la raccolta degli elementi. In secondo luogo, descrive lappiattimento dellelenco nel risultato finale. Esaminiamo ciascuna di queste funzionalità a turno.
Ordine di iterazione
Considera la seguente matrice:
$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm
Possiamo usare unespressione Table
per creare una copia della matrice ripetendo tutti i suoi elementi:
$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *)
Questa identità loperazione non è interessante, ma possiamo trasformare larray scambiando lordine delle variabili di iterazione. Ad esempio, possiamo scambiare i
e j
iteratori. Ciò equivale a scambiare gli indici di livello 1 e 2 e i loro elementi corrispondenti:
$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm
Se guardiamo attentamente, possiamo vedere che ogni elemento originale $m[[i, j, k]]
corrisponderà allelemento risultante $r[[j, i, k]]
– i primi due indici sono ape n “swapped”.
Flatten
ci consente di esprimere unoperazione equivalente a questa Table
espressione in modo più succinto:
$r === Flatten[$m, {{2}, {1}, {3}}] (* True *)
Il secondo argomento dellespressione Flatten
specifica esplicitamente lordine degli indici desiderato: gli indici 1, 2, 3 sono modificato per diventare indici 2, 1, 3. Nota come non abbiamo bisogno di specificare un intervallo per ogni dimensione dellarray: una notevole comodità notazionale.
Il seguente Flatten
è unoperazione sullidentità poiché non specifica alcuna modifica allordine dellindice:
$m === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Mentre la seguente espressione riorganizza tutti e tre gli indici: 1, 2 , 3 -> 3, 2, 1
Flatten[$m, {{3}, {2}, {1}}] // MatrixForm
Ancora , possiamo verificare che un elemento originale trovato nellindice [[i, j, k]]
si troverà ora in [[k, j, i]]
nel risultato.
Se qualche indice viene omesso da un Flatten
, vengono trattati come se fossero stati specificati per ultimi e nel loro ordine naturale:
Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *)
Questultimo esempio può essere abbreviato ulteriormente:
Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *)
Un elenco di indice vuoto risulta nelloperazione di identità:
$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Questo si occupa dellordine di iterazione e dello scambio di indici. Ora, esaminiamo …
Appiattimento elenco
Ci si potrebbe chiedere perché negli esempi precedenti abbiamo dovuto specificare ogni indice in una sottolista. Il motivo è che ogni sottolista nella specifica dellindice specifica quali indici devono essere appiattiti insieme nel risultato. Considera ancora la seguente operazione di identità:
Flatten[$m, {{1}, {2}, {3}}] // MatrixForm
Cosa succede se uniamo i primi due indici nella stessa sottolista ?
Flatten[$m, {{1, 2}, {3}}] // MatrixForm
Possiamo vedere che il risultato originale era un Griglia di coppie 4 x 3, ma il secondo risultato è un semplice elenco di coppie. La struttura più profonda, le coppie, è rimasta intatta. I primi due livelli sono stati appiattiti in un unico livello. Le coppie nel terzo livello della sorgente matrice è rimasta non appiattita.
Potremmo combinare i secondi due indici invece:
Flatten[$m, {{1}, {2, 3}}] // MatrixForm
Questo risultato ha lo stesso numero di righe della matrice originale, il che significa che il primo livello non è stato toccato. Ma ogni riga dei risultati ha un elenco semplice di sei elementi presi dalla corrispondente riga originale di tre coppie. Pertanto, i due livelli inferiori sono stati appiattiti.
Possiamo anche combinare tutti e tre gli indici per ottenere un risultato completamente appiattito:
Flatten[$m, {{1, 2, 3}}]
Questo può essere abbreviato:
Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *)
Flatten
offre anche una notazione abbreviata quando non deve avvenire lo scambio di indice:
$n = Array[n[##]&, {2, 2, 2, 2, 2}]; Flatten[$n, {{1}, {2}, {3}, {4}, {5}}] === Flatten[$n, 0] (* True *) Flatten[$n, {{1, 2}, {3}, {4}, {5}}] === Flatten[$n, 1] (* True *) Flatten[$n, {{1, 2, 3}, {4}, {5}}] === Flatten[$n, 2] (* True *) Flatten[$n, {{1, 2, 3, 4}, {5}}] === Flatten[$n, 3] (* True *)
“Ragged” Arrays
Tutti gli esempi finora hanno utilizzato matrici di varie dimensioni. Flatten
offre una funzionalità molto potente che lo rende più di unabbreviazione per unespressione Table
. Flatten
gestirà con garbo il caso in cui le sottoliste a un dato livello abbiano lunghezze diverse. Gli elementi mancanti verranno ignorati silenziosamente. Ad esempio, un array triangolare può essere capovolto:
$t = Array[# Range[#]&, {5}]; $t // TableForm (* 1 2 4 3 6 9 4 8 12 16 5 10 15 20 25 *) Flatten[$t, {{2}, {1}}] // TableForm (* 1 2 3 4 5 4 6 8 10 9 12 15 16 20 25 *)
…o capovolto e appiattito:
Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *)
Commenti
- Questa è una spiegazione fantastica e completa!
- @ rm-rf Grazie. Immagino che se
Flatten
fosse generalizzato per accettare una funzione da applicare durante lappiattimento (contrazione) degli indici, sarebbe un ottimo inizio per ” algebra tensoriale in una lattina “. - A volte abbiamo bisogno di contrazioni interne. Ora so di poterlo fare utilizzando
Flatten[$m, {{1}, {2, 3}}]
invece di Map Flatten su un certo livello. Sarebbe bello seFlatten
accettasse argomenti negativi per farlo. Quindi questo caso potrebbe essere scritto comeFlatten[$m, -2]
. - Perché questa eccellente risposta ha ottenuto meno voti di Leonid ‘: (.
- @Tangshutao Vedi la seconda FAQ sul mio profilo .
Risposta
Ho imparato molto dalle risposte di WReach “se Leonid” e “vorrei dare un piccolo contributo:
Sembra valga la pena sottolineando che lo scopo principale del secondo argomento a valore di elenco di Flatten
è semplicemente quello di appiattire determinati livelli di elenchi (come WReach menziona nel suo List Flattening sezione). Lutilizzo di Flatten
come Transpose
irregolare sembra un lato -effetto di questo progetto primario, secondo me.
Ad esempio, ieri avevo bisogno di trasformare questo elenco
lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) };
in questo:
list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) }
Cioè, dovevo schiacciare insieme il 2 ° e il 3 ° livello di elenco.
Lho fatto con
list2 = Flatten[lists, {{1}, {2, 3}}];
Risposta
Questa è una vecchia domanda, ma spesso viene posta da un lotto di persone. Oggi, quando stavo cercando di spiegare come funziona, mi sono imbattuto in una spiegazione abbastanza chiara, quindi penso che condividerla qui sarebbe utile per un ulteriore pubblico.
Cosa significa indice?
Per prima cosa chiariamo cosa è index : In Mathematica ogni espressione è un albero, ad esempio, guardiamo in un elenco:
TreeForm@{{1,2},{3,4}}
Come navighi in un albero?
Semplice! Parti dalla radice e ad ogni incrocio scegli da che parte andare, ad esempio qui se vuoi raggiungere 2
, inizi con la scelta del il primo percorso, quindi scegli il secondo percorso. Scriviamolo come {1,2}
che è solo lindice dellelemento 2
in questa espressione.
Come capire Flatten
?
Qui prendi in considerazione una semplice domanda, se non ti fornisco unespressione completa, ma invece ti do tutti gli elementi e i loro indici, come costruisci lespressione originale? Ad esempio, qui ti do:
{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>}
e ti dico che tutte le teste sono List
, quindi cosa “s lespressione originale?
Beh, sicuramente puoi ricostruire lespressione originale come {{1,2},{3,4}}
, ma come? Probabilmente puoi elencare i seguenti passaggi:
- Prima esaminiamo il primo elemento di index, ordiniamo e raccogliamo in base a esso. Quindi sappiamo che il primo lelemento dellintera espressione deve contenere i primi due elementi nellelenco originale …
- Quindi continuiamo a guardare il secondo argomento, facciamo lo stesso …
- Infine otteniamo lelenco originale come
{{1,2},{3,4}}
.
Bene, è ragionevole! Quindi cosa succede se ti dico, no, dovresti prima ordinare e raccogliere in base al secondo elemento dellindice e poi raccogliere in base al primo elemento dellindice? Oppure dico che non li raccogliamo due volte, ordiniamo semplicemente in base a entrambi gli elementi ma diamo priorità più alta al primo argomento?
Bene, probabilmente otterresti rispettivamente i due seguenti elenchi, giusto?
-
{{1,3},{2,4}}
-
{1,2,3,4}
Bene, controlla da solo, Flatten[{{1,2},{3,4}},{{2},{1}}]
e Flatten[{{1,2},{3,4}},{{1,2}}]
fanno lo stesso!
Quindi, come intendi il secondo argomento di Flatten ?
- Ogni elemento dellelenco allinterno dellelenco principale, ad esempio
{1,2}
, significa che dovresti RACCOGLIE tutti gli elenchi in base a questi elementi nellindice, in altre parole questi livelli . - Lordine allinterno di un elemento di elenco rappresenta il modo in cui SORT gli elementi raccolti allinterno di un elenco nel passaggio precedente . ad esempio,
{2,1}
significa che la posizione al secondo livello ha una priorità maggiore rispetto alla posizione al primo livello.
Esempi
Ora facciamo un po di pratica per acquisire familiarità con le regole precedenti.
1. Transpose
Lobiettivo di Transpose
su una semplice matrice m * n serve a rendere $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Ma possiamo considerarlo in un altro modo, originariamente ordiniamo il elemento in base al loro indice i
, quindi ordinarli in base al loro indice j
, ora tutto ciò che dobbiamo fare è cambiare per ordinarli per j
index prima, poi i
successivo! Quindi il codice diventa:
Flatten[mat,{{2},{1}}]
Semplice, vero?
2. Tradizionale Flatten
Lobiettivo dellappiattimento tradizionale su una semplice matrice m * n è crea un array 1D invece di una matrice 2D, ad esempio: Flatten[{{1,2},{3,4}}]
restituisce {1,2,3,4}
. Ciò significa che questa volta non “t raccogliamo elementi, ma solo ordina , prima in base al primo indice e poi al secondo:
Flatten[mat,{{1,2}}]
3. ArrayFlatten
Parliamo di un caso molto semplice di ArrayFlatten, qui abbiamo un elenco 4D:
{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}}
quindi come possiamo fare una tale conversione per renderlo un elenco 2D?
$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ sinistra (\ begin {array} {cc} 3 & 4 \\ 7 & 8 \\ \ end {array} \ right) \\ \ left (\ begin {array} {cc} 9 & 10 \\ 13 & 14 \\ \ end {array} \ right) & \ left (\ begin {array} {cc} 11 & 12 \\ 15 & 16 \\ \ end {array} \ right) \\ \ end {array} \ right) \ rightarrow \ left (\ begin {array} {cccc} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ 13 & 14 & 15 & 16 \\ \ end {array} \ right) $
Bene, anche questo è semplice, abbiamo bisogno del gruppo con lindice originale di primo e terzo livello prima, e dovremmo dare al primo indice una priorità più alta in ordinamento. Lo stesso vale per il secondo e il quarto livello:
Flatten[mat,{{1,3},{2,4}}]
4. “Ridimensiona” unimmagine
Ora abbiamo unimmagine, ad esempio:
img=Image@RandomReal[1,{10,10}]
Ma è decisamente troppo piccola per noi visualizzazione, quindi vogliamo ingrandirlo estendendo ogni pixel a un enorme pixel di dimensioni 10 * 10.
Per prima cosa proveremo:
ConstantArray[ImageData@img,{10,10}]
Ma restituisce una matrice 4D con dimensioni {10,10,10,10}. Quindi dovremmo Flatten
. Questa volta vogliamo che il terzo argomento abbia invece priorità più alta del primo, quindi una regolazione minore potrebbe funzionare:
Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}]
Un confronto:
Spero che questo possa aiutare!
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}}
e il risultato sarebbe{{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}}
.In[63]:= Flatten[{{1,2,3},{4,5},{6,7},{8,9,10}},{{2},{1}}] Out[63]= {{1,4,6,8},{2,5,7,9},{3,10}}
, dici Quello che succede è che gli elementi che costituivano il livello 1 nellelenco originale sono ora costituenti livello 2 nel risultato. Non ‘ capisco bene, input e output hanno la stessa struttura di livello, gli elementi sono ancora allo stesso livello. Puoi spiegarlo in generale?