Egy dolog, amire soha nem tudtam átgondolni a fejemet, az az, hogy a Flatten
hogyan működik, amikor második argumentumként mátrixot kapott, és a Mathematica súgó nem különösebben jó ebben.
A Flatten
Mathematica dokumentáció:
Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}]
Elsimítja
list
az összes $ s_ {ij} $ szint kombinálásával, hogy minden szint $ i $ legyen az eredményben.
Tudna valaki részletezni, hogy ez valójában mit jelent / jelent?
Válasz
Egy A Flatten
gondolkodásának kényelmes módja a második érvvel az, hogy valami olyasmit hajt végre, mint a Transpose
rongyos (szabálytalan) listáknál. Itt van egy egyszerű példa:
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}}
Az történik, hogy az elemek alkotják Az eredeti listában az uted 1
szint mostantól az eredmény 2
szintű alkotóelemei és fordítva. A Transpose
pontosan ezt teszi, de a szabálytalan listák esetében. Ne feledje azonban, hogy a pozíciókkal kapcsolatos információk itt elvesznek, ezért nem tudjuk közvetlenül megfordítani a műveletet:
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}}
A helyes megfordítás érdekében ilyesmit tenni:
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}}
Érdekesebb példa, ha mélyebben fészkelünk:
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}}}
Itt is láthatjuk, hogy a Flatten
hatékonyan működött (általánosítva) Transpose
, és az első 2 szinten darabokat váltott . A következőket nehezebb lesz megérteni:
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}}}
A következő kép ezt az általános átültetést szemlélteti:
Két egymást követő lépésben tehetjük meg:
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}}}
Mivel a permutáció {3,1,2}
{1,3,2}
néven kapható, amelyet {2,1,3}
követhet. A működésének másik módja az, hogy számokat használjon wh ich jelzi a pozíciót a listaszerkezetben:
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *)
Ebből látható, hogy a legkülső listában (első szint) a harmadik index (a az eredeti lista harmadik szintje) nő, minden taglistában (második szint) az első elem növekszik elemenként (megfelel az eredeti lista első szintjének), végül a legbelső (harmadik szint) listákban a második index növekszik , amely megfelel az eredeti lista második szintjének. Általában, ha a lista második elemként átadott k-edik eleme {n}
, az eredményül kapott listaszerkezetben a k-edik index növelése megfelel az eredeti struktúra.
Végül több szint kombinálható az alszintek hatékony ellaposításához, így:
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}}
Megjegyzések
Válasz
A Flatten
cím második argumentuma kettőt szolgál célokra. Először meghatározza az indexek iterációjának sorrendjét az elemek összegyűjtésekor. Másodszor a végeredményben a lista laposodását írja le. Nézzük soronként ezeket a képességeket.
Iterációs sorrend
Vegye figyelembe a következő mátrixot:
$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm
Használhatjuk Table
kifejezés a mátrix másolatának létrehozására az összes elemének ismétlésével:
$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *)
Ez az identitás a művelet nem érdekes, de a tömböt átalakíthatjuk az iterációs változók sorrendjének felcserélésével. Például felcserélhetjük a i
és a j
iterátorok. Ez az 1. és 2. szintű indexek és azok megfelelő elemeinek felcserélését jelenti:
$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm
Ha alaposan megnézzük, láthatjuk, hogy minden egyes eredeti elem, $m[[i, j, k]]
, megfelel a kapott elemnek: $r[[j, i, k]]
– az első két index méh n “cserélve”.
Flatten
lehetővé teszi számunkra, hogy ezzel az Table
kifejezéssel egyenértékűbb műveletet fejezzünk ki tömörebben:
$r === Flatten[$m, {{2}, {1}, {3}}] (* True *)
A Flatten
kifejezés második argumentuma kifejezetten meghatározza a kívánt indexrendet: az 1, 2, 3 indexek 2, 1, 3 indexgé változik. Vegye figyelembe, hogy miért nem kellett tartományt megadnunk a tömb minden dimenziójához – ez jelentős jelölési kényelem.
A következő Flatten
egy identitásművelet, mivel nem határoz meg változásokat az index sorrendjében:
$m === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Míg a következő kifejezés mindhárom indexet átrendezi: 1, 2 , 3 -> 3, 2, 1
Flatten[$m, {{3}, {2}, {1}}] // MatrixForm
Ismét , ellenőrizhetjük, hogy az [[i, j, k]]
indexnél található eredeti elem megtalálható-e az eredményben a [[k, j, i]]
címen.
Ha valamely index elhagyásra kerül egy Flatten
kifejezés, úgy kezeljük őket, mintha utoljára és természetes sorrendjükben lett volna megadva:
Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *)
Ez az utolsó példa még rövidítve:
Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *)
Egy üres indexlista eredményezi az identitásműveletet:
$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Ez gondoskodik az iterációs sorrendről és az indexcseréről. Most nézzük meg …
Lista lapozás
Elképzelhető, hogy miért kellett az előző példákban megadnunk az egyes indexeket egy allistában. Ennek oka az, hogy az index-specifikáció minden egyes allistája meghatározza, hogy mely indexeket kell lapítani az eredménybe. Vizsgáljuk meg újra a következő azonossági műveletet:
Flatten[$m, {{1}, {2}, {3}}] // MatrixForm
Mi történik, ha az első két indexet egyesítjük ugyanabban az allistában ?
Flatten[$m, {{1, 2}, {3}}] // MatrixForm
Láthatjuk, hogy az eredeti eredmény egy 4 x 3 pár rács, de a második eredmény a párok egyszerű felsorolása. A legmélyebb struktúra, a párok érintetlenül maradtak. Az első két szintet egy szintre simítottuk. A forrás harmadik szintjén lévő párok a mátrix lapítatlan maradt.
Helyettesíthetjük a második két indexet:
Flatten[$m, {{1}, {2, 3}}] // MatrixForm
Ennek az eredménynek ugyanannyi sora van, mint az eredeti mátrixnak, vagyis az első szintet érintetlenül hagyták. De mindegyik eredménysornak hat elemből álló lapos listája van, amely a megfelelő eredeti három pár sorból származik. Így az alsó két szintet ellapítottuk.
Mindhárom indexet kombinálhatjuk is, hogy teljesen lapos eredményt kapjunk:
Flatten[$m, {{1, 2, 3}}]
Ez rövidíthető:
Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *)
rövidítés jelölést is kínál, ha nem történik indexcsere:
$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” tömbök
Az eddigi összes példa különböző dimenziójú mátrixokat használt. A Flatten
egy nagyon hatékony funkciót kínál, amely nem csupán egy Table
kifejezés rövidítését jelenti. A Flatten
kecsesen fogja kezelni azt az esetet, amikor az adott szintű allisták hossza eltérő. A hiányzó elemeket csendben figyelmen kívül hagyjuk. Például egy háromszög alakú tömb átfordítható:
$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 *)
…vagy lapított és lapított:
Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *)
Megjegyzések
- Ez egy fantasztikus és alapos magyarázat!
- @ rm-rf Köszönöm. Úgy gondolom, hogy ha a
Flatten
általánosítanák, hogy elfogadják az indexek ellapításakor alkalmazandó függvényt, az kiváló kezdet lenne a ” tenzor algebra egy dobozban “. - Néha belső összehúzódásokat kell végrehajtanunk. Most már tudom, hogy meg tudom csinálni a
Flatten[$m, {{1}, {2, 3}}]
használatával a Map Flatten helyett valamilyen szinten. Jó lenne, haFlatten
negatív érveket fogadna el ehhez. Tehát ezt az esetet úgy írhatjuk, hogyFlatten[$m, -2]
. - Miért kapott ez a kiváló válasz kevesebb szavazatot, mint Leonid ‘ s: (.
- @Tangshutao Lásd a második GYIK-ot a profilomon .
Válasz
Sokat tanultam a WReach és Leonid válaszaiból, és szeretnék egy kis hozzájárulást adni:
Úgy tűnik, érdemes hangsúlyozva, hogy a Flatten
listaértékű második argumentumának elsődleges célja csupán a listák bizonyos szintjeinek ellaposítása (ahogy a WReach megemlíti a Lista lapozás szakasz). A Flatten
rongyos Transpose
használata oldalnak tűnik véleményem szerint ennek az elsődleges tervezésnek a hatása.
Például tegnap át kellett alakítanom ezt a listát
lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) };
ebbe:
list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) }
Vagyis össze kellett törnöm a 2. és a 3. listaszintet.
A
list2 = Flatten[lists, {{1}, {2, 3}}];
Válasz
Ez egy régi kérdés, de gyakran feltesz egy tétel emberek. Ma, amikor megpróbáltam elmagyarázni, hogyan működik ez, egy egészen világos magyarázatra bukkantam, ezért úgy gondolom, hogy a megosztása itt hasznos lehet a további közönség számára.
Mit jelent az index?
Először tegyük világossá, mi a index : A Mathematicában minden kifejezés egy fa, például nézzük meg listán:
TreeForm@{{1,2},{3,4}}
Hogyan navigálsz egy fán?
Egyszerű! A gyökérből indul ki, és minden átkelésnél kiválaszthatja, hogy melyik irányba haladjon, például itt, ha el akarja érni a 2
fájlt, akkor kezdje el a
első elérési út, majd válassza a második utat. Írjuk ki “s”{1,2}
néven, amely csak a2
elem indexe ebben a kifejezésben.
Hogyan lehet megérteni a Flatten
?
Itt vegyünk fontolóra egy egyszerű kérdést, ha nem adok neked teljes kifejezést, de ehelyett megadom neked az összes elemet és indexeik, hogyan szerkeszted az eredeti kifejezést? Például itt megadom neked:
{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>}
és mondom, hogy minden fej List
, tehát mi van? az eredeti kifejezés?
Nos, biztosan rekonstruálhatja az eredeti kifejezést {{1,2},{3,4}}
néven, de hogyan? Valószínűleg felsorolhatja a következő lépéseket:
- Először az index első elemét nézzük meg, rendezzük és összegyűjtjük. Ezután tudjuk, hogy a első a teljes kifejezés elemének tartalmaznia kell az első két elemet az eredeti listában …
- Ezután folytatjuk a második argumentum vizsgálatát, tegyük ugyanezt …
- Végül az eredeti listát
{{1,2},{3,4}}
néven kapjuk meg.
Nos, ez ésszerű! Szóval mi van, ha azt mondom, hogy nem, akkor először az index második eleme szerint kell rendezni és összegyűjteni, majd az index első eleme alapján összegyűjteni? Vagy azt mondom, hogy nem gyűjtjük őket kétszer, csak mindkét elem szerint válogatunk, de az első argumentumnak nagyobb prioritást adunk?
Nos, valószínűleg a következő két listát kapnád, igaz?
-
{{1,3},{2,4}}
-
{1,2,3,4}
Nos, ellenőrizze egyedül, Flatten[{{1,2},{3,4}},{{2},{1}}]
és Flatten[{{1,2},{3,4}},{{1,2}}]
tegye ugyanezt!
Szóval, hogy érted a Flatten második argumentumát ?
- A fő lista belsejében található minden listaelem, például
{1,2}
, azt jelenti, hogy GATHER az összes lista az index ezen elemei szerint, más szóval ezek az szintek . - A listaelemen belüli sorrend azt ábrázolja, hogyan SORT rendezi az előző lépésben a listán belül összegyűjtött elemeket. . például a
{2,1}
azt jelenti, hogy a második szint pozíciójának elsőbbsége van, mint az első szint pozíciójának.
Példák
Most legyen némi gyakorlata, hogy ismerje a korábbi szabályokat.
1. Transpose
A Transpose
egy egyszerű m * n mátrixon $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $ értéket kap. De tekinthetjük más módon is, eredetileg a elemet először i
indexük alapján, majd j
indexük szerint rendezzük, most csak annyit kell tennünk, hogy változtatnunk kell a j
indexeljen először, majd i
következővel! Tehát a kód:
Flatten[mat,{{2},{1}}]
Egyszerű, igaz?
2. Hagyományos Flatten
A hagyományos lapítás célja egy egyszerű m * n mátrixon: hozzon létre 1D tömböt 2D mátrix helyett, például: Flatten[{{1,2},{3,4}}]
visszatér {1,2,3,4}
. Ez azt jelenti, hogy ezúttal nem “t gyűjtünk elemeket, csak rendezze őket, először az első indexük, majd a második szerint:
Flatten[mat,{{1,2}}]
3. ArrayFlatten
Beszéljük meg az ArrayFlatten legegyszerűbb esetét, itt van egy 4D-s lista:
{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}}
tehát hogyan lehet egy ilyen átalakítást 2D listává tenni?
$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {tömb} \ jobb) & \ balra (\ begin {array} {cc} 3 & 4 \\ 7 & 8 \\ end {array} \ right) \\ \ left (\ begin {array} {cc} 9 & 10 \\ 13 & 14 \\ \ end {tömb} \ jobb) & \ left (\ begin {array} {cc} 11 & 12 \\ 15 & 16 \\ \ end {array} \ right) \\ \ end {tömb} \ right) \ rightarrow \ left (\ begin {tömb} {cccc} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ 13 & 14 & 15 & 16 \\ \ end {array} \ right) $
Nos, ez is egyszerű, először az eredeti első és a harmadik szintű index alapján kell a csoportot megadni, és az első indexnek nagyobb prioritást kell adnunk válogató. Ugyanez vonatkozik a második és a negyedik szintre is:
Flatten[mat,{{1,3},{2,4}}]
4. Kép átméretezése
Most van egy képünk, például:
img=Image@RandomReal[1,{10,10}]
De határozottan túl kicsi ahhoz, hogy nézetet, ezért nagyobbá akarjuk tenni az egyes pixelek 10 * 10-es méretű hatalmas pixelekké való kiterjesztését.
Először megpróbáljuk:
ConstantArray[ImageData@img,{10,10}]
De egy 4D-s mátrixot ad vissza, amelynek dimenziói: {10,10,10,10}. Ezért Flatten
meg kell adnunk. Ezúttal azt akarjuk, hogy a harmadik argumentum magasabb prioritást élvezzen az elsőből, így egy kisebb hangolás működne:
Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}]
Összehasonlítás:
Remélem, hogy ez segíthet!
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}}
lenne, az eredmény pedig{{{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}}
esetében azt mondod, hogy mi történik, az az elem, amely az eredeti listában az 1. szintet alkotta, most alkotóelem 2. szint az eredményben. Nem ‘ nem értem, a bemenetnek és a kimenetnek ugyanaz a szintstruktúrája, az elemek továbbra is ugyanazon a szinten vannak. Meg tudnád magyarázni ezt általában?