2017-07-03 23 views
8

Mam ramki danych tak:przekształcanie kolumny K do 2 kolumny reprezentujące kolejne pary wartości zmiennych k

id y1 y2 y3 y4 
--+--+--+--+-- 
a |12|13|14| 
b |12|18| | 
c |13| | | 
d |13|14|15|16 

Chcę przekształcić w taki sposób, że kończę z dwoma kolumnami. Powyższy przykład da się wtedy:

id from to 
--+----+--- 
a |12 |13 
a |13 |14 
a |14 | 
b |12 |18 
b |18 | 
c |13 | 
d |13 |14 
d |14 |15 
d |15 |16 

Każdy id ma „od” a „do” za parę wartości rocznie.
Czy ktoś wie o łatwy sposób to zrobić? Próbowałem użyć reshape2. Spojrzałem też na Combine Multiple Columns Into Tidy Data, ale myślę, że mój przypadek jest inny.

Odpowiedz

5

Można użyć lapply do pętli nad parami kolumn i rbind do unii nich:

do.call(rbind, 
     lapply(2:(length(df)-1), 
       function(x) setNames(df[!is.na(df[,x]),c(1,x,x+1)], 
            c("id", "from", "to")))) 
    id from to 
1 a 12 13 
2 b 12 18 
3 c 13 NA 
4 d 13 14 
11 a 13 14 
21 b 18 NA 
41 d 14 15 
12 a 14 NA 
42 d 15 16 
5

Rozwiązanie wykorzystuje dplyr i tidyr. dt2 to końcowe wyjście.

# Create example data frame 
dt <- data.frame(id = c("a", "b", "c", "d"), 
       y1 = c(12, 12, 13, 13), 
       y2 = c(13, 18, NA, 14), 
       y3 = c(14, NA, NA, 15), 
       y4 = c(NA, NA, NA, 16), 
       stringsAsFactors = FALSE) 

# Load packages 
library(dplyr) 
library(tidyr) 

# Process the data 
dt2 <- dt %>% 
    gather(STEP, from, -id) %>% 
    drop_na(from) %>% 
    arrange(id, STEP) %>% 
    group_by(id) %>% 
    mutate(to = lead(from)) %>% 
    select(-STEP) 
+0

Neat, choć wytwarzania dodatkowych rząd – HubertL

+1

@HubertL Dzięki za komentarz. Wiem, że ostatni rząd nie jest w pożądanych wynikach OP, ale czuję, że powinien tam być. Przynajmniej nie znajduję dobrej logiki, aby wykluczyć ostatni wiersz, ponieważ istnieje również ostatni wiersz id "a", "b" i "c". – www

+0

Nie powinien, ponieważ jego wartość "to" jest generowana przez "lead". Przegrupowanie: 'df%>% gather (var, from, -id)%>% aranżacja (id, var)%>% group_by (id)%>% mutate (to = lead (z))%> % #slice (-n())%>% filtr (! Is.na (z), var! = 'Y4')%>% select (-var) ' – alistaire

4

bazy R stack i przesunięcie wszystko z powrotem jednego rzędu w każdej z grup. Korzystanie @ przykładowych danych ycw, w dt:

tmp <- na.omit(cbind(dt[1], stack(dt[-1])[-2])) 
names(tmp)[2] <- "from" 
tmp$to <- with(tmp, ave(from, id, FUN=function(x) c(tail(x,-1),NA))) 
tmp[order(tmp$id),] 

# id from to 
#1 a 12 13 
#5 a 13 14 
#9 a 14 NA 
#2 b 12 18 
#6 b 18 NA 
#3 c 13 NA 
#4 d 13 14 
#8 d 14 15 
#12 d 15 16 
#16 d 16 NA 

W świecie data.table, obowiązuje ta sama logika. melt, następnie shiftby= id:

library(data.table) 
dt <- as.data.table(dt) 

melt(dt, id.vars="id", value.name="from")[ 
    !is.na(from),-"variable"][, to := shift(from,1,type="lead"), by=id 
][order(id)]