Eine Sache, um die ich mich nie kümmern könnte, ist, wie Flatten funktioniert, wenn mit einer Matrix als zweitem Argument versehen, und die Mathematica -Hilfe ist in diesem Fall nicht besonders gut.

Entnommen aus der Flatten Mathematica Dokumentation:

Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}] 

Flacht list ab, indem alle Ebenen $ s_ {ij} $ kombiniert werden, um jede Ebene $ i $ im Ergebnis zu erhalten.

Könnte jemand näher erläutern, was dies tatsächlich bedeutet / tut?

Antwort

Eins Eine bequeme Möglichkeit, Flatten mit dem zweiten Argument zu betrachten, besteht darin, dass es für zerlumpte (unregelmäßige) Listen so etwas wie Transpose ausführt. Hier ist eine einfache Beispiel:

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}} 

Was passiert, sind die Elemente, die konstituieren Die festgelegte Ebene 1 in der ursprünglichen Liste sind jetzt Bestandteile auf der Ebene 2 im Ergebnis und umgekehrt. Dies ist genau das, was Transpose tut, jedoch für unregelmäßige Listen. Beachten Sie jedoch, dass hier einige Informationen zu Positionen verloren gehen, sodass wir die Operation nicht direkt umkehren können:

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}} 

Um sie korrekt umzukehren, hätten wir “ Um so etwas zu tun:

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}} 

Ein interessanteres Beispiel ist, wenn wir tiefer verschachtelt sind:

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}}} 

Auch hier können wir sehen, dass Flatten effektiv wie (generalisiert) Transpose funktioniert hat und Teile auf den ersten beiden Ebenen ausgetauscht hat Folgendes ist schwerer zu verstehen:

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}}} 

Das folgende Bild zeigt diese verallgemeinerte Transponierung:

Darstellung der zyklischen verallgemeinerten Transponierung

Wir können dies in zwei aufeinander folgenden Schritten tun:

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}}} 

Seit der Permutation {3,1,2} kann als {1,3,2} gefolgt von {2,1,3} abgerufen werden benutze Zahlen wh Ich gebe die Position in der Listenstruktur an:

Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *) 

Daraus kann man ersehen, dass in der äußersten Liste (erste Ebene) der dritte Index (entsprechend dem dritte Ebene der ursprünglichen Liste) wächst, in jeder Mitgliederliste (zweite Ebene) wächst das erste Element pro Element (entsprechend der ersten Ebene der ursprünglichen Liste), und schließlich wächst in den innersten Listen (dritte Ebene) der zweite Index , entsprechend der zweiten Ebene in der ursprünglichen Liste. Wenn das als zweites Element übergebene k-te Element der Liste {n} ist, entspricht das Erhöhen des k-ten Index in der resultierenden Listenstruktur im Allgemeinen dem Erhöhen des n-ten Index in der ursprüngliche Struktur.

Schließlich kann man mehrere Ebenen kombinieren, um die Unterebenen effektiv zu reduzieren, wie folgt:

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}} 

Kommentare

  • Ich denke, ‚ ist leichter zu verstehen, wenn die Zahlen die ursprüngliche Position in der verschachtelten Liste angeben. Im Permutationsbeispiel mit drei Zahlen wäre es beispielsweise Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}} und das Ergebnis würde {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} lauten.
  • @celtschk Danke, aber ich bin nicht überzeugt. Für mich persönlich ist es einfacher, visuell unterschiedliche Zahlen zu verfolgen und zu sehen, wo sie in der neuen Struktur landen. Aber zögern Sie nicht, dies zu meiner Antwort hinzuzufügen, das ist vollkommen in Ordnung für mich.
  • Ich denke, unsere Art zu verstehen ist in dieser Hinsicht einfach anders. Eigentlich habe ich die zyklische Permutation erst nach dem Umschreiben vollständig verstanden (aber dann direkt, ohne die zweistufige Zerlegung, die Sie danach durchgeführt haben). Der Punkt ist, dass Sie auf diese Weise sofort sehen können, welcher Index sich ändert, wenn Sie sich entlang jeder Liste bewegen, und Sie können bestimmen, woher die Nummer in der Listenstruktur stammt, ohne die ursprüngliche Liste zu betrachten. Mit anderen Worten, es enthüllt direkter (zumindest für mich) die Struktur der Transformation.
  • @celtschk Ja, ich habe Ihre Argumentation verstanden. Für mich war es jedoch einfacher zu verstehen, welche Elemente welche Listen übersprungen haben, als sich die ‚ -Indizes der Elemente anzusehen. Vielleicht bin ich ‚ nur ich, ich habe mich immer eher für Geometrie als für Algebra interessiert. Ich denke, beide Wege haben ihre Vorzüge.
  • @LeonidShifrin Für 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}} sagen Sie, was passiert, ist, dass Elemente, die Stufe 1 in der ursprünglichen Liste bildeten, jetzt Bestandteile sind Stufe 2 im Ergebnis. Ich verstehe ‚ nicht ganz, Eingabe und Ausgabe haben dieselbe Ebenenstruktur, Elemente befinden sich immer noch auf derselben Ebene. Können Sie dies allgemein erklären?

Antwort

Ein zweites Listenargument für Flatten dient zwei Zwecke. Zunächst wird die Reihenfolge angegeben, in der Indizes beim Sammeln von Elementen iteriert werden. Zweitens wird die Listenreduzierung im Endergebnis beschrieben. Schauen wir uns diese Funktionen nacheinander an.

Iterationsreihenfolge

Betrachten Sie die folgende Matrix:

$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm 

Matrixergebnis

Wir können verwenden Ein Table -Ausdruck zum Erstellen einer Kopie der Matrix durch Iteration aller ihrer Elemente:

$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *) 

Diese Identität Die Operation ist uninteressant, aber wir können das Array transformieren, indem wir die Reihenfolge der Iterationsvariablen vertauschen. Beispielsweise können wir i und j tauschen Iteratoren. Dies läuft darauf hinaus, die Indizes der Ebenen 1 und 2 und ihre entsprechenden Elemente auszutauschen:

$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm 

Matrixergebnis

Wenn wir genau hinschauen, können wir sehen, dass jedes ursprüngliche Element $m[[i, j, k]] dem resultierenden Element $r[[j, i, k]] – Die ersten beiden Indizes haben Biene n „getauscht“.

Flatten ermöglicht es uns, eine äquivalente Operation zu diesem Table Ausdruck prägnanter auszudrücken:

$r === Flatten[$m, {{2}, {1}, {3}}] (* True *) 

Das zweite Argument des Ausdrucks Flatten gibt explizit die gewünschte Indexreihenfolge an: Die Indizes 1, 2, 3 sind geändert, um die Indizes 2, 1, 3 zu werden. Beachten Sie, dass wir nicht für jede Dimension des Arrays einen Bereich angeben mussten – eine erhebliche Bequemlichkeit für die Notation.

Die folgenden Flatten ist eine Identitätsoperation, da keine Änderung der Indexreihenfolge angegeben wird:

$m === Flatten[$m, {{1}, {2}, {3}}] (* True *) 

Der folgende Ausdruck ordnet alle drei Indizes neu an: 1, 2 , 3 -> 3, 2, 1

Flatten[$m, {{3}, {2}, {1}}] // MatrixForm 

Matrixergebnis

Wieder können wir überprüfen, ob ein ursprüngliches Element, das im Index [[i, j, k]] gefunden wurde, jetzt im Ergebnis unter [[k, j, i]] gefunden wird.

Wenn Indizes in einer Flatten Ausdruck, sie werden so behandelt, als ob sie zuletzt und in ihrer natürlichen Reihenfolge angegeben worden wären:

Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *) 

Dieses letzte Beispiel kann noch weiter abgekürzt werden:

Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *) 

Eine leere Indexliste führt zur Identitätsoperation:

$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *) 

Das kümmert sich um die Iterationsreihenfolge und den Indexaustausch. Schauen wir uns nun …

Listenabflachung

an Man könnte sich fragen, warum wir in den vorherigen Beispielen jeden Index in einer Unterliste angeben mussten. Der Grund dafür ist, dass jede Unterliste in der Indexspezifikation angibt, welche Indizes im Ergebnis zusammengeflacht werden sollen. Betrachten Sie erneut die folgende Identitätsoperation:

Flatten[$m, {{1}, {2}, {3}}] // MatrixForm 

Matrixergebnis

Was passiert, wenn wir die ersten beiden Indizes in derselben Unterliste kombinieren? ?

Flatten[$m, {{1, 2}, {3}}] // MatrixForm 

Matrixergebnis

Wir können sehen, dass das ursprüngliche Ergebnis a war 4 x 3 Raster von Paaren, aber das zweite Ergebnis ist eine einfache Liste von Paaren. Die tiefste Struktur, die Paare, wurden unberührt gelassen. Die ersten beiden Ebenen wurden zu einer einzigen Ebene abgeflacht. Die Paare in der dritten Ebene der Quelle Die Matrix blieb nicht abgeflacht.

Wir könnten stattdessen die zweiten beiden Indizes kombinieren:

Flatten[$m, {{1}, {2, 3}}] // MatrixForm 

Matrixergebnis

Dieses Ergebnis hat die gleiche Anzahl von Zeilen wie die ursprüngliche Matrix, was bedeutet, dass die erste Ebene unberührt blieb. Jede Ergebniszeile enthält jedoch eine flache Liste von sechs Elementen aus der entsprechenden ursprünglichen Zeile mit drei Paaren. Daher wurden die beiden unteren Ebenen abgeflacht.

Wir können auch alle drei Indizes kombinieren, um ein vollständig abgeflachtes Ergebnis zu erhalten:

Flatten[$m, {{1, 2, 3}}] 

Matrixergebnis

Dies kann abgekürzt werden:

Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *) 

Flatten bietet auch eine Kurzschreibweise, wenn kein Indexaustausch stattfinden soll:

$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

In allen bisherigen Beispielen wurden Matrizen mit verschiedenen Dimensionen verwendet. Flatten bietet eine sehr leistungsstarke Funktion, die mehr als nur eine Abkürzung für einen Table -Ausdruck darstellt. Flatten behandelt den Fall, in dem Unterlisten auf einer bestimmten Ebene unterschiedliche Längen haben, ordnungsgemäß. Fehlende Elemente werden stillschweigend ignoriert. Beispielsweise kann ein dreieckiges Array umgedreht werden:

$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 *) 

…oder gespiegelt und abgeflacht:

Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *) 

Kommentare

  • Dies ist eine fantastische und gründliche Erklärung!
  • @ rm-rf Danke. Ich denke, wenn Flatten verallgemeinert würde, um eine Funktion zu akzeptieren, die beim Reduzieren (Kontrahieren) von Indizes angewendet werden soll, wäre dies ein ausgezeichneter Start für “ Tensoralgebra in einer Dose „.
  • Manchmal müssen wir interne Kontraktionen durchführen. Jetzt weiß ich, dass ich es mit Flatten[$m, {{1}, {2, 3}}] anstelle von Map Flatten über eine bestimmte Ebene tun kann. Es wäre schön, wenn Flatten negative Argumente dafür akzeptieren würde. Dieser Fall könnte also wie folgt geschrieben werden: Flatten[$m, -2].
  • Warum diese hervorragende Antwort weniger Stimmen erhielt als Leonid ‚ s: (.
  • @Tangshutao Siehe die zweiten FAQ in meinem -Profil .

Antwort

Ich habe viel aus den Antworten von WReach und Leonid gelernt und möchte einen kleinen Beitrag leisten:

Es scheint sich zu lohnen Hervorheben, dass die Hauptabsicht des zweiten Arguments mit Listenwert von Flatten lediglich darin besteht, bestimmte Listenebenen zu reduzieren (wie WReach in seinem Listenabflachung Abschnitt). Die Verwendung von Flatten als zerlumpte Transpose scheint eine Seite zu sein -Effekt dieses primären Designs, meiner Meinung nach.

Zum Beispiel musste ich gestern diese Liste transformieren

lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) }; 

treeform1

in diese:

list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) } 

treeform2

Das heißt, ich musste die 2. und 3. Listenebene zusammenbrechen.

Ich habe es mit

list2 = Flatten[lists, {{1}, {2, 3}}]; 

gemacht

Antwort

Dies ist eine alte Frage, die jedoch häufig von einem Los von Menschen. Als ich heute versuchte zu erklären, wie dies funktioniert, stieß ich auf eine ziemlich klare Erklärung, daher denke ich, dass es für ein weiteres Publikum hilfreich wäre, sie hier zu teilen.

Was bedeutet Index?

Machen wir zuerst klar, was index ist: In Mathematica ist jeder Ausdruck ein Baum, sehen wir uns zum Beispiel um in einer Liste:

TreeForm@{{1,2},{3,4}} 

illus1

Wie navigieren Sie in einem Baum?

Einfach! Sie beginnen an der Wurzel und wählen an jeder Kreuzung den Weg aus. Wenn Sie beispielsweise 2 erreichen möchten, beginnen Sie mit der Auswahl von zuerst Pfad, dann wählen Sie den zweiten Pfad. Schreiben wir es als {1,2}, was nur der Index des Elements 2 in diesem Ausdruck ist.

Wie verstehe ich Flatten?

Betrachten Sie hier eine einfache Frage, wenn ich Ihnen keinen vollständigen Ausdruck gebe, sondern Ihnen alle Elemente und gebe ihre Indizes, wie konstruieren Sie den ursprünglichen Ausdruck? Zum Beispiel gebe ich Ihnen hier:

{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>} 

und sage Ihnen, dass alle Köpfe List sind, also was „s der ursprüngliche Ausdruck?

Nun, Sie können den ursprünglichen Ausdruck sicherlich als {{1,2},{3,4}} rekonstruieren, aber wie? Sie können wahrscheinlich die folgenden Schritte auflisten:

  1. Zuerst schauen wir uns das erste Element des Index an und sortieren und sammeln danach. Dann wissen wir, dass die zuerst Element des gesamten Ausdrucks sollte die ersten beiden Elemente in der ursprünglichen Liste enthalten …
  2. Dann schauen wir uns das zweite Argument weiter an und machen dasselbe …
  3. Schließlich erhalten wir die ursprüngliche Liste als {{1,2},{3,4}}.

Nun, das ist vernünftig! Was ist, wenn ich Ihnen sage, nein, Sie sollten zuerst nach dem zweiten Element des Index sortieren und sammeln und dann nach dem ersten Element des Index sammeln? Oder ich sage, wir sammeln sie nicht zweimal, wir sortieren nur nach beiden Elementen, geben dem ersten Argument jedoch eine höhere Priorität?

Nun, Sie würden wahrscheinlich die folgenden beiden Listen erhalten, oder?

  1. {{1,3},{2,4}}
  2. {1,2,3,4}

Nun, Überprüfen Sie selbst, Flatten[{{1,2},{3,4}},{{2},{1}}] und Flatten[{{1,2},{3,4}},{{1,2}}] machen dasselbe!

Wie verstehen Sie das zweite Argument von Flatten? ?

  1. Jedes Listenelement in der Hauptliste, z. B. {1,2}, bedeutet, dass Sie verwenden sollten GATHER alle Listen gemäß diesen Elementen im Index, mit anderen Worten diese Ebenen .
  2. Die Reihenfolge in einem Listenelement gibt an, wie Sie SORTIEREN die Elemente, die im vorherigen Schritt in einer Liste gesammelt wurden . Beispiel: {2,1} bedeutet, dass die Position auf der zweiten Ebene eine höhere Priorität hat als die Position auf der ersten Ebene.

Beispiele

Lassen Sie uns nun etwas üben, um mit früheren Regeln vertraut zu sein.

1. Transpose

Das Ziel von Transpose in einer einfachen m * n-Matrix ist es, $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $ zu machen. Aber wir können es anders betrachten, ursprünglich sortieren wir die Element nach ihrem i -Index zuerst sortieren und dann nach ihrem j -Index sortieren. Jetzt müssen wir nur noch ändern, um sie nach j zuerst indexieren, dann durch i weiter! Der Code lautet also:

Flatten[mat,{{2},{1}}] 

Einfach, richtig?

2. Traditionell Flatten

Das Ziel der traditionellen Abflachung auf einer einfachen m * n-Matrix ist es, Erstellen Sie ein 1D-Array anstelle einer 2D-Matrix. Beispiel: Flatten[{{1,2},{3,4}}] gibt {1,2,3,4}. Dies bedeutet, dass wir diesmal keine Elemente sammeln, sondern nur sortieren Sie sie zuerst nach ihrem ersten Index und dann nach dem zweiten:

Flatten[mat,{{1,2}}] 

3. ArrayFlatten

Lassen Sie uns einen sehr einfachen Fall von ArrayFlatten diskutieren. Hier haben wir eine 4D-Liste:

{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}} 

Wie können wir eine solche Konvertierung durchführen, um daraus eine 2D-Liste zu machen?

$ \ 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) $

Nun, das ist auch einfach, wir brauchen zuerst die Gruppe nach dem ursprünglichen Index der ersten und der dritten Ebene, und wir sollten dem ersten Index in eine höhere Priorität geben Sortierung. Gleiches gilt für die zweite und vierte Ebene:

Flatten[mat,{{1,3},{2,4}}] 

4. Bildgröße ändern

Jetzt haben wir ein Bild, zum Beispiel:

img=Image@RandomReal[1,{10,10}] 

Aber es ist definitiv zu klein für uns Wir möchten es also vergrößern, indem wir jedes Pixel auf ein riesiges Pixel mit einer Größe von 10 * 10 erweitern.

Zuerst werden wir versuchen:

ConstantArray[ImageData@img,{10,10}] 

Es wird jedoch eine 4D-Matrix mit den Dimensionen {10,10,10,10} zurückgegeben. Wir sollten sie also Flatten verwenden. Dieses Mal soll das dritte Argument stattdessen eine höhere Priorität haben von der ersten würde also eine geringfügige Abstimmung funktionieren:

Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}] 

Ein Vergleich:

illus2

Hoffe, das könnte helfen!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.