2016-03-17 7 views
5

Ich habe dieses Dataset, das ich transformieren möchte, um die "von" - und "bis" -Positionen innerhalb einer bestimmten Gruppierung von Datenpunkten zu erhalten, die einen Test bestehen.erste und letzte Positionen in einem Dataset extrahieren

Hier ist, wie die Daten aussehen:

pos <- seq(from = 10, to = 100, by = 10) 
test <- c(1, 1, 1, 0, 0, 0, 1, 1, 1, 0) 
df <- data.frame(pos, test) 

So können Sie sehen, dass die Positionen 10, 20 und 30 sowie 70, 80 und 90 bestehen den Test (b/c Test = 1) aber der Rest der Punkte nicht. Die Antwort, die ich bin auf der Suche nach würde ein Datenrahmen, die unter so etwas wie der „Antwort“ Datenrahmen im Code aussieht:

peaknum <- c(1, 2) 
from <- c(10, 70) 
to <- c(30, 90) 
answer <- data.frame(peaknum, from, to) 

Irgendwelche Vorschläge, wie ich den Datensatz zu verwandeln? Ich bin ratlos.

Danke, Steve

Antwort

5

Wir können data.table verwenden. Verwenden Sie die rleid-Funktion zum Erstellen der Lauflängengruppen-IDs ('peaknum') basierend auf den benachbarten Werten, die denselben 'test' haben. Unter Verwendung von 'peaknum' als Gruppierungsvariable erhalten wir 'min' und 'max' von 'pos', während 'i' als 'test == 1' spezifiziert wird, um die Zeilen zu unterteilen. Bei Bedarf können die 'peaknum'-Werte in die Sequenz (' seq_len (.N) `) geändert werden.

library(data.table) 
setDT(df)[, peaknum:= rleid(test)][test==1, 
    list(from=min(pos), to=max(pos)) ,peaknum][, peaknum:= seq_len(.N)] 
# peaknum from to 
#1:  1 10 30 
#2:  2 70 90 
+2

Das hat absolut wunderbar funktioniert. Es macht mich denken, dass ich data.table irgendwann lernen sollte :-) – Steven

+0

@Steven, wissen Sie, ob es für Sie ist oder nicht, indem Sie ~ 10-15 Minuten auf der [Einführung in data.table] verbringen (https://github.com/Rdatatable/data.table/wiki/Getting-started) Vignette. – Arun

3

Wir können es mit dplyr, obwohl die Knoten trennt ein wenig hässlich ist:

library(dplyr) 
df %>% group_by(peaknum = rep(seq(rle(test)[['lengths']]), rle(test)[['lengths']])) %>% 
    filter(test == 1) %>% 
    summarise(from = min(pos), 
      to = max(pos)) %>% 
    mutate(peaknum = seq_along(peaknum)) 

# Source: local data frame [2 x 3] 

# peaknum from to 
#  (int) (dbl) (dbl) 
# 1  1 10 30 
# 2  2 70 90 

Was es tut:

  • die erste group_by verwendet rle um eine Spalte hinzuzufügen, die eine Sequenz entlang der wiederholten Nummern in test ist, und sie fürgruppiertspäter;
  • filter Koteletts Zeilen nach unten nur diejenigen, bei denen test1
  • summarise ist kollabiert die Gruppen und fügt maxmin und für jeden,
  • und schließlich mutate die Nummerierung der peaknum säubert.
+0

Oder laden Sie data.table neben dplyr und verwenden Sie rleid für den ersten Schritt. – Frank

+0

Ja, das würde es viel schöner machen. – alistaire

Verwandte Themen