Je souhaite rendre mon code plus efficace, j'ai une enquête où mes données ressemblent à:

survey <- data.frame(
                     x = c(1, 6, 2, 60, 75, 40, 27, 10),
                     y = c(100, 340, 670, 700, 450, 200, 136, 145)) 

#Two lists:
A <- c(3, 6, 7, 27, 40, 41)
t <- c(0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16)

Ce que j'ai fait, c'est créer de nouvelles colonnes, comme ceci:

z <- ifelse(survey$x %in% A), 0, min(t))

for (i in t) {
  survey[paste0("T",i)] <-z
  survey[paste0("T",i)] <-ifelse (z > 0, i, z)
}

Mais avec ce code, cela prend du temps, y a-t-il une meilleure façon de le faire?

7
Marlon Molina 27 nov. 2017 à 12:45

3 réponses

Meilleure réponse

Comme l'OP l'a mentionné à propos de la vitesse d'exécution, l'option data.table serait plus rapide

library(data.table)
i1 <- !survey$x %in% A

setDT(survey)[, paste0("T", t) := 0]
for(j in t) {
    set(survey2, i = which(i1), j = paste0("T", j), value = j) 
    }

Repères

set.seed(24)
survey1 <- data.frame(x = sample(survey$x, 1e7, replace = TRUE),
       y = sample(survey$y, 1e7, replace = TRUE))

survey2 <- copy(survey1)

system.time({

survey1[paste0("T", t)] <- lapply(t, function(y) ifelse(survey1$x %in% A, 0, y))
})
# user  system elapsed 
#   8.20    2.75   11.03 

system.time({
i1 <- !survey2$x %in% A

setDT(survey2)[, paste0("T", t) := 0]
for(j in t) {
     set(survey2, i = which(i1), j = paste0("T", j), value = j) 
        }

})
# user  system elapsed 
#   0.97    0.31    1.28 
7
akrun 27 nov. 2017 à 10:04

Il peut être encore plus rapide d'utiliser la multiplication matricielle.

dat <- cbind(survey, matrix(!survey$x %in% A) %*% t)
   x   y   1    2    3    4    5    6    7
1  1 100 0.1 0.11 0.12 0.13 0.14 0.15 0.16
2  6 340 0.0 0.00 0.00 0.00 0.00 0.00 0.00
3  2 670 0.1 0.11 0.12 0.13 0.14 0.15 0.16
4 60 700 0.1 0.11 0.12 0.13 0.14 0.15 0.16
5 75 450 0.1 0.11 0.12 0.13 0.14 0.15 0.16
6 40 200 0.0 0.00 0.00 0.00 0.00 0.00 0.00
7 27 136 0.0 0.00 0.00 0.00 0.00 0.00 0.00
8 10 145 0.1 0.11 0.12 0.13 0.14 0.15 0.16

Ici, matrix(!survey$x %in% A) construit une matrice nX1 avec VRAI et FAUX en fonction de la présence ou non des valeurs de l'enquête $ x dans A. Ce résultat est une matrice multipliée (%*%) par t, qui est traitée comme un Matrice 1Xn. Le résultat est alors la sortie souhaitée.

Vous pouvez ajouter les noms de colonne par la suite si vous le souhaitez en utilisant le code dans la réponse de Lyzander.

2
lmo 27 nov. 2017 à 12:59

Vous pouvez utiliser sapply pour cela:

#just make your new cols with sapply
newcols <- sapply(t, function(i) ifelse (z > 0, i, z))
#add the names you wanted
colnames(newcols) <- paste0("T", seq_along(t))
#merge to your original survey data set
cbind(survey, newcols)

#   x   y  T1   T2   T3   T4   T5   T6   T7
#1  1 100 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#2  6 340 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#3  2 670 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#4 60 700 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#5 75 450 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#6 40 200 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#7 27 136 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#8 10 145 0.1 0.11 0.12 0.13 0.14 0.15 0.16
4
LyzandeR 27 nov. 2017 à 09:51
47507915