2
votes

Création de nouvelles colonnes allant de 0 à la valeur dans la variable d'une table

Tableau reproductible: J'ai une base de données similaire à celle illustrée ci-dessous. La différence étant que la base de données avec laquelle je travaille est beaucoup plus grande.

   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

general_tibble donne:

general_binded <- bind_rows(general_list)
Question:

Comment créer une nouvelle table à partir d'une table précédente, qui prend la valeur de nrs , et crée une variable de colonne, appelée n , qui va de 0 à la valeur dans nrs?

Pour illustrer davantage, dans la ligne 1 de general_tibble la colonne nrs est égale à 42 donc la colonne serait aller de 0 à 42, dans la ligne 2 nrs est égal à 41 donc la colonne passerait de 0 à 41, et de même pour la ligne 3.

J'utilise actuellement le code ci-dessous. Cela fonctionne, mais lorsque general_tibble est trop gros, le code fonctionne très lentement.

general_list <- list()

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

Ensuite, je bind_rows () general_list pour obtenir general_binded

  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

general_binded [c (1: 5, 38:42),] donne:

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

PS: Dans la boucle for, j'utilise data.frame () à la place de tibble () parce que je veux recycler les lignes. Si vous avez une sorte de conseil impliquant des tibbles ou des dataframes, je suis heureux de le prendre.


5 Réponses :


2
votes

Nous pouvons utiliser uncount

general_tibble %>% 
   mutate(n = map(nrs+1, ~  seq(.x) - 1)) %>%
   unnest

Une autre option est unnest

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


0 commentaires

1
votes

Un moyen avec la base R (moins le package tibble ).

Tout d'abord, divisé par le groupe nrs . Ensuite, développez les lignes de chaque dataframe par la valeur nrs . Troisièmement, créez une colonne id qui représente 0: quel que soit le nombre de lignes. Quatrièmement, ramenez-le à une 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


0 commentaires

5
votes

L'approche la plus simple pour cela serait d'étendre la colonne general_tibble sur nrs en utilisant la fonction tidyr :: expand () :

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)


2 commentaires

Salut, le group_by_all ()%>% expand () a très bien fonctionné. Cependant, je suis maintenant confronté au problème qu'il faut environ 15 minutes pour agrandir un tibble d'environ 600 000 lignes. Que suggérez-vous?


@DennisAguilar donne une chance à la solution data.table de Toucan, car data.table est généralement plus rapide. Une autre idée pour le moment est de diviser après le regroupement, l'expansion puis la reliure (je ne sais pas si cela aiderait).



1
votes

Avec dplyr et tidyr , vous pouvez également faire:

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 commentaires

4
votes

Une bonne chose à propos de l'utilisation de data.table par rapport à tidyverse est que vous n'avez pas besoin de penser aux opérations pour savoir si ce que vous faites est un muter , développer ou résumer . Vous pouvez simplement mettre ce que vous voulez dans la partie j de df [i, j, k] et quel que soit le nombre de lignes à résoudre, c'est ce que vous obtenez.

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


0 commentaires