Создание новых столбцов, которые идут от 0 до значения в переменной таблицы - PullRequest
3 голосов
/ 21 мая 2019

Воспроизводимый тиббл: У меня есть база данных, подобная показанной ниже. Разница в том, что база данных, с которой я работаю, намного больше.

general_tibble <- tibble(gender = c("female", "female", "male"),
                             age = c(18, 19,18),
                             age_partner = c(22,20,17),
                             max_age = c(60, 60, 65), 
                             nrs =c(42,41,47))

general_tibble Результат:

  gender age age_partner max_age nrs
1 female  18          22      60  42
2 female  19          20      60  41
3   male  18          17      65  47

Вопрос: Как создать новую таблицу из предыдущей таблицы, которая принимает значение nrs и создает переменную столбца с именем n, которая переходит от 0 к значению в nrs?

Чтобы проиллюстрировать это далее, в строке 1 general_tibble столбец nrs равен 42, поэтому столбец будет идти от 0 до 42, в строке 2 nrs равен 41, поэтому столбец будет идти от 0 до 41, и то же самое для ряда 3.

Я сейчас использую код ниже. Это работает, но когда general_tibble слишком большой, код работает очень медленно.

general_list <- list()

for(i in 1:NROW(general_tibble)){
  general_list[[i]] <- data.frame(general_tibble[i, ], 
                             n = 0:general_tibble[[i, "nrs"]])
} 

Тогда я bind_rows() general_list для получения general_binded

general_binded <- bind_rows(general_list)

general_binded[c(1:5, 38:42),] Результат:

   gender age age_partner max_age nrs  n
1  female  18          22      60  42  0
2  female  18          22      60  42  1
3  female  18          22      60  42  2
4  female  18          22      60  42  3
5  female  18          22      60  42  4
38 female  18          22      60  42 37
39 female  18          22      60  42 38
40 female  18          22      60  42 39
41 female  18          22      60  42 40
42 female  18          22      60  42 41

PS: В цикле for я использую data.frame() вместо tibble(), потому что я хочу перезаписать строки. Если у вас есть какой-то совет, связанный с тибблами или кадрами, я с радостью приму его.

Ответы [ 5 ]

5 голосов
/ 21 мая 2019

Самый простой подход к этому: расширение столбца general_tibble на nrs с использованием функции tidyr::expand():

library(tidyverse)

general_tibble %>% 
        group_by_all()%>% 
        expand(n = 0:nrs)

#> # A tibble: 133 x 6
#> # Groups:   gender, age, age_partner, max_age, nrs [3]
#>    gender   age age_partner max_age   nrs     n
#>    <chr>  <dbl>       <dbl>   <dbl> <dbl> <int>
#>  1 female    18          22      60    42     0
#>  2 female    18          22      60    42     1
#>  3 female    18          22      60    42     2
#>  4 female    18          22      60    42     3
#>  5 female    18          22      60    42     4
#>  6 female    18          22      60    42     5
#>  7 female    18          22      60    42     6
#>  8 female    18          22      60    42     7
#>  9 female    18          22      60    42     8
#> 10 female    18          22      60    42     9
#> # ... with 123 more rows

Создано в 2019-05-21 с помощью представпакет (v0.2.1)


Еще одна идея, использующая только base R функции:

expanded_vars <- do.call(rbind,lapply(general_tibble$nrs, 
                                              function(x) expand.grid(x, 0:x)))
names(expanded_vars) <- c("nrs", "n")

merge(y = expanded_vars, x = general_tibble, by = "nrs", all = TRUE)
4 голосов
/ 21 мая 2019

Одна из приятных особенностей использования data.table против tidyverse заключается в том, что вам не нужно думать об операциях с точки зрения того, что вы делаете: mutate, expand или summarize.Вы можете просто поместить то, что вы хотите, в j часть df[i, j, k], и сколько угодно строк - это то, что вы получите.

library(data.table)
setDT(general_tibble)

general_tibble[, .(n = seq(0, nrs))
               , by = names(general_tibble)]


#      gender age age_partner max_age nrs  n
#   1: female  18          22      60  42  0
#   2: female  18          22      60  42  1
#   3: female  18          22      60  42  2
#   4: female  18          22      60  42  3
#   5: female  18          22      60  42  4
#  ---                                      
# 129:   male  18          17      65  47 43
# 130:   male  18          17      65  47 44
# 131:   male  18          17      65  47 45
# 132:   male  18          17      65  47 46
# 133:   male  18          17      65  47 47
2 голосов
/ 21 мая 2019

Мы можем использовать uncount

library(tidyverse)
general_tibble %>% 
   mutate(grp = row_number(), nrsN = nrs + 1) %>% 
   uncount(nrsN) %>%
   group_by(grp) %>% 
   mutate(n = row_number() - 1) %>%
   ungroup %>%
   select(-grp)
# A tibble: 133 x 6
#   gender   age age_partner max_age   nrs     n
#   <chr>  <dbl>       <dbl>   <dbl> <dbl> <dbl>
# 1 female    18          22      60    42     0
# 2 female    18          22      60    42     1
# 3 female    18          22      60    42     2
# 4 female    18          22      60    42     3
# 5 female    18          22      60    42     4
# 6 female    18          22      60    42     5
# 7 female    18          22      60    42     6
# 8 female    18          22      60    42     7
# 9 female    18          22      60    42     8
#10 female    18          22      60    42     9
# … with 123 more rows

Другой вариант - unnest

general_tibble %>% 
   mutate(n = map(nrs+1, ~  seq(.x) - 1)) %>%
   unnest
1 голос
/ 21 мая 2019

С dplyr и tidyr вы также можете сделать:

general_tibble %>%
 group_by(rowid = row_number()) %>%
 mutate(n = nrs) %>%
 complete(n = seq(0, n, 1)) %>%
 fill(everything(), .direction = "up") %>%
 ungroup() %>%
 select(-rowid)

       n gender   age age_partner max_age   nrs
   <dbl> <chr>  <dbl>       <dbl>   <dbl> <dbl>
 1     0 female    18          22      60    42
 2     1 female    18          22      60    42
 3     2 female    18          22      60    42
 4     3 female    18          22      60    42
 5     4 female    18          22      60    42
 6     5 female    18          22      60    42
 7     6 female    18          22      60    42
 8     7 female    18          22      60    42
 9     8 female    18          22      60    42
10     9 female    18          22      60    42
0 голосов
/ 21 мая 2019

В одну сторону с основанием R (минус пакет tibble).

Сначала разделим на группу nrs. Во-вторых, разверните строки каждого кадра данных на значение nrs. В-третьих, создайте столбец id, который представляет 0: любое количество строк. В-четвертых, верните его на tibble:

library(tibble)

df <- tibble(
  gender      = c("female", "female", "male"),
  age         = c(18, 19, 18),
  age_partner = c(22, 20, 17),
  max_age     = c(60, 60, 65), 
  nrs         = c(42, 41, 47)
  )

nrs_split <- split(df, df$nrs)
df_list <- lapply(nrs_split, function(i) i[rep(seq_len(nrow(i)), each=i$nrs + 1), ])
df_renum <- lapply(df_list, function(i) {i$id <- 0:rle(i$nrs)$values; return(i)})
df <- do.call("rbind", df_renum)
df
#> # A tibble: 133 x 6
#>    gender   age age_partner max_age   nrs    id
#>  * <chr>  <dbl>       <dbl>   <dbl> <dbl> <int>
#>  1 female    19          20      60    41     0
#>  2 female    19          20      60    41     1
#>  3 female    19          20      60    41     2
#>  4 female    19          20      60    41     3
#>  5 female    19          20      60    41     4
#>  6 female    19          20      60    41     5
#>  7 female    19          20      60    41     6
#>  8 female    19          20      60    41     7
#>  9 female    19          20      60    41     8
#> 10 female    19          20      60    41     9
#> # … with 123 more rows
...