Une chose que je ne pourrais jamais comprendre, cest comment Flatten fonctionne quand fourni avec une matrice comme deuxième argument, et laide Mathematica nest pas particulièrement bonne sur celui-ci.

Tiré de Flatten Mathematica documentation:

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

Aplatit list en combinant tous les niveaux $ s_ {ij} $ pour rendre chaque niveau $ i $ dans le résultat.

Quelquun pourrait-il expliquer ce que cela signifie / signifie réellement?

Réponse

Un un moyen pratique de penser à Flatten avec le deuxième argument est quil exécute quelque chose comme Transpose pour les listes irrégulières (irrégulières). Voici un simple exemple:

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 qui se passe, cest que les éléments qui constituent uted level 1 dans la liste dorigine sont maintenant des constituants au niveau 2 dans le résultat, et vice versa. Cest exactement ce que fait Transpose, mais fait pour les listes irrégulières. Notez cependant que certaines informations sur les positions sont perdues ici, nous ne pouvons donc pas inverser directement lopération:

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

Pour linverser correctement, nous « aurions pour faire quelque chose comme ceci:

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 exemple plus intéressant est celui où nous avons une imbrication plus profonde:

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

Ici encore, nous pouvons voir que Flatten fonctionnait effectivement comme (généralisé) Transpose, en interchangeant les pièces aux 2 premiers niveaux . Ce qui suit sera plus difficile à comprendre:

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

Limage suivante illustre cette transposition généralisée:

Illustration de la transposition généralisée cyclique

On peut le faire en deux étapes consécutives:

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

Depuis la permutation {3,1,2} peut être obtenu sous la forme {1,3,2} suivi de {2,1,3}. Une autre façon de voir comment cela fonctionne est de utiliser des nombres wh ich indique la position dans la structure de la liste:

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

De là, on peut voir que dans la liste la plus externe (premier niveau), le troisième index (correspondant au troisième niveau de la liste dorigine) grandit, dans chaque liste de membres (deuxième niveau) le premier élément grandit par élément (correspondant au premier niveau de la liste originale), et enfin dans les listes les plus internes (troisième niveau), le deuxième index grandit , correspondant au deuxième niveau de la liste dorigine. Généralement, si le k-ième élément de la liste passé comme deuxième élément est {n}, augmenter le k-ième indice dans la structure de liste résultante correspond à augmenter le n-ième indice dans le structure originale.

Enfin, on peut combiner plusieurs niveaux pour aplatir efficacement les sous-niveaux, comme ceci:

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

Commentaires

  • Je pense que ‘ est plus facile à comprendre si les nombres indiquent la position dorigine dans la liste imbriquée. Par exemple, dans lexemple de permutation à trois nombres, ce serait Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}} et le résultat serait {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}}.
  • @celtschk Merci, mais je ne suis pas convaincu. Pour moi personnellement, il est plus facile de suivre des nombres visuellement distincts et de voir où ils aboutissent dans la nouvelle structure. Mais nhésitez pas à ajouter ceci à ma réponse, cela me convient parfaitement.
  • Je suppose que nos façons de comprendre sont simplement différentes à cet égard. En fait, seulement après avoir réécrit mon chemin, jai complètement compris la permutation cyclique (mais directement, sans la décomposition en deux étapes que vous avez faite par la suite). Le fait est que de cette façon, vous pouvez voir immédiatement quel index change si vous vous déplacez le long de chaque liste, et vous pouvez déterminer doù provient le numéro dans la structure de la liste sans même regarder la liste dorigine. En dautres termes, cela révèle plus directement (du moins à moi) la structure de la transformation.
  • @celtschk Oui, jai compris votre raisonnement. Mais pour moi, il était plus facile de comprendre quels éléments sautaient quelles listes, plutôt que de regarder les éléments ‘ indices. Peut-être que ‘ est juste moi, jai toujours été attirée par la géométrie plutôt que par lalgèbre. Je pense que les deux manières ont leurs mérites.
  • @LeonidShifrin Pour 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}}, vous dites que ce qui se passe, cest que les éléments qui constituaient le niveau 1 dans la liste originale sont maintenant des constituants à niveau 2 dans le résultat. Je ne ‘ pas tout à fait comprendre, lentrée et la sortie ont la même structure de niveau, les éléments sont toujours au même niveau. Pouvez-vous expliquer cela en général?

Réponse

Un deuxième argument de liste à Flatten sert deux fins. Premièrement, il spécifie lordre dans lequel les index seront itérés lors de la collecte des éléments. Deuxièmement, il décrit laplatissement de la liste dans le résultat final. Examinons chacune de ces fonctionnalités tour à tour.

Ordre ditération

Considérez la matrice suivante:

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

résultat de la matrice

Nous pouvons utiliser une expression Table pour créer une copie de la matrice en itérant sur tous ses éléments:

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

Cette identité lopération nest pas intéressante, mais nous pouvons transformer le tableau en inversant lordre des variables ditération. Par exemple, nous pouvons permuter i et j itérateurs. Cela revient à permuter les indices de niveau 1 et de niveau 2 et leurs éléments correspondants:

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

matrice résultat

Si nous regardons attentivement, nous pouvons voir que chaque élément dorigine $m[[i, j, k]] correspondra à lélément résultant $r[[j, i, k]] – les deux premiers indices ont bee n « swapped ».

Flatten nous permet dexprimer une opération équivalente à cette Table expression plus succinctement:

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

Le deuxième argument de lexpression Flatten spécifie explicitement lordre dindex souhaité: les indices 1, 2, 3 sont modifié pour devenir des indices 2, 1, 3. Notez que nous navons pas eu besoin de spécifier une plage pour chaque dimension du tableau – une commodité de notation significative.

Ce qui suit Flatten est une opération didentité car elle ne spécifie aucun changement dans lordre des index:

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

Alors que lexpression suivante réorganise les trois indices: 1, 2 , 3 -> 3, 2, 1

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

résultat de la matrice

Encore , nous pouvons vérifier quun élément dorigine trouvé à lindex [[i, j, k]] sera désormais trouvé à [[k, j, i]] dans le résultat.

Si des indices sont omis dun Flatten expression, ils sont traités comme sils avaient été spécifiés en dernier et dans leur ordre naturel:

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

Ce dernier exemple peut être abrégée encore plus loin:

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

Une liste dindex vide entraîne lopération didentité:

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

Cela prend en charge lordre ditération et léchange dindex. Voyons maintenant …

Aplatissement de la liste

On peut se demander pourquoi nous avons dû spécifier chaque index dans une sous-liste dans les exemples précédents. La raison en est que chaque sous-liste de la spécification dindex spécifie quels index doivent être aplatis dans le résultat. Réfléchissez à lopération didentité suivante:

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

résultat de la matrice

Que se passe-t-il si nous combinons les deux premiers indices dans la même sous-liste ?

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

résultat de la matrice

Nous pouvons voir que le résultat original était un Grille de paires 4 x 3, mais le deuxième résultat est une simple liste de paires. La structure la plus profonde, les paires, na pas été modifiée. Les deux premiers niveaux ont été aplatis en un seul niveau. Les paires du troisième niveau de la source matrice est restée non aplatie.

Nous pourrions combiner les deux deuxièmes indices à la place:

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

résultat de la matrice

Ce résultat a le même nombre de lignes que la matrice dorigine, ce qui signifie que le premier niveau na pas été touché. Mais chaque ligne de résultat a une liste plate de six éléments tirés de la ligne dorigine correspondante de trois paires. Ainsi, les deux niveaux inférieurs ont été aplatis.

Nous pouvons également combiner les trois indices pour obtenir un résultat complètement aplati:

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

résultat de la matrice

Ceci peut être abrégé:

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

Flatten propose également une notation abrégée lorsquaucun échange dindex ne doit avoir lieu:

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

Tableaux « Ragged »

Jusquà présent, tous les exemples ont utilisé des matrices de différentes dimensions. Flatten offre une fonctionnalité très puissante qui en fait plus quune simple abréviation pour une expression Table. Flatten traitera gracieusement le cas où les sous-listes à un niveau donné ont des longueurs différentes. Les éléments manquants seront discrètement ignorés. Par exemple, un tableau triangulaire peut être retourné:

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

…ou retourné et aplati:

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

Commentaires

  • Cest une explication fantastique et approfondie!
  • @ rm-rf Merci. Je suppose que si Flatten était généralisé pour accepter une fonction à appliquer lors de laplatissement (de la contraction) des indices, ce serait un excellent début pour  » algèbre tensorielle dans un can « .
  • Parfois, nous devons faire des contractions internes. Maintenant, je sais que je peux le faire en utilisant Flatten[$m, {{1}, {2, 3}}] au lieu de Map Flatten sur un certain niveau. Ce serait bien si Flatten acceptait des arguments négatifs pour faire cela. Donc ce cas pourrait être écrit comme Flatten[$m, -2].
  • Pourquoi cette excellente réponse a obtenu moins de votes que Leonid ‘ s: (.
  • @Tangshutao Voir la deuxième FAQ sur mon profil .

Réponse

Jai beaucoup appris des réponses de WReach et Leonid et jaimerais apporter une petite contribution:

Cela vaut la peine soulignant que lintention première du deuxième argument de valeur de liste de Flatten est simplement daplatir certains niveaux de listes (comme le mentionne WReach dans son Aplatissement de la liste section). Utiliser Flatten comme un Transpose en lambeaux semble être un côté -effet de cette conception principale, à mon avis.

Par exemple, hier, javais besoin de transformer cette liste

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

treeform1

dans celui-ci:

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

treeform2

Autrement dit, je devais écraser les deuxième et troisième niveaux de liste ensemble.

Je lai fait avec

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

Réponse

Cest une vieille question, mais fréquemment posée par un lot de personnes. Aujourdhui, alors que jessayais dexpliquer comment cela fonctionne, je suis tombé sur une explication assez claire, donc je pense que la partager ici serait utile pour un public plus large.

Que signifie lindex?

Commençons par préciser ce que index est: Dans Mathematica, chaque expression est un arbre, par exemple, regardons dans une liste:

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

illus1

Comment naviguez-vous dans un arbre?

Simple! Vous partez de la racine et à chaque croisement choisissez le chemin à suivre, par exemple ici si vous voulez atteindre 2, vous commencez par choisir le premier chemin, puis choisissez le deuxième chemin. Écrivons-le sous la forme {1,2} qui est simplement lindex de lélément 2 dans cette expression.

Comment comprendre Flatten?

Considérons ici une question simple, si je ne vous donne pas une expression complète, mais à la place je vous donne tous les éléments et leurs index, comment construisez-vous lexpression originale? Par exemple, je vous donne ici:

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

et je vous dis que toutes les têtes sont List, alors que « s lexpression originale?

Eh bien, vous pouvez sûrement reconstruire lexpression originale comme {{1,2},{3,4}}, mais comment? Vous pouvez probablement énumérer les étapes suivantes:

  1. Commençons par examiner le premier élément de lindex et le trions et le rassemblons. Ensuite, nous savons que le premier Lélément de lexpression entière doit contenir les deux premiers éléments de la liste dorigine …
  2. Ensuite, nous continuons à regarder le deuxième argument, faisons de même …
  3. Enfin, nous obtenons la liste dorigine sous la forme {{1,2},{3,4}}.

Eh bien, cest raisonnable! Alors que faire si je vous dis, non, vous devriez dabord trier et rassembler par le deuxième élément de lindex, puis rassembler par le premier élément de lindex? Ou je dis que nous ne les rassemblons pas deux fois, nous trions simplement par les deux éléments mais donnons au premier argument une priorité plus élevée?

Eh bien, vous obtiendrez probablement les deux listes suivantes respectivement, non?

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

Eh bien, vérifiez par vous-même, Flatten[{{1,2},{3,4}},{{2},{1}}] et Flatten[{{1,2},{3,4}},{{1,2}}] faites de même!

Alors, comment vous comprenez le deuxième argument de Flatten ?

  1. Chaque élément de la liste dans la liste principale, par exemple {1,2}, signifie que vous devriez RASSEMBLEZ toutes les listes en fonction de ces éléments dans lindex, cest-à-dire ces niveaux .
  2. Lordre à lintérieur dun élément de liste représente la manière dont vous TRIER les éléments rassemblés dans une liste à létape précédente . par exemple, {2,1} signifie que la position au deuxième niveau a une priorité plus élevée que la position au premier niveau.

Exemples

Prenons maintenant un peu de pratique pour se familiariser avec les règles précédentes.

1. Transpose

Lobjectif de Transpose sur une simple matrice m * n est de faire $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Mais nous pouvons le considérer autrement, à lorigine nous trions les élément par leur index i puis triez-les par leur index j, il ne nous reste plus quà changer pour les trier par j indexer dabord puis par i ensuite! Le code devient donc:

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

Simple, non?

2. Traditionnel Flatten

Le but de laplatissement traditionnel sur une simple matrice m * n est de créer un tableau 1D au lieu dune matrice 2D, par exemple: Flatten[{{1,2},{3,4}}] renvoie {1,2,3,4}. Cela signifie que nous ne « t rassemblons éléments cette fois, que trier , dabord par leur premier index puis par le second:

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

3. ArrayFlatten

Parlons dun cas très simple de ArrayFlatten, nous avons ici une liste 4D:

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

alors comment faire une telle conversion pour en faire une liste 2D?

$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ gauche (\ 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) $

Eh bien, cest simple aussi, nous avons besoin du groupe par le premier et le troisième index dorigine en premier, et nous devrions donner au premier index une priorité plus élevée dans tri. Il en va de même pour le deuxième et le quatrième niveau:

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

4. « Redimensionner » une image

Nous avons maintenant une image, par exemple:

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

Mais cest vraiment trop petit pour nous view, nous voulons donc lagrandir en étendant chaque pixel à un énorme pixel de taille 10 * 10.

Nous allons dabord essayer:

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

Mais il renvoie une matrice 4D de dimensions {10,10,10,10}. Nous devrions donc la Flatten. Cette fois, nous voulons que le troisième argument ait une priorité plus élevée. du premier, donc un réglage mineur fonctionnerait:

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

Une comparaison:

illus2

Jespère que cela pourra vous aider!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *