Zip récursif

introduction

numpy.ndarray a un mécanisme appelé Fancy Index. C'est très pratique, mais la structure des index imbriqués est contraire à mon intuition et est difficile à utiliser. À titre d'exemple, citons le code suivant de l'article précédent.

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
a[[0, 1], [2, 2]] #=> [3, 6]

L'index pour extraire l'élément [0, 2] et l'élément [1, 2] est ([0, 1], [2, 2]), mais je suis ʻa [[ Je veux écrire 0, 2], [1, 2]] `(Eh bien, peut-être que c'est l'ordre imbriqué parce que je veux l'utiliser avec broadcast et slice, mais je veux l'écrire intuitivement). La fonction zip peut être utilisée pour une telle imbrication:

a[tuple(zip([0, 2], [1, 2]))] #=> array([3, 6])
#L'objet zip ne peut pas être indexé directement, il est donc tuplé.

Cependant, «numpy.ndarray» peut être un tenseur d'ordre supérieur, et un simple «zip» peut ne pas suffire, donc je veux une fonction qui remplace récursivement.

la mise en oeuvre

Puisqu'il est difficile de verbaliser les exigences, montrons d'abord le résultat des essais et des erreurs.

import collections

def deepzip(*x):
  if isinstance(x[0][0], collections.abc.Iterable):
    return zip(*map(lambda y: deepzip(*y), x))
  else:
    return zip(*x)
def invert_index(idx):
  return tuple(deepzip(*idx))

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
a[invert_index(([[0, 2], [1, 2]], [[1, 0], [1, 1]]))] #=> array([[3, 6], [4, 5]])

Puisqu'il est jugé selon s'il est ʻIterable, il est OK même si l'index n'est pas une liste mais un taple ou ndarray`. Bien que «x [0] [0]» soit dégoûtant, j'ai omis le traitement illégal tel que le fait que les profondeurs ne sont pas uniformes. L'entrée et la sortie (si elles sont cohérentes) peuvent être n'importe quel nombre d'étages ...

Veuillez me faire savoir s'il existe un modèle qui ne fonctionne pas ou si vous devez le faire.

Recommended Posts

Zip récursif
Zip *: français
zip en python
Fonction récursive
Mémo de représentation récursive
Géocodage du code postal