2015-09-12 26 views
5

Un MRE viene incollato sottoR Trovare la frequenza e la durata un'onda è superiore ad un dato valore utilizzando condizionale in data.table

MRE

date<-c('2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-01','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02','2001-01-02') 
time<-c('07:00:00 GMT','08:00:00 GMT','09:00:00 GMT','10:00:00 GMT','11:00:00 GMT','12:00:00 GMT','13:00:00 GMT','14:00:00 GMT','15:00:00 GMT','16:00:00 GMT','17:00:00 GMT', '18:00:00 GMT','19:00:00 GMT','20:00:00 GMT','21:00:00 GMT','22:00:00 GMT','23:00:00 GMT','00:00:00 GMT', '01:00:00 GMT','02:00:00 GMT','03:00:00 GMT','04:00:00 GMT','05:00:00 GMT','06:00:00 GMT','07:00:00 GMT','08:00:00 GMT','09:00:00 GMT','10:00:00 GMT','11:00:00 GMT','12:00:00 GMT','13:00:00 GMT','14:00:00 GMT','15:00:00 GMT','16:00:00 GMT','17:00:00 GMT','18:00:00 GMT','19:00:00 GMT','20:00:00 GMT','21:00:00 GMT') 
el<-c(0.257,0.687,1.861,3.288, 4.821,6.172,7.048,7.258,6.799,5.654,4.463,3.443,2.704,2.708,3.328,4.23,5.244,5.985,6.317,6.074,5.234,3.981,2.662,1.615,0.88,0.746,1.405,2.527,3.928,5.283,6.517,7.179,7.252,6.625,5.454,4.214,3.144,2.491,2.357) 
Time<-as.POSIXct(paste(date, time),tz="GMT") 
wave<-data.table(Time, el) 
ggplot(wave, aes(wave$Time, wave$el)) + geom_point() + labs(x="time", y="elevation") + geom_hline(aes(yintercept=4)) 

Ho una serie temporale d'onda e voglio essere in grado di avere una funzione che è in grado di dirmi la frequenza e la durata media/mediana dell'onda al di sopra di una data elevazione. Nel mio esempio ho scelto 4.

Voglio interpolare il tempo in cui l'onda raggiunge 4 sui fronti di salita e discesa e trovare la differenza di tempo tra i due punti per ogni onda.

Posso farlo con un ciclo for, ma penso che dovrei essere in grado di farlo in data.table molto più velocemente. Ho 1mil + punti per diverse posizioni e non credo che un ciclo for sarebbe efficiente.

Per la crescente ondata voglio fare qualcosa di simile:

wave[,timeIs4:=ifelse(elev<3 & elev[+1]>4,TRUE,FALSE)] 

Ma invece di mettere TRUE nel mio calcolo interpolazione. Non so come accedere ai valori precedenti e successivi all'interno di una tabella di dati come in un ciclo for i + 1 o i-1.

output desiderato

aumento gamba voglio interpolare tra i punti 4 e 5; 15 e 16; 29 e 30.

Piedino pendente Voglio interpolare tra i punti 11 e 12; 21 e 22; 36 e 37

Esito approssimativo

Rising  Falling 
10:28:00 17:27:00 
21:45:00 3:59:00 
11:03:00 18:12:00 

Poi potranno sottrarre Alzandosi dalla caduta usando difftime() per determinare la quantità di tempo che il livello dell'acqua era sopra la data elevazione.

Questo mi darà la frequenza e la durata in cui l'acqua è al di sopra della quota indicata.

+1

controllo funzione 'shift' dalla versione data.table' 1.9.5', dovresti leggere anche su [MRE] (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible- esempio) – jangorecki

+1

Qual è il risultato esatto desiderato.Posso aiutarti a separare le onde ma non sono sicuro di come procedere ulteriormente –

risposta

6

Ecco una possibile soluzione utilizzando devel version from GH. Ne avrai bisogno sia per la funzione shift (come menzionato da @Jan), sia per il nuovo metodo dcast che accetta le espressioni. Inoltre, non hai minuti nel tuo MRE, quindi non sei sicuro di dove li hai ottenuti nel tuo output previsto.

Ad ogni modo, per cominciare, creeremo un indice (lo chiameremo Wave in modo da sapere da quale onda # proviene) che ci dirà se l'onda sta salendo o scendendo usando shift. Poi, ci sarà dcast su valori corrispondenti durante la rimozione del senza pari usando na.omit (È possibile riordinare i nomi delle colonne in seguito, se ti piace usare la funzione setcolorder)

library(data.table) ## V 1.9.5+ 
dt[elev <= 4 & shift(elev, type = "lead") > 4, Wave := "Rising"] 
dt[elev > 4 & shift(elev, type = "lead") <= 4, Wave := "Falling"] 
dcast(na.omit(dt), cumsum(Wave == "Rising") ~ Wave, value.var = "time") 
# Wave    Falling    Rising 
# 1: 1 2001-01-01 17:00:00 2001-01-01 10:00:00 
# 2: 2 2001-01-02 03:00:00 2001-01-01 21:00:00 
# 3: 3 2001-01-02 18:00:00 2001-01-02 11:00:00 
+0

Questo è fantastico, ho bisogno di guardare più a turni. Ho in programma di ottenere minuti interpolando l'onda del tempo raggiunge 4. Mi chiedo per un grande insieme di dati che ha alcuni dati mancanti possibili come si dovrebbe tenere conto per il controllo di qualità. Sembra che ci possano essere alcune gambe che mancano; come faccio a buttare via l'altra metà del set? Ho alcune idee, come usare un set pulito più piccolo conosciuto e ottenere l'intervallo di tempo e garantire che tutte le gambe in salita e in caduta rientrino in quell'intervallo (con un piccolo buffer extra). Questo sarebbe un approccio appropriato? –

3

Ecco un'altra idea possibile:

elev = 4  

#a helper function to calculate elapsed time 
ff = function(el1, el2, el, time1, time2) 
      time1 + ((el - el1)/(el2 - el1)) * (time2 - time1)  

dif = diff(findInterval(wave$el, c(-Inf, elev, Inf))) 
ris = which(dif == 1) #risings 
fal = which(dif == -1) #fallings 

ff(wave$el[ris], wave$el[ris + 1], elev, wave$Time[ris], wave$Time[ris + 1]) 
#[1] "2001-01-01 10:27:52 GMT" "2001-01-01 21:44:42 GMT" "2001-01-02 11:03:11 GMT" 
ff(wave$el[fal], wave$el[fal + 1], elev, wave$Time[fal], wave$Time[fal + 1]) 
#[1] "2001-01-01 17:27:14 GMT" "2001-01-02 03:59:05 GMT" "2001-01-02 18:12:00 GMT" 
+0

Grazie, ma ho dovuto dare la risposta a David, a causa dell'uso di data.table. –