2
votes

Comment créer des index de groupe pour des groupes imbriqués dans r

J'ai un ensemble de données avec plusieurs observations imbriquées dans des individus. Cet exemple d'ensemble de données comprend des colonnes pour l'id et pour le jour de la semaine (dayweek, 1-7). J'ai des observations de 3 jours de chaque individu. Ainsi, une personne peut avoir soumis des rapports uniquement pour dim / mer / jeu (1, 4, 5), et l'autre peut avoir soumis des rapports pour dim / lun / mar (1, 2, 3), comme dans cet exemple:

df %>% group_indices(id, dayweek) 

Je veux créer une colonne qui marque le premier, le deuxième et le troisième jour de chaque individu, comme ceci:

df2 <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3),
  daynum = c(rep(1:3, each = 2, times = 2), 3)
)

J'ai essayé d'utiliser

df <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3)
)

mais cela produit un nouvel identifiant pour chaque combinaison individuelle-jour. Quelle est la bonne façon de procéder?

Merci d'avance!

r

2 commentaires

Et si les jours étaient vendredi, samedi, dimanche: alors vous auriez 6,7,1 mais le 6 serait le premier jour et le 1 serait le troisième, non? Les lignes sont-elles déjà dans l'ordre des dates, de sorte que la première ligne d'un identifiant obtienne daynum = 1?


Salut, c'est exact: dans ce cas, je voudrais recoder 6 à 1, 7 à 2 et 1 à 3. Oui, les lignes sont dans l'ordre mais il y a un nombre d'observations différent pour chaque individu et chaque jour. Ils pourraient donc avoir 4 observations pour samedi, 2 pour soleil, etc.


3 Réponses :


4
votes

Nous pourrions group_by id et créer un id unique pour chaque dayweek

with(df, ave(dayweek, id, FUN = function(x) 
         as.integer(factor(x, levels = unique(x)))))
#[1] 1 1 2 2 3 3 1 1 2 2 3 3 3


4 commentaires

Pour le cas "vendredi, samedi, dimanche" ( dayweek 6, 7, 1), cela retournera 2, 3, 1 alors que l'OP attend 1, 2, 3 selon les commentaires.


@Uwe Merci, a mis à jour la réponse pour gérer ce cas.


Intéressant de voir l'utilisation de unique . D'une manière ou d'une autre, le ! Dupliqué peut facilement être interprété comme signifiant unique mais son application devient délicate.


@NelsonGon Oui, ici l'OP voulait suivre le bon ordre en fonction du moment où la dayweek a été observée, d'où l'utilisation de unique .



5
votes

dplyr

Utilisation de cumsum et ! dupliqué avec dplyr

unlist(tapply(df$dayweek, df$id, function(x) cumsum(!duplicated(x))))

 1  1  2  2  3  3  1  1  2  2  3  3  3 

tapply depuis la base R

df %>%
  group_by(id) %>%
  mutate(daynum = cumsum(!duplicated(dayweek)))


# A tibble: 13 x 3
# Groups:   id [2]
      id dayweek daynum
   <dbl>   <dbl>  <int>
 1     1       1      1
 2     1       1      1
 3     1       4      2
 4     1       4      2
 5     1       5      3
 6     1       5      3
 7     2       1      1
 8     2       1      1
 9     2       2      2
10     2       2      2
11     2       3      3
12     2       3      3
13     2       3      3

1 commentaires

Cela gère également le cas "vendredi, samedi, dimanche" ( dayweek 6, 7, 1).



2
votes

D'après Commentaire d'OP a >, les lignes sont dans l'ordre.

Ensuite, voici deux approches différentes qui traiteront également le cas "vendredi, samedi, dimanche" ( dayweek 6, 7, 1) mentionné dans les commentaires .

  1. rleid()
  2. fct_inorder()

rleid()

Ceci utilise la fonction rleid () de la data.table package:

df2 <- data.frame(
  id = c(rep(1:2, each = 6), 2, rep(3, 3)),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3, 6, 7, 1),
  daynum = c(rep(1:3, each = 2, times = 2), 3, 1:3)
)
df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = 
           dayweek %>% 
           as.character() %>% 
           forcats::fct_inorder() %>% 
           as.integer()
         ) 

Notez qu'un ensemble de données étendu est utilisé qui couvre également le cas "vendredi, samedi, dimanche" ( dayweek 6, 7, 1).

fct_inorder()

Ceci est une version améliorée de réponse de Ronak qui s'occupe également de l'affaire «vendredi, samedi, dimanche». Il utilise le fct_inorder () du package forcats qui réorganise les niveaux de facteur par première apparition.

      id dayweek daynum daynum2
   <dbl>   <dbl>  <dbl>   <int>
 1     1       1      1       1
 2     1       1      1       1
 3     1       4      2       2
 4     1       4      2       2
 5     1       5      3       3
 6     1       5      3       3
 7     2       1      1       1
 8     2       1      1       1
 9     2       2      2       2
10     2       2      2       2
11     2       3      3       3
12     2       3      3       3
13     2       3      3       3
14     3       6      1       1
15     3       7      2       2
16     3       1      3       3

Le résultat est comme ci-dessus.

Données

Il s'agit d'un ensemble de données étendu qui comprend également le cas "vendredi, samedi, dimanche" ( dayweek 6, 7 , 1):

library(dplyr)
df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = data.table::rleid(dayweek)) 


0 commentaires