Utilisant les fonctions de tableau et de tableau dans Mathematica. Ce qui est mieux quand
j'ai été la plupart du temps un utilisateur de fonctions de Table dans mathematica. Cependant, j'ai remarqué que dans plusieurs exemples où j'ai utilisé tableau au lieu de Table pour exprimer le même résultat, il a couru beaucoup plus vite, surtout que la dimension de la table a augmenté.
Donc ma question est la suivante: Lorsque la vitesse d'exécution est la principale préoccupation, quand est-il plus approprié d'utiliser un tableau?
Qu'est-ce qui explique cette différence?
mon avis est que parce que les tableaux supposent une relation fonctionnelle entre les articles dans la liste, il les stocke plus efficacement, donc utilisent moins de mémoire, facilitant ainsi le stockage et le traitement ultérieur?
est-ce que c'est ce qui se passe?
5 réponses
Array
n'a aucun avantage de performance par rapport à Table
. Il y a des différences entre eux qui font que l'un est préféré à l'autre.
éditer il a été noté par plusieurs personnes que
Table
est plus lent sur les tableaux multidimensionnels. Tous ont utilisé la variable pour tenir la taille de la table. Table
possède les attributs HoldAll
et n'évalue que la limite de l'interation la plus externe. Parce que les itérateurs internes restent non évalué, l'élément du tableau ne se compile pas. En utilisant des nombres explicites ou With
avec le résultat de l'auto-compilation:
In[2]:= With[{b = 10^4, c = 10^4},
{Timing@(#[[1, 1]] &[ar = Array[(# + #2) &, {b, c}]]) ,
Timing@(#[[1, 1]] &[ta = Table[(i + j), {i, b}, {j, c}]])}
]
Out[2]= {{4.93, 2}, {4.742, 2}}
In[3]:= Attributes[Table]
Out[3]= {HoldAll, Protected}
Le
Array
vous permet de construire un tableau de valeurs de la fonction, tout autant que le Table
. Ils prennent des arguments différents. Array
prend une fonction:
In[34]:= Array[Function[{i, j}, a[i, j]], {3, 3}]
Out[34]= {{a[1, 1], a[1, 2], a[1, 3]}, {a[2, 1], a[2, 2],
a[2, 3]}, {a[3, 1], a[3, 2], a[3, 3]}}
tandis que le tableau prend une forme explicite:
In[35]:= Table[a[i, j], {i, 3}, {j, 3}]
Out[35]= {{a[1, 1], a[1, 2], a[1, 3]}, {a[2, 1], a[2, 2],
a[2, 3]}, {a[3, 1], a[3, 2], a[3, 3]}}
Array
peut ne passez que sur les tableaux réguliers, alors que Table
peut faire une itération arbitraire sur la liste:
In[36]:= Table[a[i, j], {i, {2, 3, 5, 7, 11}}, {j, {13, 17, 19}}]
Out[36]= {{a[2, 13], a[2, 17], a[2, 19]}, {a[3, 13], a[3, 17],
a[3, 19]}, {a[5, 13], a[5, 17], a[5, 19]}, {a[7, 13], a[7, 17],
a[7, 19]}, {a[11, 13], a[11, 17], a[11, 19]}}
parfois Array
peut être plus succinct. Comparer la table de multiplication:
In[37]:= Array[Times, {5, 5}]
Out[37]= {{1, 2, 3, 4, 5}, {2, 4, 6, 8, 10}, {3, 6, 9, 12, 15}, {4, 8,
12, 16, 20}, {5, 10, 15, 20, 25}}
versus
In[38]:= Table[i j, {i, 5}, {j, 5}]
Out[38]= {{1, 2, 3, 4, 5}, {2, 4, 6, 8, 10}, {3, 6, 9, 12, 15}, {4, 8,
12, 16, 20}, {5, 10, 15, 20, 25}}
Array
permet de construire une expression avec n'importe quelle tête, pas seulement la liste:
In[39]:= Array[a, {3, 3}, {1, 1}, h]
Out[39]= h[h[a[1, 1], a[1, 2], a[1, 3]], h[a[2, 1], a[2, 2], a[2, 3]],
h[a[3, 1], a[3, 2], a[3, 3]]]
par défaut la tête h
est choisie pour être List
résultant dans la création du réseau régulier. Le tableau n'a pas cette souplesse.
Michael Trott dans Programming (pp 707 - 710) abordent la question des différences entre Array
et Table
et fait valoir que comme Table
a l'attribut HoldAll
il calcule son argument pour chaque appel, tandis que Array
" dans la mesure du possible " calcule son argument seulement au début. Cela peut entraîner des différences de comportement et de vitesse.
Attributes[Table]
{HoldAll, Protégé}
Attributes[Array]
{protégé}
Michael Trott utilise les exemples suivants pour illustrer la différence de vitesse et de comportement. Je prends le mot à mot de son livre (disque). J'espère ne pas enfreindre les règles en le faisant.
Remove[a, i, j];
a = 0;
Table[a = a + 1; ToExpression[StringJoin["a" <> ToString[a]]][i, j],
{i, 3}, {j, 3}]
{{a1[1, 1], a2[1, 2], a3[1, 3]}, {a4[2, 1], a5[2, 2], a6[2, 3]}, {a7[3, 1], a8[3, 2], a9 [3, 3]}
a = 0;
Array[a = a + 1;
ToExpression[StringJoin["a" <> ToString[a]]], {3, 3}]
{{a1[1, 1], a1[1, 2], a1[1, 3]}, {a1[2, 1], a1[2, 2], a1 [2, 3]}, {a1[3, 1], a1[3, 2], a1[3, 3]}
(noter la différence de comportement)
pour illustrer l'effet de précomputer le premier argument, il utilise l'exemple suivant (encore une fois mot à mot, p 709).
o[a = 0;
Table[a = a + 1;
ToExpression[StringJoin["a" <> ToString[a]]][i, j],
{i, 3}, {j, 3}], {2000}] // Timing
Do[a = 0;
Array[a = a + 1; ToExpression[ StringJoin["a" <> ToString[a]]],
{3, 3}], {2000}] // Timing
{0.700173, Null}
{0.102587, Null}
(j'utilise mma7 sur Mac. Ma copie de programmation utilisations v5.1. Il pourrait bien y avoir une mise à jour)
ce n'est pas la seule différence entre Array
et Table
discuté dans programmation , bien sûr.
j'ai vu d'autres réponses, je serai intéressé de savoir ce que pensent les autres de ce point.
une des raisons pour lesquelles Array
peut être plus rapide est qu'il compile souvent mieux son premier argument.
In Mathematica 7:
In[1]:= SystemOptions[CompileOptions -> ArrayCompileLength]
Out[1]= {"CompileOptions" -> {"ArrayCompileLength" -> 250}}
et
In[2]:= SystemOptions[CompileOptions -> TableCompileLength]
Out[2]= {"CompileOptions" -> {"TableCompileLength" -> 250}}
pour que l'on puisse déduire que Array
et Table
devraient être compilés au même point.
mais essayons. Je vais faire usage de Timo timeAvg
fonction :
n = 15;
Array[Mod[#^2, 5]*(1 + #2) &, {n, n}] // timeAvg
Table[Mod[i^2, 5]*(1 + j), {i, n}, {j, n}] // timeAvg
(* Out = 0.00034496 *)
(* Out = 0.00030016 *)
n = 16;
Array[Mod[#^2, 5]*(1 + #2) &, {n, n}] // timeAvg
Table[Mod[i^2, 5]*(1 + j), {i, n}, {j, n}] // timeAvg
(* Out = 0.000060032 *)
(* Out = 0.0005008 *)
ce que nous voyons est que le tableau est capable de compiler Mod[#^2, 5]*(1 + #2) &
tandis que Table
n'est pas capable de compiler Mod[i^2, 5]*(1 + j)
et donc pour Array
devient plus rapide lorsque le CompileLength est atteint. Beaucoup de fonctions ne sont pas si favorables. Si vous changez simplement la multiplication en division dans la fonction, ce qui donne un résultat rationnel plutôt qu'entier, alors cette auto-compilation n'arrive pas, et Table
est plus rapide:
n = 15;
Array[Mod[#^2, 5]/(1 + #2) &, {n, n}] // timeAvg
Table[Mod[i^2, 5]/(1 + j), {i, n}, {j, n}] // timeAvg
(* Out = 0.000576 *)
(* Out = 0.00042496 *)
n = 16;
Array[Mod[#^2, 5]/(1 + #2) &, {n, n}] // timeAvg
Table[Mod[i^2, 5]/(1 + j), {i, n}, {j, n}] // timeAvg
(* Out = 0.0005744 *)
(* Out = 0.0004352 *)
mais que faire si nous pouvons faire de cette compilation? Si nous utilisons des nombres à virgule flottante, en commençant par 1.
, nous obtenons la sortie Real
, qui peut être compilée:
n = 15;
Array[Mod[#^2, 5]/(1 + #2) &, {n, n}, 1.] // timeAvg
Table[Mod[i^2, 5]/(1 + j), {i, 1., n}, {j, 1., n}] // timeAvg
(* Out = 0.0006256 *)
(* Out = 0.00047488 *)
n = 16;
Array[Mod[#^2, 5]/(1 + #2) &, {n, n}, 1.] // timeAvg
Table[Mod[i^2, 5]/(1 + j), {i, 1., n}, {j, 1., n}] // timeAvg
(* Out = 0.00010528 *)
(* Out = 0.00053472 *)
et encore une fois, Array
est plus rapide sur le plus grand tableau de dimensions.
votre déclaration:
cependant, j'ai remarqué que dans plusieurs exemples où J'ai utilisé Array au lieu de Table pour exprimer le même résultat, il a couru beaucoup plus vite, surtout que la dimension de la table a augmenté.
n'est généralement pas vrai pour les matrices unidimensionnelles . Regardez:
Cl;
Needs["PlotLegends`"]
$HistoryLength = 0;
a = 10^8;
arr = {}; tab = {};
Do[(
arr = {First@Timing@Array[# &, a], arr};
tab = {First@Timing@Table[i, {i, a}], tab};
), {10}];
ListLinePlot[{Flatten@arr, Flatten@tab},
AxesLabel -> {Style["Iteration", 14], Style["Time", 14]},
PlotLegend -> {Style["Array", 14], Style["Table", 14]},
PlotRange -> {{0, 10}, {1.6, 2}}]
sans donner quelques exemples concrets, il est difficile de répondre correctement à votre question.
comme Mathematica est un programme source fermé, les implémentations exactes de Table
et Array
ne peuvent pas être connues, à moins qu'elles ne soient expliquées par des personnes qui ont été impliquées dans le développement de Mathematica.
ces facteurs entravent votre capacité à raisonner quelle structure vous devez utiliser dans quelles circonstances. L'expérimentation sera votre meilleur bet, donc je vous suggère de garder des versions parallèles de vos programmes, l'Une utilisant Table
, l'autre utilisant Array
. De cette façon, vous pourrez voir lequel est le plus rapide.
Encore mieux, vous pouvez écrire une fonction wrapper qui dépend d'une variable globale. Cette fonction sera, selon la variable, utiliser Table
, ou Array
comme l'implémentation sous-jacente, de sorte que vous serez en mesure de passer rapidement d'une version à l'autre, sans faire beaucoup modifications à votre code.