J'ai une question concernant la préparation des données. J'ai l'ensemble de données suivant (au format long; une ligne par point de mesure, donc plusieurs lignes par personne):
dd <- read.table(text= "ID time new.var 1 -4 0 1 -3 0 1 -2 0 1 -1 0 1 0 1 1 1 0 2 -3 0 2 -1 0 2 2 1 2 3 0 2 4 0 3 -3 0 3 -2 0 3 -1 0 4 -1 0 4 1 1 4 2 0 4 3 0 5 0 1 5 1 0 5 2 0 5 3 0 5 4 0", header=TRUE)
Maintenant, je voudrais créer une nouvelle variable qui a un 1 dans le ligne, dans laquelle un changement de signe sur la variable de temps se produit pour la première fois pour cette personne, et un 0 dans toutes les autres lignes. Si une personne n'a que des valeurs négatives à l ' heure , le ne doit pas être égal à 1 sur la nouvelle variable. Pour une personne qui n'a que des valeurs positives à heure , la première ligne doit avoir un 1 sur la nouvelle variable et toutes les autres lignes doivent être codées avec 0. Pour mon exemple ci-dessus, le nouveau bloc de données devrait ressembler à ceci:
dd <- read.table(text= "ID time 1 -4 1 -3 1 -2 1 -1 1 0 1 1 2 -3 2 -1 2 2 2 3 2 4 3 -3 3 -2 3 -1 4 -1 4 1 4 2 4 3 5 0 5 1 5 2 5 3 5 4", header=TRUE)
Est-ce que quelqu'un sait comment faire cela? J'ai pensé à utiliser dplyr et group_by, mais je suis assez nouveau dans R et je ne l'ai pas fait. Toute aide est très appréciée!
3 Réponses :
Vous pouvez essayer ceci:
library(dplyr) dd %>% left_join(dd %>% group_by(ID) %>% summarise(index=min(which(time>=0)))) %>% group_by(ID) %>% mutate(new.var=ifelse(row_number(ID)==index,1,0)) %>% select(-index)-> DF # A tibble: 23 x 3 # Groups: ID [5] ID time new.var <int> <int> <dbl> 1 1 -4 0 2 1 -3 0 3 1 -2 0 4 1 -1 0 5 1 0 1 6 1 1 0 7 2 -3 0 8 2 -1 0 9 2 2 1 10 2 3 0
En espérant que cela peut vous aider!
Il y a 2 opérations différentes que vous voulez faire pour créer new.var
, vous devez donc les faire en 2 étapes. Je vais diviser cela en 2 appels mutate
séparés pour plus de simplicité, mais vous pouvez les mettre tous les deux dans le même mutate
Premièrement, nous groupons par ID puis trouvons les lignes où le signe change. Nous devons utiliser time> = 0
au lieu de sign
comme recommandé dans cette réponse: R identifiant une ligne avant un changement de signe car vous voulez qu'un changement de signe soit compté uniquement lorsque vous passez de -1 0, pas de 0 1:
dd3 <- dd2 %>% mutate(new.var = case_when( !is.na(new.var) ~ new.var, all(time >= 0) ~ 1, TRUE ~ 0) ) print(dd3, n = 100) #n=100 because tibbles are truncated to 10 rows by print # A tibble: 23 x 3 # Groups: ID [5] ID time new.var <int> <int> <dbl> 1 1 -4 0 2 1 -3 0 3 1 -2 0 4 1 -1 0 5 1 0 1 6 1 1 0 7 2 -3 0 8 2 -1 0 9 2 2 1 10 2 3 0 11 2 4 0 12 3 -3 0 13 3 -2 0 14 3 -1 0 15 4 -1 0 16 4 1 1 17 4 2 0 18 4 3 0 19 5 0 1 20 5 1 0 21 5 2 0 22 5 3 0 23 5 4 0
Ensuite, nous utilisons case_when
pour modifier la première ligne en fonction des règles souhaitées. En raison du fonctionnement de lag
, la première ligne aura toujours NA
(car il n'y a pas de ligne précédente à regarder), ce qui en fait un bon moyen de la sélectionner en premier. ligne pour le modifier en fonction des valeurs time
dans ce groupe:
library(tidyverse) dd2 <- dd %>% group_by(ID) %>% mutate(new.var = as.numeric((time >= 0) != (lag(time) >= 0))) dd2 # A tibble: 23 x 3 # Groups: ID [5] ID time new.var <int> <int> <dbl> 1 1 -4 NA 2 1 -3 0 3 1 -2 0 4 1 -1 0 5 1 0 1 6 1 1 0 7 2 -3 NA 8 2 -1 0 9 2 2 1 10 2 3 0 # ⦠with 13 more rows
L'instruction ave
suivante fait ce que la question demande.
identical(dd, dd2) #[1] TRUE
Si la sortie attendue est renommée dd2
alors p >
dd$new.var <- with(dd, ave(time, ID, FUN = function(x){ y <- integer(length(x)) if(any(x >= 0)) y[which.max(x[1]*x <= 0)] <- 1L y })) dd # ID time new.var #1 1 -4 0 #2 1 -3 0 #3 1 -2 0 #4 1 -1 0 #5 1 0 1 #6 1 1 0 #7 2 -3 0 #8 2 -1 0 #9 2 2 1 #10 2 3 0 #11 2 4 0 #12 3 -3 0 #13 3 -2 0 #14 3 -1 0 #15 4 -1 0 #16 4 1 1 #17 4 2 0 #18 4 3 0 #19 5 0 1 #20 5 1 0 #21 5 2 0 #22 5 3 0 #23 5 4 0
Également associé: stackoverflow.com/q/45154687/8366499 , stackoverflow.com/q/48378653/8366499