2017-03-25 2 views
0

Ich habe einen Datensatz in xarray mit den folgenden Dimensionen:xarray: umformen Daten, Split Dimension

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 ... 

Ich mag jede Studie (Thema/session-Kombi) in kleinere Zeitabschnitte aufgeteilt, zum Beispiel in 3 Segmente von 15000 Werten jeweils die resultierenden Dimensionen können wie folgt aussehen:

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

ich habe gesucht und eine Menge Dinge ausprobiert, aber nicht gelungen, wie dies getan werden kann?

Eines der Dinge, die ich versucht habe, scheint nahe zu sein, einen neuen MultiIndex zu erstellen und ihn zu entstapeln.

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']) 

jedoch, dass letzte Zeile eine riesige Menge an Speicherplatz benötigt und scheint eine Dimension fragment: len(ds.time)**2, zu schaffen, die nicht richtig zu sein scheint. Ich bin mir auch nicht sicher, was ich danach machen müsste (unstack('fragment')?).

edit: Einige weitere Versuche haben mich hierher gebracht hat:

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')) 

Was ergibt dies:

aber es ist nicht ganz da, da jeder time2 Punkt jetzt 45000 Werte hat, während es in der Nähe
(subject: 30, segment: 3, session: 5, time: 45000, time2: 15000) 

Dies scheint sollte ein einzelner Wert sein:

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

edit: ich fand schließlich ein Weise es zu tun, sehe meine Antwort. Weitere Vorschläge willkommen!

Antwort

1

Zuerst sicherstellen, dass Sie die Etiketten für die zwei neuen Dimensionen haben. In diesem Fall wie folgt:

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

Dann ein pandas Multiindex von diesen Etiketten * erstellen.

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

Schließlich ersetzen den time Index im Datensatz von diesem neuen Index, und dann seine Niveaus entstapeln die beiden erforderlichen Abmessungen zu schaffen.

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

Sie wollen rename verwenden, um die neue Dimension umbenennen:

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

resultierenden Dimensionen:

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

Das einzige, was ist los jetzt ist die Reihenfolge der Dimensionen (im Idealfall und session sollten vertauscht werden). Ich dachte, transpose würde hier helfen, aber "although the order of dimensions on each array will change, the dataset dimensions themselves will remain in fixed (sorted) order." ** So werde ich wahrscheinlich damit leben.

* Hinweis: Sie können den Namen der Dimension, die Sie teilen möchten, nicht verwenden, daher haben wir 'new_time' hier. Eine unnötige Einschränkung von assign?

** Eine weitere Einschränkung, die ich nicht erklären kann.