Numpy: ENH : alternative à `random.shuffle`, avec un argument `axis`.

Créé le 11 oct. 2014  ·  35Commentaires  ·  Source: numpy/numpy

Ce serait bien d'avoir une alternative à numpy.random.shuffle qui accepte un argument axis , et qui mélange indépendamment les tranches unidimensionnelles. Voici une implémentation que j'appellerai disarrange . Cela fonctionne, mais ce serait bien d'avoir une implémentation C plus efficace.

def disarrange(a, axis=-1):
    """
    Shuffle `a` in-place along the given axis.

    Apply numpy.random.shuffle to the given axis of `a`.
    Each one-dimensional slice is shuffled independently.
    """
    b = a.swapaxes(axis, -1)
    # Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
    # so `a` is shuffled in place, too.
    shp = b.shape[:-1]
    for ndx in np.ndindex(shp):
        np.random.shuffle(b[ndx])
    return

Exemple:

In [156]: a = np.arange(20).reshape(4,5)

In [157]: a
Out[157]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [158]: disarrange(a, axis=-1)

In [159]: a
Out[159]: 
array([[ 2,  0,  4,  3,  1],
       [ 8,  6,  7,  9,  5],
       [11, 14, 13, 10, 12],
       [19, 18, 16, 17, 15]])

In [160]: a = np.arange(20).reshape(4,5)

In [161]: disarrange(a, axis=0)

In [162]: a
Out[162]: 
array([[ 5, 11,  7, 13, 14],
       [ 0,  6,  2,  3,  4],
       [10,  1, 17, 18, 19],
       [15, 16, 12,  8,  9]])

Cette demande a été motivée par cette question sur stackoverflow : http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

01 - Enhancement numpy.random

Commentaire le plus utile

des nouvelles à ce sujet? J'ai été surpris que cette fonctionnalité n'existe pas. Pour l'instant, j'utilise np.apply_along_axis avec np.random.permutation comme solution de contournement.

Tous les 35 commentaires

Je ne vois pas pourquoi cela devrait être une alternative -- pourquoi ne pas simplement ajouter un
argument d'axe à mélanger ? La valeur par défaut est Aucun, comme np.sum.

Le sam. 11 oct. 2014 à 21:36, Warren Weckesser [email protected]
a écrit:

Ce serait bien d'avoir une alternative à numpy.random.shuffle qui
accepte un argument d'axe, et cela mélange indépendamment le
tranches unidimensionnelles. Voici une implémentation que j'appellerai disarrange.
Cela fonctionne, mais ce serait bien d'avoir une implémentation C plus efficace.

def disarrange(a, axe=-1) :
"""
Mélangez a sur place le long de l'axe donné.

Apply numpy.random.shuffle to the given axis of `a`.
Each one-dimensional slice is shuffled independently.
"""
b = a.swapaxes(axis, -1)
# Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
# so `a` is shuffled in place, too.
shp = b.shape[:-1]
for ndx in np.ndindex(shp):
    np.random.shuffle(b[ndx])
return

Exemple:

Dans [156] : a = np.arange(20).reshape(4,5)

Dans [157] : un
Sortie[157] :
tableau([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])

Dans [158] : disarrange(a, axe=-1)

Dans [159] : un
Sortie[159] :
tableau([[ 2, 0, 4, 3, 1],
[ 8, 6, 7, 9, 5],
[11, 14, 13, 10, 12],
[19, 18, 16, 17, 15]])

Dans [160] : a = np.arange(20).reshape(4,5)

Dans [161] : disarrange(a, axe=0)

Dans [162] : un
Sortie[162] :
tableau([[ 5, 11, 7, 13, 14],
[ 0, 6, 2, 3, 4],
[10, 1, 17, 18, 19],
[15, 16, 12, 8, 9]])

Cette demande a été motivée par cette question sur stackoverflow :
http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/numpy/numpy/issues/5173.

Nathaniel J. Smith
Chercheur postdoctoral - Informatique - Université d'Edimbourg
http://vorpus.org

Le comportement actuel de shuffle n'est pas vraiment comme axis=None . Il traite son argument comme une séquence unidimensionnelle.

In [181]: a = np.arange(20).reshape(4,5)

In [182]: np.random.shuffle(a)

In [183]: a
Out[183]: 
array([[ 0,  1,  2,  3,  4],
       [15, 16, 17, 18, 19],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

Vous pouvez interpréter cela comme étant axis=0 , mais la fonctionnalité manquante est le brassage indépendant des tranches 1D.

Pour un tableau 2D, vous pouvez mélanger a.T pour émuler axis=1 , mais cela ne vous procurera pas un mélange indépendant :

In [184]: a = np.arange(20).reshape(4,5)

In [185]: np.random.shuffle(a.T)

In [186]: a
Out[186]: 
array([[ 4,  1,  0,  3,  2],
       [ 9,  6,  5,  8,  7],
       [14, 11, 10, 13, 12],
       [19, 16, 15, 18, 17]])

Dans disarrange , je m'attendrais axis=None ce que np.random.shuffle(a.flat) .

Ce serait bien si le brassage alternatif était implémenté en ajoutant des arguments appropriés à shuffle qui contrôlent son comportement, mais je n'ai pas de proposition pour cette API.

Peut-être que deux arguments pourraient être ajoutés à shuffle : axis et independent (ou quelque chose du genre). La nouvelle signature serait :

def shuffle(a, independent=False, axis=0)

Lorsque independent est False, il agit comme le shuffle actuel. Lorsque True, il agit comme disarrange .

Oh, ugh, j'ai juste supposé que c'était plus cohérent avec l'analogue
fonctions comme sort :-(. Ce serait mieux si ce genre de
shuffling-of-slices a été écrit comme idx = arange(...); shuffle(idx);
multi_dim_array[idx, ...] ; mais personne ne m'a demandé :-)

Je suis +1 sur une version de shuffle qui a des conventions d'appel qui correspondent
np.sort, bien qu'en règle générale, nous devrions vérifier avec la liste. Ils pourraient avoir
suggestions sur des questions cruciales comme le meilleur nom aussi :-)

(Peut-être "scrambler" ?)

Le sam. 11 oct. 2014 à 22:31, Warren Weckesser < [email protected]

a écrit:

Le comportement actuel de shuffle n'est pas vraiment comme axis=None. il traite
son argument comme une séquence unidimensionnelle.

Dans [181] : a = np.arange(20).reshape(4,5)

Dans [182] : np.random.shuffle(a)

Dans [183] : un
Sortie[183] :
tableau([[ 0, 1, 2, 3, 4],
[15, 16, 17, 18, 19],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])

Vous pouvez interpréter cela comme étant axe=0, mais la caractéristique manquante est le
brassage indépendant des tranches 1-D.

Pour un tableau 2D, vous pouvez mélanger aT pour émuler axis=1, mais cela ne le fera pas
obtenez-vous un brassage indépendant :

Dans [184] : a = np.arange(20).reshape(4,5)

Dans [185] : np.random.shuffle(aT)

Dans [186] : un
Sortie[186] :
tableau([[ 4, 1, 0, 3, 2],
[ 9, 6, 5, 8, 7],
[14, 11, 10, 13, 12],
[19, 16, 15, 18, 17]])

En cas de désordre, je m'attendrais à ce que axis=None agisse comme
np.random.shuffle(a.flat).

Ce serait bien si le brassage alternatif était implémenté en ajoutant
arguments appropriés pour mélanger qui contrôlent son comportement, mais je ne
avoir une proposition pour cette API.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment-58765220 .

Nathaniel J. Smith
Chercheur postdoctoral - Informatique - Université d'Edimbourg
http://vorpus.org

Ah, décrire le comportement souhaité comme un analogue de sort est une bonne idée.

Oh, ugh, j'ai juste supposé que c'était plus cohérent avec des fonctions analogues comme le tri

J'ai également été surpris et, sur la base des commentaires sur la question de stackoverflow, au moins deux autres utilisateurs expérimentés de numpy ont été surpris. Je vais lancer une discussion sur la liste de diffusion.

Je suppose que si l'utilisateur moyen se trompe actuellement, cela en vaut la peine
mentionnant l'autre option -- nous _pourrions_ ajouter un argument pour choisir entre
les deux comportements, qui commencent par défaut au comportement actuel,
et à un moment donné, changez la valeur par défaut après beaucoup de FutureWarning et de cris
pour avertir les gens. Mais c'est une transition moche à faire...

Le sam. 11 oct. 2014 à 23h00, Warren Weckesser < [email protected]

a écrit:

Oh, ugh, j'ai juste supposé que c'était plus cohérent avec l'analogue
des fonctions comme le tri

J'ai été surpris aussi, et sur la base des commentaires sur le stackoverflow
question, au moins deux autres utilisateurs expérimentés de numpy ont été surpris. je vais
lancer une discussion sur la liste de diffusion.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment -58766099.

Nathaniel J. Smith
Chercheur postdoctoral - Informatique - Université d'Edimbourg
http://vorpus.org

Ils pourraient également avoir des suggestions sur des questions cruciales comme le meilleur nom.

Nous avons besoin d'une fonction nommée Sue.

Je voulais juste donner +1 à cette fonctionnalité, car je m'attendais aussi à ce qu'elle existe, de manière analogue à sort(axis=N). Y a-t-il eu une décision prise sur la liste de diffusion?

Le fil de la liste de diffusion est ici :
http://thread.gmane.org/gmane.comp.python.numeric.general/59014

Ce serait vraiment utile !

J'apprécierais aussi ça !

Selon https://stackoverflow.com/a/35647011/3401634 , pour les tableaux multidimensionnels X

np.random.shuffle(X)

est le même que

np.take(X, np.random.permutation(X.shape[0]), axis=0, out=X)

Alors pourquoi ne pas implémenter

np.random.shuffle(X, axis=axis)

comme

np.take(X, np.random.permutation(X.shape[axis]), axis=axis, out=X)

avec la valeur par défaut axis=0 ?

des nouvelles à ce sujet? J'ai été surpris que cette fonctionnalité n'existe pas. Pour l'instant, j'utilise np.apply_along_axis avec np.random.permutation comme solution de contournement.

Cela peut-il être fermé maintenant à cause de #13829 ?

(Notez qu'en travaillant sur les exemples ici, j'ai trouvé un bogue dans le nouveau code shuffle. Dans ce qui suit, j'utilise le correctif proposé dans https://github.com/numpy/numpy/pull/14662, qui a été fusionné.)

@wkschwartz , le changement dans #13829 est utile, mais ce n'est pas l'amélioration demandée ici. L'axe ajouté dans #13829 traite toujours le tableau comme une séquence 1D à mélanger. Le nouvel argument d'axe permet à l'utilisateur de spécifier quel axe est considéré comme l'axe 1-d, mais il ne fait pas de mélange indépendant au sein de l'axe.

Par example,

In [1]: import numpy as np                                                      

In [2]: rng = np.random.default_rng()                                           

In [3]: x = np.arange(20).reshape(2, 10)                                        

In [4]: x                                                                       
Out[4]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [5]: rng.shuffle(x, axis=1)                                                  

In [6]: x                                                                       
Out[6]: 
array([[ 5,  9,  6,  4,  7,  0,  3,  2,  1,  8],
       [15, 19, 16, 14, 17, 10, 13, 12, 11, 18]])

Vous pouvez voir que les lignes n'ont pas été mélangées indépendamment . Les colonnes ont été réorganisées, mais les valeurs dans chaque colonne sont les mêmes.

Le comportement demandé dans ce numéro est de mélanger indépendamment, comme dans le code disarrange j'ai donné ci-dessus :

In [10]: x = np.arange(20).reshape(2, 10)                                       

In [11]: x                                                                      
Out[11]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [12]: disarrange(x, axis=1)                                                  

In [13]: x                                                                      
Out[13]: 
array([[ 4,  3,  7,  8,  0,  6,  5,  2,  9,  1],
       [12, 15, 19, 17, 18, 14, 10, 13, 11, 16]])

Je voudrais faire flotter cela à nouveau, peut-être aussi pour la réunion du mercredi. Nous venons d'ajouter des capacités dimensionnelles supérieures à choice et permutation et en 1.18 même l'argument d'axe (il est donc tout nouveau).

Tous ces éléments utilisent la logique de lecture aléatoire actuelle qui est shuffle the subarrays along this axis , au lieu de shuffle along (individual) axis qui, je pense, est sans doute ce qui devrait se produire. C'est-à-dire qu'il mélange "sur" au lieu de "le long" ou dans l'axe donné.

Mais, dans presque toutes les occasions, axis signifie le long de l' axe dans NumPy, avec, espérons-le, très peu d'exceptions, telles que apply_over_axes qui a le "plus" dans le nom. Je vais donc être si audacieux et prétendre que même renommer l'argument en over_axis=0 serait mieux pour éviter toute confusion ! Surtout pour les nombres aléatoires où un mélange incorrect peut être très difficile à remarquer.

Comme indiqué dans la référence croisée github ci-dessus, j'ai un PR de travail en cours sur https://github.com/numpy/numpy/pull/15121. J'ai reçu de bons commentaires après avoir soumis le PR, mais je n'ai pas pris le temps d'aborder tous les problèmes qui ont été soulevés.

@WarrenWeckesser qui est cool aussi , plus ce que je suis personnellement préoccupé par est que nous avons élargi le plus sens dans la nouvelle API et récemment à ce sujet .
Et je me demande si nous ne devrions pas retirer cela partiellement, par exemple en renommant au moins l'argument axis . Ou même se débarrasser complètement du comportement multidimensionnel pour le moment...

Je suis probablement en train de réagir de manière excessive en ce moment, car je suis un peu ennuyé d'avoir raté cela ou de ne pas l'avoir pensé jusqu'au bout avant... Mais je pense honnêtement que la logique actuelle est très dangereuse. Il est facile de rater qu'il ne fournit pas prévu le long du sens. Et ce n'est pas le sens que np.sort utilise.

@seberg , merci d'avoir axis . Je ne sais pas si nous pouvons, à ce stade, annuler totalement l'interprétation "le long" existante de axis pour shuffle et permutation , mais je pense que beaucoup de gens serait heureux s'il s'avère que nous pouvons. :)

À la fin de la discussion sur la liste de diffusion il y a plusieurs années, j'ai fini par penser que la solution consistait à ne pas modifier les API de shuffle et permutation , mais plutôt à introduire deux nouvelles méthodes aléatoires le long de l'axe au lieu de dessus. Une méthode fonctionnerait sur place, et l'autre renverrait une copie. Ma préférence à l'époque était pour les noms permute et permuted , mais il y avait quelques objections à ces noms. Dans le PR de décembre dernier, je les ai appelés randomly_permute et randomly_permuted , mais ces noms doivent être considérés comme des espaces réservés. Avant d'essayer de décider de ces noms, nous devons décider si l'ajout de deux nouvelles fonctions est la bonne approche. À partir de maintenant, par souci de concision, je ferai référence aux nouvelles méthodes proposées par permute et permuted .

Avec les nouvelles fonctions, nous aurions les méthodes Generator associées suivantes :

meaning    operate     return
of axis    in-place     copy
-------    --------  -----------
"over"     shuffle   permutation
"along"    permute   permuted

(Les méthodes qui opèrent "sur" l'axe, shuffle et permutation , existent déjà.)

Au lieu de deux nouvelles méthodes, il a été suggéré que nous n'en avons qu'une, avec un paramètre qui contrôle le comportement sur place par rapport à la copie. Deux suggestions ont été émises pour cela :

(a) Ajoutez un paramètre out . Pour travailler sur place, transmettez le tableau d'entrée sous la forme out . Si out n'est pas fourni, retournez une copie mélangée.
(b) Ajoutez un indicateur booléen tel que copy ou inplace , qui spécifie le comportement souhaité.

La principale alternative à la création de nouvelles méthodes consiste à ajouter un nouveau paramètre aux méthodes existantes qui modifie la façon dont axis est interprété. Avant de les énumérer, je vais réitérer un commentaire que Robert Kern a fait dans le fil de discussion de la liste de diffusion sur la façon dont l'argument supplémentaire est susceptible d'être utilisé dans la pratique (se référant ici au paramètre independent indiqué ci-dessous) :

Cela me semble une parfaitement bonne raison d'avoir deux méthodes au lieu de
un. Je ne peux pas imaginer quand je n'utiliserais pas un vrai ou un faux littéral
pour cela, il devrait donc s'agir de deux méthodes différentes.

( Digression éditoriale : Inévitablement dans une discussion comme celle-ci, la question de la croissance de l'espace de noms (dans ce cas, l'espace Generator noms

Cela dit, voici deux ajouts à la signature existante de shuffle qui ont été suggérés.

(1) shuffle(x, axis=0, independent=False) : Le drapeau booléen independent détermine comment axis est interprété : False -> "over", True -> "lelong". (Il y a probablement de meilleurs noms que independent .)
(2) shuffle(x, axis=0, iaxis=???) : Un deuxième argument, iaxis , donne l'axe du comportement "le long". (La façon dont cela interagit avec axis besoin d'une spécification claire. Vraisemblablement, donner une valeur pour iaxis fait que axis est ignoré.)

Je pense avoir couvert toutes les différentes idées d'API qui ont surgi. Si quelqu'un en connaît d'autres, faites-le nous savoir.

Je suis heureux d'augmenter l'API ici. Je ne suis pas sûr qu'il y ait beaucoup de raisons d'être contre :

  • Nous pouvons probablement convenir que c'est un outil utile
  • Il n'y a pas de bon moyen d'y parvenir avec les fonctionnalités existantes
  • utiliser un kwarg pour un changement de comportement total ne semble pas un modèle normal, je pense que Rober Kern avait tout à fait raison.

Je suppose que ce qui se passe ici est que shuffle et permutation (et peut-être choice ) peuvent être comparés à une opération d'indexation (c'est- take dire axis . Et la raison pour laquelle cela me semble un peu étrange, c'est probablement l'inconvénient de cette définition qu'elle ne peut jamais généraliser à ND contrairement aux fonctions typiques prenant en charge les tableaux (même l'indexation elle-même le fait si vous utilisez arr[..., index] . C'est tout généraliser à des piles de tableaux et faire la même opération que précédemment pour chaque individu).
Notez que take_along_axis fournit le sens "long" généralisable de ND pour take à ND correctement (même si cela semble compliqué). apply_along_axis et apply_over_axis sont d'où j'ai obtenu le "over", bien que je ne sois pas sûr que "over" soit le bon mot...

Je trouve que permutation (qui n'est pas facilement modifiable mais devrait être shuffled ) est la vraie valeur aberrante ici. C'était shuffle - shuffled , permute - permuted alors je pense que les choses commencent à sembler assez claires et raisonnables. Quelqu'un est-il prêt à ajouter shuffled et à lancer une dépréciation sur permutation ? permutation n'est pas non plus très cohérent dans son comportement avec itertools.permutations , FWIW.

Je pense que permutation , permute , permuted est un triplet déroutant de noms à consonance similaire avec des comportements différents. Il serait bon (peut-être sur le long terme) d'éviter cela.

Bien qu'il semble simple d'étendre l'API existante, je pense que le point de

Je suppose que pour sur place ou pas sur place, nous avons l'orthographe alternative out= dans NumPy. Mais comme le shuffle est en place, ce n'est pas une solution et le shuffle est agréable. Cela pourrait être pour permuted (c'est- permuted(arr, out=arr) dire que permute(arr) , sauf que – contrairement au shuffle – il sera converti en ndarray ).
Dans tous les cas, j'aime le plan de dépréciation de permutation en faveur de shuffled pour nettoyer le nouvel espace de noms !

Je reviens sur ce problème (et le PR associé sur https://github.com/numpy/numpy/pull/15121).

À l'époque où j'ai créé le problème d'origine et essayé de décrire le problème avec l'API shuffle , il a été souligné qu'une façon d'expliquer le problème est que la plupart des gens s'attendent à l'argument axis de shuffle pour agir de la même manière que l'argument axis de sort . L'analogie avec sort est assez bonne, il peut donc être utile d'examiner également comment nous gérons le problème de l'opération sur place par rapport à la copie pour le tri. La fonction numpy.sort() accepte un argument de type tableau et renvoie une copie triée. Pour le tri sur place, on utilise la méthode ndarray sort() . Comme il s'agit d'une méthode sur un ndarray existant, l'opération sur place est claire. Dans gh-15121, l'argument de la fonction sur place qui permute aléatoirement son argument doit être un ndarray, et non un tableau arbitraire. Sinon, la fonction devra faire toute la découverte de forme que fait np.array , et également rejeter les entrées qui s'avèrent immuables (par exemple, nous ne pouvons pas faire un mélange sur place de [(1, 2, 3, 4), (5, 6, 7, 8)] ).

Ce serait formidable si nous pouvions vraiment répliquer l'API sort , avec une fonction qui renvoie une copie mélangée, et une méthode ndarray qui mélange sur place, mais je ne pense pas ajouter une telle une méthode de la classe ndarray a toutes les chances d'être acceptée.

et une ndarray _method_ qui mélange sur place, mais je ne pense pas que l'ajout d'une telle méthode à la classe ndarray ait la moindre chance d'être accepté.

Sans un générateur singleton, je pense que cela serait impossible à réaliser.

@bashtage a écrit

Je trouve que permutation (qui n'est pas facilement modifiable mais devrait être shuffled ) est la vraie valeur aberrante ici. [Si c'était] shuffle-shuffled , permute-permuted alors je pense que les choses commencent à sembler assez claires et raisonnables. Quelqu'un est-il prêt à ajouter shuffled et à lancer une dépréciation sur permutation ?

C'est ce vers quoi la discussion de la liste de diffusion (en quelque sorte) a convergé en 2014. Voici un lien vers la suggestion de Nathaniel : https://mail.python.org/pipermail/numpy-discussion/2014-October/071364.html

Son scramble[d] est ce que j'ai appelé randomly_permute[d] dans https://github.com/numpy/numpy/pull/15121.

Si nous ajoutons shuffled en remplacement de permutation , et appelons les nouvelles méthodes qui opèrent le long d' un axe permute[d] , le tableau des fonctions associées est

meaning    operate
of axis    in-place   return copy
-------    ---------  -----------
"over"     shuffle    shuffled
"along"    permute    permuted

qui a une belle consistance. Dans cette version de l'API, aucune des méthodes n'a out paramètre

Plus dans https://github.com/numpy/numpy/pull/15121 , j'ai récemment ajouté une autre méthode, avec le nom disgracieux et évidemment temporaire permuted_with_out qui montre comment l'argument out pourrait être utilisé. Si nous utilisons un paramètre out et que nous nous en tenons aux noms des méthodes existantes shuffle et permutation , le tableau ressemble à

meaning    operate
of axis    in-place                           return copy
-------    ---------------------------------  --------------------
"over"     shuffle(x, axis)                   permutation(x, axis)
"along"    permuted_with_out(x, axis, out=x)  permuted_with_out(x, axis)

Mais si nous allons introduire un paramètre out , nous devons être cohérents et l'utiliser également dans permutation . Et nous pouvons toujours envisager de remplacer permutation par shuffled . Et puisque la nouvelle méthode shuffled a un paramètre out , qui permet une opération sur place, shuffle devient redondant et peut être déprécié avec permutation . Ensuite, en passant aux « jolis » noms de shuffled et permuted , la table est

    meaning    operate
    of axis    in-place                  return copy
    -------    ------------------------  -----------------
    "over"     shuffled(x, axis, out=x)  shuffled(x, axis)
    "along"    permuted(x, axis, out=x)  permuted(x, axis)

Notez que le paramètre out n'est pas uniquement destiné au fonctionnement sur place. Il permet de réutiliser un tableau de sortie, évitant potentiellement la création d'un tableau temporaire. C'est un avantage de cette API par rapport à l'API shuffle/shuffled/permute/permuted , mais je ne suis pas sûr de l'importance de cet avantage. L'inconvénient de cette API est la dépréciation de deux méthodes, shuffle et permutation . Ceux-ci peuvent être des dépréciations "douces" pendant un certain temps (c.

C'est mon résumé des deux principaux prétendants au changement. Nous avons la version shuffle/shuffled/permute/permuted , ou la version avec shuffled/permuted avec un paramètre out . Si, en 2014, quelqu'un s'était empressé de mettre en œuvre les changements qui ont été discutés, nous aurions probablement déjà la version shuffle/shuffled/permute/permuted . Mais la version utilisant out a quelques avantages (petits ? insignifiants ?) : deux noms au lieu de quatre, et out permet potentiellement à un utilisateur d'avoir moins de variables temporaires. Je serais heureux avec l'un ou l'autre.

Qu'en pensent les gens ?

Sur les trois scénarios que vous avez énumérés, dans l'ordre, je les classerais à 1, 3 et assez loin derrière 2. Les 2 permutations qui font des choses assez radicalement différentes semblent être une grande source de confusion. Ma préférence personnelle est d'éviter l'utilisation obligatoire de out pour accéder à une fonctionnalité ; Je pense toujours à out comme un choix de performance qui peut avoir du sens dans certains scénarios. Je n'aimerais pas vraiment apprendre aux étudiants à utiliser juste pour accéder à une fonctionnalité. Je suppose également que dans le cas où 3 x = shuffled(x, axis, out=x) seraient également return x plutôt que return None , de sorte que tant qu'il est en place, on pourrait se retrouver avec x apparaissant 3 fois.

Ma préférence personnelle est d'éviter l'utilisation obligatoire de out pour accéder à une fonctionnalité ; Je pense toujours à out comme un choix de performance qui peut avoir du sens dans certains scénarios.

Mais le brassage en place _est_ un choix de performance, n'est-ce pas ?

Mais le brassage en place _est_ un choix de performance, n'est-ce pas ?

In-place peut également être un choix de style de codage, lorsqu'il est disponible. Peut-être un sujet déroutant et peut-être sujet aux erreurs.

Mon point de vue personnel est que lorsque f(x, out=x) se sent toujours un peu magique car il est parfois utilisé comme un moyen très peu évident d'accomplir quelque chose rapidement. f(x, inplace=True), bien qu'il ne ressemble à rien d'autre, semble beaucoup plus clair (ressemble un peu à un ancien motif de pandas qui a pour la plupart été supprimé).

C'est vrai, mais c'est un choix de style de codage qui, dans NumPy, semble généralement orthographié en utilisant out=... (sauf si vous utilisez un opérateur sur place ou une méthode). Ou peut-être s'agit-il d'un choix de style de codage que NumPy n'essaie pas activement de rendre facile dans la plupart des cas actuellement...

J'avoue que c'est un peu magique et qu'un inplace= kwarg est peut-être moins magique, mais aussi sans réelle priorité ? Et je ne sais pas si la raison principale pour laquelle cela semble moins magique est que le remaniement sur place est au cœur de l'algorithme ici. Les détails algorithmiques ne devraient pas avoir beaucoup d'importance pour la plupart des étudiants et en fin de compte, l'utilisation de out= protège également environ une seule copie + la bande passante mémoire associée, et est comparable à ufuncs. (Assez juste, aussi pour les ufuncs out=input est peut-être un peu magique, mais sa magie commune et un modèle connu – pour les utilisateurs avancés.)

Bien que possible un peu fastidieux à écrire et un peu moins rapide à lire, np.shuffled(x, out=x) semble très clair quant à son comportement. La partie non évidente semble uniquement l'impact sur les performances, ce qui me semble être un problème réservé aux utilisateurs avancés.

Une question hypothétique pour ceux qui préconisent l'utilisation de out : si nous n'avions pas les fonctions existantes numpy.sort et ndarray.sort , et que nous ajoutions une fonction de tri maintenant, le API préférée soit numpy.sorted(a, axis=-1, kind=None, order=None, out=None) (sans avoir besoin d'implémenter la méthode ndarray.sort pour le tri sur place) ?

ndarray.sort est calqué sur list.sort , il s'agit donc probablement d'un choix d'API judicieux. Cela dit, j'aurais été favorable à ce que np.sort n'existe pas, et np.sorted(..., out=...) place.

Oui, je pense que np.sort devrait être nommé np.sorted (tout comme le sorted() python après tout). Étant donné que seule la méthode a le comportement en place, je ne vois pas beaucoup de problème cependant.

Je ne suis pas sûr du "sans avoir besoin d'implémenter la méthode ndarray.sort ". Je ne vois rien de mal à la méthode (ou à son comportement sur place). La question concernant la méthode est simplement de savoir si nous pensons qu'elle est suffisamment importante pour fournir une méthode abrégée pratique.
Je suppose qu'il n'y a rien de mal non plus à avoir une version de fonction sur place. La version non en place semble juste plus agréable pour les nouveaux utilisateurs et le modèle out= me semble assez courant pour que les utilisateurs avancés soient suffisamment bien servis.

Je ne suis pas sûr du "sans avoir besoin d'implémenter la méthode ndarray.sort". Je ne vois rien de mal à la méthode (ou à son comportement sur place).

Cela faisait partie de mon expérience de pensée API. Je ne voulais pas dire qu'il y a quelque chose qui ne va pas avec ce que nous avons maintenant. Je disais juste que, si nous partions de zéro - et j'ajouterai à mes hypothèses hypothétiques que nous ne sommes pas concernés par la correspondance de l'API Python pour les listes - alors l'API préférée pour le tri serait numpy.sorted(..., out=...) , et nous n'aurions besoin de rien d'autre.

Autre question, pas si hypothétique : si l'utilisation de out est l'option préférée ici, alors, pour la cohérence de l'API dans NumPy, devrions-nous éventuellement ajouter out à numpy.sort , numpy.partition , numpy.argsort , et bien, tout le reste qui ne l'a pas actuellement ?

Oui, à mon avis, ajouter un out= kwarg avec la même sémantique que pour ufuncs est un bon choix pour pratiquement toutes les fonctions de l'API NumPy. L'absence d'un argument out est généralement une amélioration en attente d'être apportée (bien que, dans la pratique, je suppose qu'il peut s'agir d'une petite amélioration et, dans de rares cas, ne vaut peut-être pas trop de complexité de code supplémentaire).

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

dcsaba89 picture dcsaba89  ·  3Commentaires

Kreol64 picture Kreol64  ·  3Commentaires

inducer picture inducer  ·  3Commentaires

astrofrog picture astrofrog  ·  4Commentaires

kevinzhai80 picture kevinzhai80  ·  4Commentaires