2017-10-20 3 views
2

J'ai une trame de données comme suit:développer une trame de données pour avoir autant de lignes que la gamme de deux colonnes dans l'original rangée

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

Je veux autant de lignes que les valeurs de l'ordre de (début, fin) pour chaque symbole. Ainsi, la trame de données final ressemblera:

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

Je pensais que je pouvais simplement avoir une liste de valeurs par ligne, puis unnest utilisons tidyr package comme suit:

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 

Ensuite, faites:

library(tidyr) 
unnest(df, value) 

Cependant, je pense que je frappe cette fonction/bug en attente: https://github.com/tidyverse/tidyr/issues/278

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

Y a-t-il un meilleur moyen de le faire, en particulier en évitant d'appliquer la famille?

Répondre

2

Avec dplyr, nous pouvons utiliser rowwise avec 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

Zut simple, hein! Je continue d'oublier combien de puissance le 'do 'a dans un pipeline. Je ai essayé de jouer avec un peu pour ce problème, mais je ne pouvais pas trouver les bonnes mesures. Parfait. Je vous remercie! – Gopala

1

Vous pouvez utiliser data.table et reproduire le df par le nombre requis de lignes (sur la base start et end pour chaque symbol), puis attribuez-lui la valeur à chaque ligne après

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

peut-être que vous pouvez utiliser pour map2 ajouter une colonne à partir de laquelle nous pouvons unnest dans le résultat souhaité.

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