Un lucru pe care nu l-aș putea înfășura niciodată este modul în care funcționează Flatten
când furnizat cu o matrice ca al doilea argument, iar ajutorul Mathematica nu este deosebit de bun în acest sens.
Luat din Flatten
Documentare Mathematica :
Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}]
Aplatizează
list
combinând toate nivelurile $ s_ {ij} $ pentru a face ca fiecare nivel să fie $ i $ în rezultat.
Ar putea cineva să ofere detalii despre ceea ce înseamnă / face de fapt acest lucru?
Răspunde
One un mod convenabil de a vă gândi la Flatten
cu al doilea argument este că efectuează ceva de genul Transpose
pentru listele zdrențuite (neregulate). Iată un simplu exemplu:
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}}
Ce se întâmplă sunt acele elemente care constituie nivelul divizat 1
din lista originală sunt acum elemente constitutive la nivelul 2
în rezultat și invers. Este exact ceea ce face Transpose
, dar este făcut pentru liste neregulate. Rețineți totuși că unele informații despre poziții sunt pierdute aici, deci nu putem inversa direct operația:
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}}
Pentru a fi inversate corect, ar fi să facem așa ceva:
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 exemplu mai interesant este atunci când avem cuiburi mai profunde:
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}}}
Aici din nou, putem vedea că Flatten
a funcționat efectiv ca (generalizat) Transpose
, schimbând piese la primele 2 niveluri . Următoarele vor fi mai greu de înțeles:
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}}}
Următoarea imagine ilustrează această transpunere generalizată:
O putem face în doi pași consecutivi:
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}}}
De la permutarea {3,1,2}
poate fi obținut ca {1,3,2}
urmat de {2,1,3}
. Un alt mod de a vedea cum funcționează este să folosiți numere wh ich indică poziția în structura listei:
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *)
Din aceasta, se poate vedea că în lista cea mai exterioară (primul nivel), al treilea index (corespunzător al treilea nivel al listei originale) crește, în fiecare listă de membri (al doilea nivel) crește primul element pe element (corespunzător primului nivel al listei originale) și, în cele din urmă, în listele cele mai interioare (al treilea nivel), al doilea index crește , corespunzător celui de-al doilea nivel din lista originală. În general, dacă al k-lea element al listei trecut ca al doilea element este {n}
, creșterea indicelui k-lea în structura listei rezultate corespunde creșterii indexului n structură originală.
În cele din urmă, se pot combina mai multe niveluri pentru a aplatiza în mod eficient sub-nivelurile, astfel:
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}}
Comentarii
Răspuns
Un al doilea argument list pentru Flatten
servește două scopuri. În primul rând, specifică ordinea în care indicii vor fi iterați atunci când se adună elemente. În al doilea rând, descrie aplatizarea listei în rezultatul final. Să vedem la rândul lor fiecare dintre aceste funcții.
Ordinea de iterație
Luați în considerare următoarea matrice:
$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm
Putem folosi o expresie Table
pentru a crea o copie a matricei prin iterarea tuturor elementelor sale:
$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *)
Această identitate operația este neinteresantă, dar putem transforma tabloul schimbând ordinea variabilelor de iterație. De exemplu, putem schimba i
și j
iteratori. Aceasta înseamnă schimbarea indicilor de nivel 1 și de nivel 2 și a elementelor corespunzătoare ale acestora:
$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm
Dacă ne uităm cu atenție, putem vedea că fiecare element original $m[[i, j, k]]
va fi găsit pentru a corespunde elementului rezultat $r[[j, i, k]]
– primii doi indici au albine n „swapped”.
Flatten
ne permite să exprimăm o operație echivalentă cu această expresie Table
mai succint:
$r === Flatten[$m, {{2}, {1}, {3}}] (* True *)
Al doilea argument al expresiei Flatten
specifică în mod explicit ordinea indexului dorită: indicii 1, 2, 3 sunt modificat pentru a deveni indici 2, 1, 3. Rețineți că nu a fost nevoie să specificăm un interval pentru fiecare dimensiune a matricei – o comoditate notatională semnificativă.
Următorul Flatten
este o operațiune de identitate, deoarece nu specifică nicio modificare a ordinii indexului:
$m === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Întrucât următoarea expresie reorganizează toți cei trei indici: 1, 2 , 3 -> 3, 2, 1
Flatten[$m, {{3}, {2}, {1}}] // MatrixForm
Din nou , putem verifica dacă un element original găsit la index [[i, j, k]]
va fi acum găsit la [[k, j, i]]
în rezultat.
Dacă indicii sunt omiși dintr-un Flatten
expresie, acestea sunt tratate ca și când ar fi fost specificate ultima și în ordinea lor naturală:
Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *)
Acest ultim exemplu poate să fie abreviat și mai departe:
Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *)
O listă de indici goale are ca rezultat operațiunea de identitate:
$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Aceasta se ocupă de ordinea de iterație și de schimbarea indexului. Acum, să vedem …
List aplatizare
Ne-am putea întreba de ce a trebuit să specificăm fiecare index dintr-o sublistă în exemplele anterioare. Motivul este că fiecare sublistă din specificația indexului specifică ce indici trebuie aplatizați împreună în rezultat. Luați în considerare din nou următoarea operație de identitate:
Flatten[$m, {{1}, {2}, {3}}] // MatrixForm
Ce se întâmplă dacă combinăm primii doi indici în aceeași sublistă ?
Flatten[$m, {{1, 2}, {3}}] // MatrixForm
Putem vedea că rezultatul inițial a fost un Grila de perechi de 4 x 3, dar al doilea rezultat este o listă simplă de perechi. Cea mai profundă structură, perechile, au fost lăsate neatinse. Primele două niveluri au fost aplatizate într-un singur nivel. Perechile din al treilea nivel al sursei matricea a rămas neatinsă.
În schimb, am putea combina al doilea doi indici:
Flatten[$m, {{1}, {2, 3}}] // MatrixForm
Acest rezultat are același număr de rânduri ca matricea originală, ceea ce înseamnă că primul nivel a fost lăsat neatins. Dar fiecare rând de rezultate are o listă plană de șase elemente preluate din rândul original corespunzător de trei perechi. Astfel, cele două niveluri inferioare au fost aplatizate.
De asemenea, putem combina toți cei trei indici pentru a obține un rezultat complet aplatizat:
Flatten[$m, {{1, 2, 3}}]
Aceasta poate fi abreviată:
Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *)
Flatten
oferă, de asemenea, o notație de tip stenogramă atunci când nu va avea loc schimbarea indexului:
$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 *)
Matrice „Ragged”
Toate exemplele de până acum au folosit matrici de diferite dimensiuni. Flatten
oferă o caracteristică foarte puternică, care o face mai mult decât o abreviere pentru o expresie Table
. Flatten
va gestiona cu grație cazul în care sublistele de la un nivel dat au lungimi diferite. Elementele lipsă vor fi ignorate în liniște. De exemplu, un tablou triunghiular poate fi răsturnat:
$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 *)
…sau răsturnat și aplatizat:
Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *)
Comentarii
- Aceasta este o explicație fantastică și amănunțită!
- @ rm-rf Mulțumesc. Cred că dacă
Flatten
ar fi generalizat pentru a accepta o funcție de aplicat la aplatizarea (contractarea) indicilor, ar fi un început excelent pentru ” algebra tensorială într-o cutie „. - Uneori trebuie să facem contracții interne. Acum știu că o pot face folosind
Flatten[$m, {{1}, {2, 3}}]
în loc de Map Flatten pe un anumit nivel. Ar fi frumos dacăFlatten
ar accepta argumente negative pentru a face acest lucru. Deci, acest caz ar putea fi scris caFlatten[$m, -2]
. - De ce acest răspuns excelent a obținut mai puține voturi decât Leonid ‘ s: (.
- @Tangshutao Consultați a doua întrebare frecventă pe profilul meu .
Răspuns
Am învățat multe din răspunsurile WReach și Leonid și aș vrea să aduc o mică contribuție:
Se pare că merită subliniind că intenția principală a celui de-al doilea argument al listei Flatten
este doar de a aplatiza anumite niveluri de liste (așa cum menționează WReach în Listă aplatizarea secțiune). Utilizarea Flatten
ca Transpose
zdrențuită pare o parte -efectul acestui design primar, după părerea mea.
De exemplu, ieri trebuia să transform această listă
lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) };
în acesta:
list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) }
Adică, trebuia să zdrobesc al doilea și al treilea nivel de listă împreună.
Am făcut-o cu
list2 = Flatten[lists, {{1}, {2, 3}}];
Răspuns
Aceasta este o întrebare veche, dar frecvent adresată de un lot de oameni. Astăzi, când încercam să explic cum funcționează acest lucru, am dat peste o explicație destul de clară, așa că cred că împărtășirea acesteia ar fi utilă pentru un public suplimentar.
Ce înseamnă indexul?
Mai întâi, să „clarificăm ce este index : în Mathematica fiecare expresie este un copac, de exemplu, să arătăm la o listă:
TreeForm@{{1,2},{3,4}}
Cum navigați într-un copac?
Simplu! Începeți de la rădăcină și la fiecare traversare alegeți ce cale să mergeți, de exemplu, aici, dacă doriți să ajungeți la 2
, începeți cu alegerea mai întâi calea , apoi alegeți calea a doua . Să-l scriem ca {1,2}
care este doar indexul elementului 2
din această expresie.
Cum să înțelegeți Flatten
?
Aici luați în considerare o întrebare simplă, dacă nu vă ofer o expresie completă, dar în schimb vă dau toate elementele și indicii lor, cum construiți expresia originală? De exemplu, aici vă dau:
{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>}
și vă spun că toate capetele sunt List
, deci ce s expresia originală?
Ei bine, cu siguranță puteți reconstrui expresia originală ca {{1,2},{3,4}}
, dar cum? Probabil puteți enumera următorii pași:
- Mai întâi ne uităm la primul element de index și sortăm și adunăm după el. Apoi știm că primul elementul întregii expresii trebuie să conțină primele două elemente din lista originală …
- Apoi continuăm să ne uităm la al doilea argument, să facem același lucru …
- În cele din urmă obținem lista originală ca
{{1,2},{3,4}}
.
Ei bine, este rezonabil! Deci, dacă vă spun, nu, ar trebui mai întâi să sortați și să strângeți după al doilea element al indexului și apoi să strângeți după primul element al indexului? Sau spun că nu le adunăm de două ori, doar sortăm după ambele elemente, dar acordăm priorității mai mari primului argument?
Ei bine, probabil că veți obține respectivele două liste, nu?
-
{{1,3},{2,4}}
-
{1,2,3,4}
Ei bine, verificați singur, Flatten[{{1,2},{3,4}},{{2},{1}}]
și Flatten[{{1,2},{3,4}},{{1,2}}]
faceți la fel!
Deci, cum înțelegeți al doilea argument al lui Flatten ?
- Fiecare element de listă din lista principală, de exemplu,
{1,2}
, înseamnă că ar trebui să ADUNĂ toate listele conform acestor elemente din index, cu alte cuvinte aceste niveluri . - Ordinea din interiorul unui element de listă reprezintă modul în care SORT elementele adunate într-o listă în pasul anterior . de exemplu,
{2,1}
înseamnă că poziția de la al doilea nivel are prioritate mai mare decât poziția de la primul nivel.
Exemple
Acum, să avem o anumită practică pentru a ne familiariza cu regulile anterioare.
1. Transpose
Scopul Transpose
pe o matrice simplă m * n este de a face $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Dar o putem considera într-un alt mod, inițial sortăm element după indexul i
mai întâi, apoi sortează-le după indexul j
, acum tot ce trebuie să facem este să ne schimbăm pentru a le sorta după j
index mai întâi apoi de i
apoi! Deci codul devine:
Flatten[mat,{{2},{1}}]
Simplu, nu?
2. Tradițional Flatten
Scopul aplatizării tradiționale pe o matrice simplă m * n este să creați o matrice 1D în loc de o matrice 2D, de exemplu: Flatten[{{1,2},{3,4}}]
returnează {1,2,3,4}
. Aceasta înseamnă că de data aceasta nu „adunăm” elemente adunăm , doar sortați-le , mai întâi după primul lor index, apoi cu al doilea:
Flatten[mat,{{1,2}}]
3. ArrayFlatten
Să discutăm despre un caz simplu al ArrayFlatten, aici avem o listă 4D:
{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}}
deci cum putem face o astfel de conversie pentru a face din aceasta o listă 2D?
$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ left (\ 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) $
Ei bine, și acest lucru este simplu, avem nevoie mai întâi de grupul după primul index original și cel de al treilea nivel și ar trebui să acordăm primului index o prioritate mai mare în triere. Același lucru este valabil și pentru al doilea și al patrulea nivel:
Flatten[mat,{{1,3},{2,4}}]
4. „Redimensionați” o imagine
Acum avem o imagine, de exemplu:
img=Image@RandomReal[1,{10,10}]
Dar este cu siguranță prea mic pentru noi vizualizare, așa că dorim să-l mărim extinzând fiecare pixel la un pixel imens de 10 * 10.
Mai întâi vom încerca:
ConstantArray[ImageData@img,{10,10}]
Dar returnează o matrice 4D cu dimensiunile {10,10,10,10}. Deci ar trebui să Flatten
. De data aceasta dorim ca al treilea argument să aibă prioritate mai mare din prima, deci o reglare minoră ar funcționa:
Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}]
O comparație:
Sper că acest lucru vă poate ajuta!
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}}
, iar rezultatul ar citi{{{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}}
, spuneți că ceea ce se întâmplă este că elementele care au constituit nivelul 1 în lista originală sunt acum elemente constitutive la nivelul 2 în rezultat. Nu ‘ nu înțeleg destul, intrarea și ieșirea au aceeași structură de nivel, elementele sunt încă la același nivel. Ați putea explica acest lucru în general?