2017-10-20 1 views
2

ich einen Datenrahmen haben wie folgt zu haben:einen Datenrahmen erweitern so viele Zeilen wie Bereich von zwei Spalten in Originalreihen

structure(list(symbol = c("u", "n", "v", "i", "a"), start = c(9L, 
6L, 10L, 8L, 7L), end = c(14L, 15L, 12L, 13L, 11L)), .Names = c("symbol", 
"start", "end"), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5")) 

ich so viele Zeilen wollen, da es Werte im Bereich von sind (Anfang, Ende) für jedes Symbol. So wird die endgültige Datenrahmen wie folgt aussehen:

structure(list(symbol = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 
4L, 4L, 5L, 5L, 5L, 5L, 5L), .Label = c("a", "l", "n", "v", "y" 
), class = "factor"), value = c(7L, 8L, 9L, 10L, 11L, 6L, 7L, 
8L, 9L, 10L, 11L, 12L, 13L, 14L, 8L, 9L, 10L, 11L, 12L, 10L, 
11L, 12L, 13L, 14L, 15L, 9L, 10L, 11L, 12L, 13L)), class = "data.frame", row.names = c(NA, 
-30L), .Names = c("symbol", "value")) 

Ich dachte ich einfach eine Liste von Werten pro Zeile haben könnte, und dann tidyr Pakets verwenden unnest wie folgt:

df$value <- apply(df, 1, function(x) as.list(x[2]:x[3])) 
dput(df) 
structure(list(symbol = structure(c(4L, 3L, 5L, 2L, 1L), .Label = c("a", 
"i", "n", "u", "v"), class = "factor"), start = c(9L, 6L, 10L, 
8L, 7L), end = c(14L, 15L, 12L, 13L, 11L), value = structure(list(
    `1` = list(9L, 10L, 11L, 12L, 13L, 14L), `2` = list(6L, 7L, 
     8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L), `3` = list(10L, 
     11L, 12L), `4` = list(8L, 9L, 10L, 11L, 12L, 13L), `5` = list(
     7L, 8L, 9L, 10L, 11L)), .Names = c("1", "2", "3", "4", 
"5"))), .Names = c("symbol", "start", "end", "value"), row.names = c("1", 
"2", "3", "4", "5"), class = "data.frame") 

df 
    symbol start end        value 
1  u  9 14    9, 10, 11, 12, 13, 14 
2  n  6 15 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 
3  v 10 12       10, 11, 12 
4  i  8 13    8, 9, 10, 11, 12, 13 
5  a  7 11     7, 8, 9, 10, 11 

Dann tun:

library(tidyr) 
unnest(df, value) 

aber ich denke, ich diese angemeldete Funktion/bug am schlagen: https://github.com/tidyverse/tidyr/issues/278

Error: Each column must either be a list of vectors or a list of data frames [value] 

Gibt es einen besseren Weg, dies zu tun, vor allem die Familie zu vermeiden?

Antwort

2

Mit dplyr, können wir verwenden rowwise mit do

library(dplyr) 
df1 %>% 
    rowwise() %>% 
    do(data.frame(symbol= .$symbol, value = .$start:.$end)) %>% 
    arrange(symbol) 
# A tibble: 30 x 2 
# symbol value 
# <chr> <int> 
# 1  a  7 
# 2  a  8 
# 3  a  9 
# 4  a 10 
# 5  a 11 
# 6  i  8 
# 7  i  9 
# 8  i 10 
# 9  i 11 
#10  i 12 
# ... with 20 more rows 
+1

Darn einfach, nicht wahr! Ich vergesse immer wieder, wie viel Macht das 'do' in einer Pipeline hat. Versucht, mit ein bisschen für dieses Problem zu spielen, aber konnte nicht mit den richtigen Schritten kommen. Perfekt. Vielen Dank! – Gopala

1

könnten Sie data.table verwenden und die df durch die erforderliche Anzahl von Zeilen (basierend auf dem start und end für jeden symbol) replizieren, dann zu jeder Zeile den Wert zuweisen, nachdem

library(data.table) 

setDT(df) 
df[rep(1:.N, (end - start + 1))][, value := (start - 1) + (1:.N), by = symbol][] 

# symbol start end value 
# 1:  u  9 14  9 
# 2:  u  9 14 10 
# 3:  u  9 14 11 
# 4:  u  9 14 12 
# 5:  u  9 14 13 
# ... etc 
1

Vielleicht könnten Sie map2 verwenden, um fügen Sie eine Spalte hinzu, aus der wir unnest in das gewünschte Ergebnis einfügen können.

library(tidyverse) 
df %>% 
    mutate(value = map2(start, end, ~ seq(from = .x, to = .y))) %>% 
    select(symbol, value) %>% 
    unnest() 
#> symbol value 
#> 1  u  9 
#> 2  u  10 
#> 3  u  11 
#> 4  u  12 
#> 5  u  13 
#> 6  u  14 
#> 7  n  6 
#> 8  n  7 
#> 9  n  8 
#> 10  n  9 
#> ...etc 
Verwandte Themen