import numpy as np
import scipy
import xarray as xr
import datetime
xarray est une bibliothèque qui complète Numpy pour en rendre son usage plus lisible.
Étiqueter les dimensions¶
Lorsque nous avons un tableau avec Numpy, nous devons nous souvenir à quoi correpondent les dimensions. Par exemple on peut avoir un tableau qui indique la température en différent endroit de la pièce à différents moments. Ainsi mes dimensions sont x
, y
et t
pour le temps.
Voici un tel tableau avec Numpy dans un pièce de 4x3 pour 2 moments différents :
temperature = 19 + 2 * np.random.rand(4,3,2)
temperature
array([[[20.56371728, 20.67268242], [19.49352738, 19.06130975], [19.86315104, 20.05260355]], [[19.22652893, 19.08068781], [20.46303709, 20.52071713], [20.17702706, 19.56179238]], [[20.0241261 , 20.90465717], [20.79127834, 20.78011232], [19.56782131, 19.00267673]], [[19.12877798, 19.64549374], [19.08113226, 20.93804337], [20.44299346, 19.67721727]]])
On a vu que pour connaitre la température moyenne dans la pièces, on indique l'axe sur lequel est fait la moyenne à savoir celui du temps donc 2:
temperature.mean(axis=2)
array([[20.61819985, 19.27741857, 19.95787729], [19.15360837, 20.49187711, 19.86940972], [20.46439164, 20.78569533, 19.28524902], [19.38713586, 20.00958782, 20.06010536]])
Regardons comment cela devient plus lisible avec xarray
.
Pour commencer on indique les noms des axes (ou dimensions). Ensuite on peut les utiliser à la place de numéro d'axes.
xtemp = xr.DataArray(temperature, dims=['x', 'y', 't'])
xtemp
<xarray.DataArray (x: 4, y: 3, t: 2)> array([[[20.56371728, 20.67268242], [19.49352738, 19.06130975], [19.86315104, 20.05260355]], [[19.22652893, 19.08068781], [20.46303709, 20.52071713], [20.17702706, 19.56179238]], [[20.0241261 , 20.90465717], [20.79127834, 20.78011232], [19.56782131, 19.00267673]], [[19.12877798, 19.64549374], [19.08113226, 20.93804337], [20.44299346, 19.67721727]]]) Dimensions without coordinates: x, y, t
xtemp.mean('t')
<xarray.DataArray (x: 4, y: 3)> array([[20.61819985, 19.27741857, 19.95787729], [19.15360837, 20.49187711, 19.86940972], [20.46439164, 20.78569533, 19.28524902], [19.38713586, 20.00958782, 20.06010536]]) Dimensions without coordinates: x, y
xtemp.max(dim=['x','y']) # to get space maximum for each time
<xarray.DataArray (t: 2)> array([20.79127834, 20.93804337]) Dimensions without coordinates: t
Réordonner¶
On peut réodonner comme on l'a vu au cours précédent mais en utilisant les noms des dimensions.
xtemp.transpose('y','x','t') # same than temperature.transpose((1,0,2))
<xarray.DataArray (y: 3, x: 4, t: 2)> array([[[20.56371728, 20.67268242], [19.22652893, 19.08068781], [20.0241261 , 20.90465717], [19.12877798, 19.64549374]], [[19.49352738, 19.06130975], [20.46303709, 20.52071713], [20.79127834, 20.78011232], [19.08113226, 20.93804337]], [[19.86315104, 20.05260355], [20.17702706, 19.56179238], [19.56782131, 19.00267673], [20.44299346, 19.67721727]]]) Dimensions without coordinates: y, x, t
Concaténer¶
On indique plus clairement suivant quelle direction. On notera qu'il ne vérifie par la pertinence d'avoir plusieurs fois la même date.
xr.concat([xtemp, xtemp], dim='t')
<xarray.DataArray (x: 4, y: 3, t: 4)> array([[[20.56371728, 20.67268242, 20.56371728, 20.67268242], [19.49352738, 19.06130975, 19.49352738, 19.06130975], [19.86315104, 20.05260355, 19.86315104, 20.05260355]], [[19.22652893, 19.08068781, 19.22652893, 19.08068781], [20.46303709, 20.52071713, 20.46303709, 20.52071713], [20.17702706, 19.56179238, 20.17702706, 19.56179238]], [[20.0241261 , 20.90465717, 20.0241261 , 20.90465717], [20.79127834, 20.78011232, 20.79127834, 20.78011232], [19.56782131, 19.00267673, 19.56782131, 19.00267673]], [[19.12877798, 19.64549374, 19.12877798, 19.64549374], [19.08113226, 20.93804337, 19.08113226, 20.93804337], [20.44299346, 19.67721727, 20.44299346, 19.67721727]]]) Dimensions without coordinates: x, y, t
Empiler des DataArray donne un DataSet¶
Ajouter une nouvelle dimension lors de la concaténation (l'équivalent de stack
sous Numpy) revient à générer
un nouveau type de données de xarray à savoir les DataSet
.
Un DataSet
est un ensemble de DataArray
qui partagent les mêmes dimensions. Pour qu'il s'y reconnaisse, chaque DataArray
doit être nomé.
Note: le type des DataArray
d'un DataSet
n'a pas besoin d'être le même. Par contre les dimensions doivent être les mêmes.
density = xr.DataArray(np.ones((2,3)), dims=['x','y'], name='Density')
quality = xr.DataArray(np.arange(6).reshape(2,3), dims=['x', 'y'], name='Quality')
xset = xr.merge([density, quality])
xset
<xarray.Dataset> Dimensions: (x: 2, y: 3) Dimensions without coordinates: x, y Data variables: Density (x, y) float64 1.0 1.0 1.0 1.0 1.0 1.0 Quality (x, y) int64 0 1 2 3 4 5
xset["Quality"]
<xarray.DataArray 'Quality' (x: 2, y: 3)> array([[0, 1, 2], [3, 4, 5]]) Dimensions without coordinates: x, y
Ajout de coordonnées¶
On voit que lors de l'affichage des xarray
il m'indique que des dimensions n'ont pas de coordonnées. C'est juste, xtemp
a 4 valeurs suivant x mais on ne sait pas à quelle positions elles correspondent, idem pour y et le temps.
Aussi ajoutons ces coordonnées pour avoir quelque chose de signicatif et donc pouvoir faire des calculs qui impliqueront ces coordonnées.
Imaginons que les 12 points dans ma pièce correpondent à 12 capteurs de température que j'ai placé suivant une grille mais que cette grille n'est pas régulière. Voici la position (en mètre) des capteurs indiquées lors de la création du xarray
à l'aide d'un dictionnaire.
xtemp = xr.DataArray(temperature,
dims=['x', 'y', 't'],
coords= {'x':[0.5, 1.1, 3, 4.1],
'y':np.linspace(0.5,3.5, 3),
't':[datetime.datetime(2020,1,5), datetime.datetime(2020,1,6)]
}
)
xtemp
<xarray.DataArray (x: 4, y: 3, t: 2)> array([[[20.56371728, 20.67268242], [19.49352738, 19.06130975], [19.86315104, 20.05260355]], [[19.22652893, 19.08068781], [20.46303709, 20.52071713], [20.17702706, 19.56179238]], [[20.0241261 , 20.90465717], [20.79127834, 20.78011232], [19.56782131, 19.00267673]], [[19.12877798, 19.64549374], [19.08113226, 20.93804337], [20.44299346, 19.67721727]]]) Coordinates: * x (x) float64 0.5 1.1 3.0 4.1 * y (y) float64 0.5 2.0 3.5 * t (t) datetime64[ns] 2020-01-05 2020-01-06
xtemp.sel(x=1.1, y=2)
<xarray.DataArray (t: 2)> array([20.46303709, 20.52071713]) Coordinates: x float64 1.1 y float64 2.0 * t (t) datetime64[ns] 2020-01-05 2020-01-06
isel
selectionne en fonction de l'indice et non plus des valeurs. xtemp.isel(x=1, y=1)
donne
le même résultat tout comme xtemp[1,1]
si on revient à la facon Numpy.
Notons qu'en sélectionnant les 2 coordonnées x
et y
, il n'y a plus que le temps qui varie, ce qu'indique l'étoile *
dans les coordonnées.
Interpolation suivant les coordonnées¶
Maintenant que les axes ont des valeurs (les coordonnées), il est possible de les utiliser pour effectuer des calculs. Ainsi on peut estimer la température en tout point de la pièce par interpolation avec interp
:
xtemp.interp(x=1.5, y=1.5)
<xarray.DataArray (t: 2)> array([20.15290838, 20.20511155]) Coordinates: * t (t) datetime64[ns] 2020-01-05 2020-01-06 x float64 1.5 y float64 1.5
L'interpolation peut se faire sur un ensemble de points de ma pièce :
xtemp.interp(x=np.arange(3), y=[1.5, 2.5])
<xarray.DataArray (x: 3, y: 2, t: 2)> array([[[ nan, nan], [ nan, nan]], [[20.01743264, 19.96699513], [20.24253956, 20.06618646]], [[20.28045923, 20.41061679], [20.37516516, 20.1947084 ]]]) Coordinates: * t (t) datetime64[ns] 2020-01-05 2020-01-06 * x (x) int64 0 1 2 * y (y) float64 1.5 2.5
On note les Not a Number (nan) qui apparaissent lorsqu'on n'a pas l'information nécessaire pour interpoler.
On peut aussi demander d'interpoler le long d'un chemin avec une courbe paramétrique suivant s
par exemple.
# 4 points along a half-circle centered in (2,2)
cx = 2 + xr.DataArray([np.cos(s) for s in np.linspace(0,np.pi,4)], dims='s')
cy = 2 + xr.DataArray([np.sin(s) for s in np.linspace(0,np.pi,4)], dims='s')
xtemp.interp(x=cx, y=cy)
<xarray.DataArray (s: 4, t: 2)> array([[20.79127834, 20.78011232], [20.14096616, 19.81000737], [20.25306828, 19.9222033 ], [20.30145214, 20.27748257]]) Coordinates: * t (t) datetime64[ns] 2020-01-05 2020-01-06 x (s) float64 3.0 2.5 1.5 1.0 y (s) float64 2.0 2.866 2.866 2.0 Dimensions without coordinates: s
Il est ainsi possible de faire des interpolations pour déformer l'espace ce qui permet de corriger des déformations comme le montre le dernier exemple de cette page.
Plus¶
Xarray offre plus de méthodes pour manipuler ses tableaux dans la veine de celles de Pandas. Aussi on reviendra sur Xarray lorsqu'on aura vu Pandas.
{{ PreviousNext("np03 Manipulations.ipynb", "np05 Notation Einstein.ipynb")}}