Nous avons publié une extension qui vous permet de définir des données xarray comme une classe de données Python.

TL;DR

xarray est un package Python utilisé dans l'analyse de données comme NumPy et pandas comme outil de gestion de données avec des métadonnées (étiquettes d'axes, etc.) attachées à un tableau multidimensionnel, mais diverses données Comme je m'occupe de xarray (DataArray), je me sens de plus en plus comme suit.

--Je veux une fonction de génération de tableau qui spécifie les axes (dimensions) et le type (dtype) d'un tableau multidimensionnel.

Il existe de nombreuses façons d'y parvenir, mais les classes de données (dataclasses) qui sont apparues dans la bibliothèque standard de Python 3.7 posent-elles le même problème? J'ai remarqué que je l'ai résolu avec un style d'écriture simple. Par conséquent, nous avons publié un package "xarray-custom" pour créer une classe DataArray définie par l'utilisateur de la même manière qu'une classe de données, je vais donc l'introduire (vous pouvez l'installer avec pip).

from xarray_custom import ctype, dataarrayclass

@dataarrayclass(accessor='img')
class Image:
    """DataArray class to represent images."""

    dims = 'x', 'y'
    dtype = float
    x: ctype('x', int) = 0
    y: ctype('y', int) = 0

    def normalize(self):
        return self / self.max()

Ci-dessous, je vais expliquer comment ce code fonctionne, en abordant les classes de données de Python et DataArary.

Python's dataclass

Tout d'abord, la classe de données Python est une fonction (décorateur de classe) qui facilite la création de structures de données définies par l'utilisateur.

from dataclasses import dataclass

@dataclass
class Coordinates:
    x: float
    y: float

    @classmethod
    def origin(cls):
        return cls(0.0, 0.0)

    def norm(self):
        return (self.x ** 2 + self.y **2) ** 0.5

Si vous définissez une classe comme celle-ci,

coord = Coordinates(x=3, y=4)

Il crée une classe qui stocke des données comme (À l'origine, il est nécessaire d'implémenter diverses méthodes spéciales telles que __init __ ()). Je pense que les avantages suivants sont possibles à définir une classe de données de cette manière.

xarray's DataArray

Ensuite, regardons la structure de données de xarray. DataArray prend une structure de données composée d'un tableau multidimensionnel NumPy, d'axes (dimensions; un type de métadonnées) et de métadonnées (coordonnées). L'exemple suivant vise à représenter les données dans un DataArray d'une image monochromatique constituée de deux axes de xy.

from xarray import DataArray

image = DataArray(data=[[0, 1], [2, 3]], dims=('x', 'y'),
                  coords={'x': [0, 1], 'y': [0, 1]})
print(image)

# <xarray.DataArray (x: 2, y: 2)>
# array([[0., 1.],
#        [2., 3.]])
# Coordinates:
#   * x        (x) int64 0 1
#   * y        (y) int64 0 1

Puisque DataArray est une classe, une manière courante de définir un DataArray défini par l'utilisateur est de créer une nouvelle classe avec DataArray comme sous-classe. Cependant, si vous codez en dur la définition en __init __ () etc., il y a un problème qui ne peut pas être réutilisé. De plus, xarray et pandas ne recommandent pas activement de sous-classer en premier lieu, et il est préférable d'implémenter le traitement défini par l'utilisateur, etc. via un objet spécial appelé accesseur.

One standard solution to this problem is to subclass Dataset and/or DataArray to add domain specific functionality. However, inheritance is not very robust. It’s easy to inadvertently use internal APIs when subclassing, which means that your code may break when xarray upgrades. Furthermore, many builtin methods will only return native xarray objects. (Extending xarray - xarray 0.15.0 documentation)

xarray's dataarrayclass

C'est finalement le sujet principal. Afin de réaliser la requête mentionnée au début, compte tenu des circonstances de xarray (DataArray),

-Fournit un moyen de générer un tableau sans coder en dur la définition des (méta) données

J'ai réalisé que j'avais besoin de quelque chose. Par conséquent, dans xarray-custom, j'ai décidé de m'habituer à la classe de données Python et de l'implémenter en ** modifiant dynamiquement la classe DataArray définie par l'utilisateur avec un décorateur de classe (dataarrayclass) **. En utilisant xarray-custom, l'exemple d'image monochromatique ci-dessus peut être défini comme suit.

from xarray_custom import ctype, dataarrayclass

@dataarrayclass(accessor='img')
class Image:
    """DataArray class to represent images."""

    dims = 'x', 'y'
    dtype = float
    x: ctype('x', int) = 0
    y: ctype('y', int) = 0

    def normalize(self):
        return self / self.max()

En connaissant la classe de données, j'espère que vous pourriez comprendre ce que fait ce code sans explication. Les points ici sont les trois points suivants.

--Spécifiez l'axe des données (`` x ',' y') et tapez (float`) avec des variables de classe

Ici, ctype est une fonction pour générer un type spécial (classe) qui définit les métadonnées. Générons maintenant un tableau défini par l'utilisateur.

image = Image([[0, 1], [2, 3]], x=[0, 1], y=[0, 1])
print(image)

# <xarray.DataArray (x: 2, y: 2)>
# array([[0., 1.],
#        [2., 3.]])
# Coordinates:
#   * x        (x) int64 0 1
#   * y        (y) int64 0 1

Vous pouvez voir que les axes et les métadonnées sont prédéfinis, il est donc beaucoup plus simple à écrire que l'exemple DataArray ci-dessus. Elle diffère de la classe de données en ce que les informations de type sont en fait utilisées pour déterminer le type du tableau. Dans l'exemple ci-dessus, la liste d'entiers est tapée pour flotter dans le DataArray. Si la conversion de type (implicite) n'est pas possible, ValueError est renvoyé. Vous pouvez également ne spécifier aucun type (auquel cas, les objets de tout type seront acceptés).

Instance methods via an accessor

Selon la politique xarray, la méthode d'instance définie dans la classe (normalize () dans l'exemple ci-dessus) peut être exécutée via l'accesseur. L'exécution sans accesseur lèvera ʻAttribute Error`.

normalized = image.img.normalize()
print(normalized)

# <xarray.DataArray (x: 2, y: 2)>
# array([[0.        , 0.33333333],
#        [0.66666667, 1.        ]])
# Coordinates:
#   * x        (x) int64 0 1
#   * y        (y) int64 0 1

Special functions as class methods

En tant que génération de séquence spéciale, zeros () ・ ʻones () ・ ʻempty ()full (), qui est familier avec NumPy, est automatiquement ajouté comme méthode de classe. zeros_like () etc. sont définis dans la fonction de niveau supérieur de xarray, alors utilisons-le.

uniform = Image.ones((2, 3))
print(uniform)

# <xarray.DataArray (x: 2, y: 3)>
# array([[1., 1., 1.],
#        [1., 1., 1.]])
# Coordinates:
#   * x        (x) int64 0 0
#   * y        (y) int64 0 0 0

Misc

Jusqu'à présent, la classe dataarray ne sous-classe-t-elle pas également DataArray après tout? Certaines personnes ont peut-être pensé. Cependant, le DataArray résultant est en fait une véritable instance de DataArray. Inversement, dans l'exemple ci-dessus, ce n'est pas une instance ʻImage`.

print(type(image)) # xarray.core.dataarray.DataArray

C'est parce que la classe dataarray génère en interne __new __ () ʻau lieu de __ init __ (), et __new __ () `retourne un DataArray. Par conséquent, il convient de noter que les variables de classe, etc. ne sont pas accessibles comme une instance créée à partir d'une classe ordinaire.

J'ai l'impression que xarray a moins d'articles et est moins connu que NumPy et pandas, mais il est certainement utile pour les tâches traitant des tableaux multidimensionnels, alors j'aimerais l'utiliser de plus en plus. xarray-custom a peu de fonctions dans les premiers stades de développement, mais j'espère contribuer autant que possible à la communauté à travers le développement et les articles de ces extensions.

References

Recommended Posts

Nous avons publié une extension qui vous permet de définir des données xarray comme une classe de données Python.
Création d'un service qui vous permet de rechercher des données J-League
Notez que l'environnement Python de Pineapple peut être modifié avec pyenv
Nous avons publié un module Python qui génère un maillage régional pour le Japon
Introduction de "scikit-mobility", une bibliothèque qui vous permet d'analyser facilement les données de flux humain avec Python (Partie 1)
Créez un plugin qui vous permet de rechercher les onglets Sublime Text 3 en Python
Feuille de route d'apprentissage qui vous permet de développer et de publier des services à partir de zéro avec Python
Script Python qui peut vérifier l'état du serveur à partir du navigateur
Comment importer des fichiers où vous le souhaitez en Python
Un script python qui convertit les données Oracle Database en csv
[Road to Intermediate Python] Appelez une instance de classe comme une fonction avec __call__
Modèles Python qui ont été publiés dans le monde et ont été examinés plus tard
[Python] J'ai fait un décorateur qui ne semble pas avoir d'utilité.
[Python3] Code qui peut être utilisé lorsque vous souhaitez découper une image dans une taille spécifique
Nous avons publié LINE BOT, qui vous permet de rechercher des hôtels et des bars en fonction des informations de localisation.
[Python3] Code qui peut être utilisé lorsque vous souhaitez modifier l'extension d'une image à la fois
[Python] Comment rendre une classe itérable
J'ai essayé de créer une classe qui peut facilement sérialiser Json en Python
Qu'est-ce que vous aimez dans la conversion d'un tableau (liste) en chaîne?
Je n'ai pas eu besoin d'écrire décorateur en classe Merci contextmanager
Présentation du livre "Créer une IA rentable avec Python" qui vous permet d'apprendre l'apprentissage automatique dans le cours le plus court
Un mémo pour générer des variables dynamiques de classe à partir de données de dictionnaire (dict) qui n'ont que des données de type standard en Python3