En ting, jeg aldrig kunne pakke mit hoved rundt, er, hvordan Flatten
fungerer, når forsynet med en matrix som det andet argument, og Mathematica hjælp er ikke særlig god på denne.
Hentet fra Flatten
Mathematica dokumentation:
Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}]
Flader
list
ved at kombinere alle niveauer $ s_ {ij} $ for at gøre hvert niveau $ i $ i resultatet.
Kunne nogen uddybe, hvad dette egentlig betyder / gør?
Svar
En praktisk måde at tænke på Flatten
med det andet argument er, at det udfører noget i retning af Transpose
for skrøbelige (uregelmæssige) lister. Her er en enkel eksempel:
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}}
Hvad der sker er de elementer, der udgør uded niveau 1
i den oprindelige liste er nu bestanddele på niveau 2
i resultatet og omvendt. Dette er præcis, hvad Transpose
gør, men gøres for uregelmæssige lister. Bemærk dog, at nogle oplysninger om positioner går tabt her, så vi kan ikke direkte vende operationen:
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}}
For at få det vendt korrekt, ville vi have at gøre noget som dette:
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}}
Et mere interessant eksempel er når vi har dybere indlejring:
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}}}
Også her kan vi se, at Flatten
effektivt fungerede som (generaliseret) Transpose
og udvekslede stykker på de første 2 niveauer Følgende vil være sværere at forstå:
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}}}
Følgende billede illustrerer denne generaliserede transponering:
Vi kan gøre det i to på hinanden følgende trin:
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}}}
Siden permutationen {3,1,2}
kan fås som {1,3,2}
efterfulgt af {2,1,3}
. En anden måde at se, hvordan det fungerer, er at brug tal wh der angiver placeringen i listestrukturen:
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *)
Herfra kan man se, at i den yderste liste (første niveau) er det tredje indeks (svarende til tredje niveau af den oprindelige liste) vokser, i hver medlemsliste (andet niveau) vokser det første element pr. element (svarende til det første niveau på den oprindelige liste), og til sidst i det inderste (tredje niveau) lister vokser det andet indeks svarende til det andet niveau i den oprindelige liste. Generelt, hvis det k-th element af listen, der er sendt som andet element, er {n}
, svarer vækst af k-th indekset i den resulterende listestruktur til at øge det n-indeks i oprindelig struktur.
Endelig kan man kombinere flere niveauer for effektivt at flade underniveauerne ud, som sådan:
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}}
Kommentarer
Svar
Et andet listeargument til Flatten
tjener to formål. For det første specificerer den rækkefølgen, i hvilken indekser skal gentages, når elementer samles. For det andet beskriver det listeudfladning i det endelige resultat. Lad os se på hver af disse muligheder efter tur.
Iterationsrækkefølge
Overvej følgende matrix:
$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm
Vi kan bruge et Table
udtryk for at oprette en kopi af matricen ved at gentage det over alle dets elementer:
$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *)
Denne identitet operation er uinteressant, men vi kan transformere arrayet ved at bytte rækkefølgen på iterationsvariablerne. For eksempel kan vi bytte i
og j
iteratorer. Dette svarer til at bytte indekserne niveau 1 og niveau 2 og deres tilsvarende elementer:
$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm
Hvis vi kigger nøje, kan vi se, at hvert originale element $m[[i, j, k]]
viser sig at svare til det resulterende element $r[[j, i, k]]
– de to første indekser har bi n “swapped”.
Flatten
giver os mulighed for mere eksplicit at udtrykke en ækvivalent operation til dette Table
-udtryk:
$r === Flatten[$m, {{2}, {1}, {3}}] (* True *)
Det andet argument i Flatten
udtrykket angiver eksplicit den ønskede indeksrækkefølge: indeks 1, 2, 3 er ændret til at blive indeks 2, 1, 3. Bemærk, hvordan vi ikke behøvede at specificere et område for hver dimension af arrayet – en betydelig notational bekvemmelighed.
Følgende Flatten
er en identitetshandling, da den ikke angiver nogen ændring i indeksrækkefølgen:
$m === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Mens følgende udtryk omarrangerer alle tre indekser: 1, 2 , 3 -> 3, 2, 1
Flatten[$m, {{3}, {2}, {1}}] // MatrixForm
Igen , kan vi kontrollere, at et originalt element, der findes i indekset [[i, j, k]]
, nu findes på [[k, j, i]]
i resultatet.
Hvis nogen indekser er udeladt fra et Flatten
udtryk, de behandles som om de var angivet sidst og i deres naturlige rækkefølge:
Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *)
Dette sidste eksempel kan forkortes yderligere:
Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *)
En tom indeksliste resulterer i identitetshandling:
$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Det tager sig af iterationsrækkefølge og indeksbytte. Lad os nu se på …
Listeudfladning
Man kan undre sig over, hvorfor vi skulle specificere hvert indeks i en underliste i de foregående eksempler. Årsagen er, at hver underliste i indeksspecifikationen specificerer, hvilke indekser der skal flades sammen i resultatet. Overvej igen følgende identitetshandling:
Flatten[$m, {{1}, {2}, {3}}] // MatrixForm
Hvad sker der, hvis vi kombinerer de to første indeks i den samme underliste ?
Flatten[$m, {{1, 2}, {3}}] // MatrixForm
Vi kan se, at det oprindelige resultat var et 4 x 3 gitter med par, men det andet resultat er en simpel liste over par. Den dybeste struktur, parene, blev efterladt uberørt. De to første niveauer er blevet fladt ud til et enkelt niveau. Parene i det tredje niveau af kilden matrix forblev ikke flad.
Vi kunne kombinere de to anden indeks i stedet:
Flatten[$m, {{1}, {2, 3}}] // MatrixForm
Dette resultat har samme antal rækker som den oprindelige matrix, hvilket betyder at det første niveau blev efterladt uberørt. Men hver resultatrække har en flad liste med seks elementer taget fra den tilsvarende originale række med tre par. Således er de to nederste niveauer blevet fladt.
Vi kan også kombinere alle tre indekser for at få et fuldstændigt fladt resultat:
Flatten[$m, {{1, 2, 3}}]
Dette kan forkortes:
Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *)
Flatten
tilbyder også en stenografisk notation, når ingen indeksbytning skal finde sted:
$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
Alle eksemplerne hidtil har brugt matricer i forskellige dimensioner. Flatten
tilbyder en meget kraftig funktion, der gør det mere end bare en forkortelse for et Table
-udtryk. Flatten
håndterer yndefuldt sagen, hvor underlister på et givet niveau har forskellige længder. Manglende elementer ignoreres stille. For eksempel kan et trekantet array vendes:
$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 *)
…eller vendt og fladt:
Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *)
Kommentarer
- Dette er en fantastisk og grundig forklaring!
- @ rm-rf Tak. Jeg regner med, at hvis
Flatten
blev generaliseret til at acceptere en funktion, der skulle anvendes, når fladning (kontraherende) indekser, ville det være en glimrende start på ” tensoralgebra i en dåse “. - Nogle gange er vi nødt til at lave interne sammentrækninger. Nu ved jeg, at jeg kan gøre det ved hjælp af
Flatten[$m, {{1}, {2, 3}}]
i stedet for Map Flatten over et eller andet niveau. Det ville være rart, hvisFlatten
accepterede negative argumenter for at gøre det. Så denne sag kunne være at skrive somFlatten[$m, -2]
. - Hvorfor dette fremragende svar fik færre stemmer end Leonid ‘ s: (.
- @Tangshutao Se den anden FAQ om min profil .
Svar
Jeg lærte meget af WReachs og Leonids svar, og jeg vil gerne give et lille bidrag:
Det virker værd understrege, at den primære hensigt med det listeværdige andet argument for Flatten
kun er at flade visse niveauer af lister (som WReach nævner i sin Listeudfladning . Brug af Flatten
som en klodset Transpose
virker som en side -effekt af dette primære design, efter min mening.
For eksempel var jeg i går nødt til at omdanne denne liste
lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) };
i denne:
list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) }
Det vil sige, jeg havde brug for at knuse det 2. og 3. liste-niveau sammen.
Jeg gjorde det med
list2 = Flatten[lists, {{1}, {2, 3}}];
Svar
Dette er et gammelt spørgsmål, men ofte stillet af et parti af mennesker. I dag, da jeg prøvede at forklare, hvordan dette fungerer, stødte jeg på en ganske klar forklaring, så jeg tror, at deling af det her ville være nyttigt for et yderligere publikum.
Hvad betyder indeks?
Lad os først gøre klart, hvad indeks : I Mathematica er hvert udtryk et træ, lad os f.eks. Se på en liste:
TreeForm@{{1,2},{3,4}}
Hvordan navigerer du i et træ?
Enkelt! Du starter fra roden og vælger ved hver krydsning hvilken vej du vil gå, for eksempel her, hvis du vil nå 2
, begynder du med at vælge først sti, vælg derefter anden sti. Lad os skrive det ud som {1,2}
hvilket er det eneste indeks for elementet 2
i dette udtryk.
Hvordan forstå Flatten
?
Overvej her et simpelt spørgsmål, hvis jeg ikke giver dig et komplet udtryk, men i stedet giver jeg dig alle elementerne og deres indekser, hvordan konstruerer du det originale udtryk? For eksempel giver jeg dig her:
{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>}
og fortæller dig, at alle hoveder er List
, så hvad er det det originale udtryk?
Nå, du kan helt sikkert rekonstruere det originale udtryk som {{1,2},{3,4}}
, men hvordan? Du kan sandsynligvis angive følgende trin:
- Først ser vi på det første element i indekset og sorterer og samler efter det. Så ved vi, at første element i hele udtrykket skal indeholde de første to -elementer i den oprindelige liste …
- Så fortsætter vi med at se på det andet argument, gør det samme …
- Endelig får vi den oprindelige liste som
{{1,2},{3,4}}
.
Nå, det er rimeligt! Så hvad hvis jeg siger dig, nej, du skal først sortere og samle efter det andet element i indekset og derefter samle efter det første element i indekset? Eller jeg siger, at vi ikke samler dem to gange, vi sorterer bare efter begge elementer, men giver det første argument højere prioritet?
Nå, du får sandsynligvis henholdsvis følgende to liste, ikke?
-
{{1,3},{2,4}}
-
{1,2,3,4}
Nå, tjek selv, Flatten[{{1,2},{3,4}},{{2},{1}}]
og Flatten[{{1,2},{3,4}},{{1,2}}]
gør det samme!
Så hvordan du forstår det andet argument fra Flatten ?
- Hvert listeelement i hovedlisten, for eksempel
{1,2}
, betyder at du skal GATHER alle listerne efter disse elementer i indekset, med andre ord disse niveauer . - Rækkefølgen inde i et listeelement repræsenterer, hvordan du SORT elementerne samlet i en liste i forrige trin . for eksempel betyder
{2,1}
positionen på det andet niveau har højere prioritet end positionen på det første niveau.
Eksempler
Lad os nu øve os på at være fortrolige med tidligere regler.
1. Transpose
Målet med Transpose
på en simpel m * n-matrix er at lave $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Men vi kan overveje det på en anden måde, oprindeligt sorterer vi element efter deres i
indeks først og derefter sortere dem efter deres j
indeks. Nu skal vi bare ændre at sortere dem efter j
indeks først og derefter med i
næste! Så koden bliver:
Flatten[mat,{{2},{1}}]
Enkelt, ikke?
2. Traditionelt Flatten
Målet med traditionel fladning på en simpel m * n-matrix er at Opret et 1D-array i stedet for en 2D-matrix, for eksempel: Flatten[{{1,2},{3,4}}]
returnerer {1,2,3,4}
. Det betyder, at vi ikke “t samler elementer denne gang, vi kun sorter dem, først efter deres første indeks og derefter efter det andet:
Flatten[mat,{{1,2}}]
3. ArrayFlatten
Lad os diskutere et mest simpelt tilfælde af ArrayFlatten, her har vi en 4D-liste:
{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}}
så hvordan kan vi gøre en sådan konvertering for at gøre det til en 2D-liste?
$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ venstre (\ begin {array} {cc} 3 & 4 \\ 7 & 8 \\ \ end {array} \ højre) \\ \ left (\ begin {array} {cc} 9 & 10 \\ 13 & 14 \\ \ end {array} \ højre) & \ 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) $
Nå, dette er også enkelt, vi har brug for gruppen efter det oprindelige første og tredje niveau indeks først, og vi skal give det første indeks højere prioritet i sortering. Det samme gælder det andet og det fjerde niveau:
Flatten[mat,{{1,3},{2,4}}]
4. “Ændr størrelse” på et billede
Nu har vi et billede, for eksempel:
img=Image@RandomReal[1,{10,10}]
Men det er bestemt for lille til, at vi kan se, så vi vil gøre det større ved at udvide hver pixel til en stor pixel på 10 * 10 størrelse.
Først skal vi prøve:
ConstantArray[ImageData@img,{10,10}]
Men det returnerer en 4D-matrix med dimensionerne {10,10,10,10}. Så vi skal Flatten
det. Denne gang vil vi have, at det tredje argument skal have højere prioritet i stedet af den første, så en mindre indstilling fungerer:
Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}]
En sammenligning:
Håber dette kan hjælpe!
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}}
og resultatet ville læse{{{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}}
siger du Hvad der sker er, at elementer, der udgjorde niveau 1 i den oprindelige liste, nu er bestanddele på niveau 2 i resultatet. Jeg forstår ikke ‘, input og output har den samme niveaustruktur, elementerne er stadig på det samme niveau. Kan du forklare det i det store og hele?