2017-03-25 1 views
0

J'ai un Dataset en xarray avec les dimensions suivantes:xarray: remodeler les données, dimension divisée

Dimensions:  (subject: 30, session: 5, time: 45000) 
Coordinates: 
    * subject  (subject) object '110' '112' '114' '117' ... 
    * session  (session) object 'week1' 'week2' 'week3' ... 
    * time   (time) timedelta64[ns] 00:00:00 00:00:00.040000 ... 

Je veux diviser chaque essai (sujet/combo de session) en segments de temps plus petits, par exemple en 3 segments de 15000 valeurs chacune, les dimensions résultantes peuvent se présenter comme suit:

(subject: 30, session: 5, segment: 3, time: 15000) 

Je l'ai cherché et essayé beaucoup de choses mais n'ont pas réussi, comment cela peut-il être fait? Une des choses que j'ai essayé, qui semble être proche, est de créer un nouveau MultiIndex et de le désempiler.

segment_data = np.repeat(range(3),len(ds.time)//3) 
segment = xr.Variable(dims='time',data=segment_data) 
newtime_data = np.tile(ds.time[:len(ds.time)//3],3) 
newtime = xr.Variable(dims='time',data=newtime_data) 
dsr = ds.assign_coords(segment=segment,newtime=newtime) 
dsr = dsr.set_index(segment='segment',newtime='newtime') 
dsr = dsr.stack(fragment=['segment','newtime']) 

Cependant cette dernière ligne prend une énorme quantité de mémoire et semble créer une dimension fragment: len(ds.time)**2, ce qui ne semble pas juste. Je ne suis pas sûr de ce que je devrais faire après cela (unstack('fragment')?).

edit: Quelques autres tentatives ont m'a amené ici:

x = np.repeat(range(3),15000) 
y = np.tile(ds.time[:len(ds.time)//3],3) 
dsr = (ds.assign_coords(segment=x,time2=y) 
     .set_index(fragment=['segment','time2']) 
     .unstack('fragment')) 

Ce qui donne ceci:

(subject: 30, segment: 3, session: 5, time: 45000, time2: 15000) 

Cela semble proche, mais il est pas tout à fait là-bas depuis chaque point time2 a maintenant 45000 valeurs alors qu'il devrait être une seule valeur:

dsr.isel(subject=0,segment=0,session=0,time2=0) 
# (time: 45000) 

modifier: J'ai finalement trouvé un façon de le faire, voir ma réponse. D'autres suggestions sont les bienvenues!

Répondre

1

Assurez-vous d'abord d'avoir les étiquettes pour les deux nouvelles dimensions. Dans ce cas comme suit:

x = range(3) # 3 segments 
y = ds.time[:len(ds.time)//3] # the first 1/3rd of the time labels 

Ensuite, créez un pandas multiindice de ces étiquettes *.

ind = pd.MultiIndex.from_product((x,y),names=('segment','new_time')) 

Enfin, remplacer l'indice time dans le dataset par ce nouvel indice, puis Désempiler ses niveaux pour créer les deux dimensions requises.

dsr = ds.assign(time=ind).unstack('time') 

Vous pouvez utiliser rename pour renommer la nouvelle dimension:

dsr = dsr.rename({'new_time':'time'}) 

dimensions résultantes:

(subject: 30, segment: 3, session: 5, time: 15000) 

La seule chose qui est hors est maintenant l'ordre des dimensions (idéalement segment et session doivent être permutés). Je pensais que transpose aiderait ici mais "although the order of dimensions on each array will change, the dataset dimensions themselves will remain in fixed (sorted) order." ** Donc je vais probablement vivre avec comme ça.

* Notez que vous ne pourrez pas utiliser le nom de la dimension que vous souhaitez diviser, nous avons donc 'new_time' ici. Une limitation inutile de assign?

** Une autre limitation que je ne peux pas expliquer.