Je suis sûr que c'est une question assez simple, mais je ne sais pas comment procéder. J'ai donné un exemple de tableau avec des dimensions (4,4,5) comme suit:
[,1] [,2] [,3] [,4]
[1,] 1 0 5 0
[2,] 0 NA 0 6
[3,] 0 0 0 0
[4,] 0 0 0 0
[,1] [,2] [,3] [,4]
[1,] 1 0 10 0
[2,] 0 NA 0 12
[3,] 0 0 0 0
[4,] 0 0 0 0
[,1] [,2] [,3] [,4]
[1,] 1 0 15 0
[2,] 0 NA 0 18
[3,] 0 0 0 0
[4,] 0 0 0 0
[,1] [,2] [,3] [,4]
[1,] 1 0 20 0
[2,] 0 NA 0 24
[3,] 0 0 0 0
[4,] 0 0 0 0
[,1] [,2] [,3] [,4]
[1,] 1 0 25 0
[2,] 0 NA 0 30
[3,] 0 0 0 0
[4,] 0 0 0 0
En gros, pour cet exemple de tableau, j'aimerais les éléments en [1,3] et [2 , 4] pour changer le long de la 3ème dimension mais je ne sais pas comment écrire ce code dans R. J'ai essayé d'utiliser des variantes du tableau de code (c (1,0,0,0,0, NA , 0,0,5,0,0,0,0,6,0,0), dim = c (4,4,3)) et j'ai essayé de vérifier en ligne mais je n'arrive pas à trouver tout ce qui peut aider à résoudre ce problème, donc toute aide que je pourrais obtenir serait grandement appréciée, merci d'avance.
3 Réponses :
Je ne suis pas tout à fait sûr de la sortie attendue, mais peut-être quelque chose comme ça en utilisant une boucle for ?
arr[1, 3, ] <- 100 arr[2, 4, ] <- 100
Comme indiqué par @ Cole, dans ce cas (simple), il n'y a pas besoin d'une boucle for
arr <- array(c(1,0,0,0,0,NA,0,0,5,0,0,0,0,6,0,0), dim=c(4,4,3))
for (i in seq_len(dim(arr)[3])) {
arr[1, 3, i] <- 100; # Change entry (1, 3) of every 2d matrix
arr[2, 4, i] <- 100; # Change entry (2, 4) of every 2d matrix
}
arr
#, , 1
#
# [,1] [,2] [,3] [,4]
#[1,] 1 0 100 0
#[2,] 0 NA 0 100
#[3,] 0 0 0 0
#[4,] 0 0 0 0
#
#, , 2
#
# [,1] [,2] [,3] [,4]
#[1,] 1 0 100 0
#[2,] 0 NA 0 100
#[3,] 0 0 0 0
#[4,] 0 0 0 0
#
#, , 3
#
# [,1] [,2] [,3] [,4]
#[1,] 1 0 100 0
#[2,] 0 NA 0 100
#[3,] 0 0 0 0
#[4,] 0 0 0 0
est beaucoup plus rapide que.
Cela semble faire ce que je veux, mais y a-t-il un moyen plus rapide de le faire en plus d'une boucle for ? Les données avec lesquelles je travaille sont malheureusement assez volumineuses: /
@ThePlowKing C'est une idée fausse que les boucles for sont intrinsèquement lentes dans R. Dans ce cas, nous écrasons les valeurs, ce qui est rapide. C'est lorsque vous abusez des boucles for pour développer dynamiquement des objets R lorsque les choses tournent mal. Si cela est vraiment trop lent, vous devrez peut-être examiner les options R non basiques, par exemple en utilisant Rcpp .
Il ne devrait pas y avoir besoin de la boucle. arr [1, 3,] <- 100 fournira le même résultat que pour (i in ...) {arr [1,3, i] <- 100} code > - la suppression de la boucle rend cette réponse 1000 fois plus rapide et environ 3 fois plus rapide que @thelatemail
@Cole - c'est certainement un bon point, mais vous devrez tout de même faire des affectations pour chacun des arr [1,3,] et arr [2,4,] etc. Si vous avez un petit nombre de combos ligne / colonne à écraser, votre suggestion sera très rapide. Je ne sais pas comment généraliser cela à de nombreux index.
Je ne suis pas sûr que arr [cbind (c (1,2), c (3,4), rep (...) économise beaucoup de saisie non plus. Mais comme votre réponse le suggère, si OP avait une règle des éléments à mettre à jour, votre réponse accepterait une règle beaucoup plus rapide que arr [1,3,] <- 100 . Il est facile d'imaginer cbind (1: 3, 4: 6, rep (...) . J'ajoute une troisième réponse car pourquoi pas arr [arr> 4] <- 100 .
@Cole a été absent pendant une heure lors d'une réunion et a manqué le suivi; merci à tous pour les mises à jour et suggestions intéressantes!
Vous pouvez également le faire avec une affectation en utilisant l'indexation matricielle:
cbind(c(1,2),c(3,4),rep(seq_len(dim(arr)[[3]]), each=2)) # row col strata # [,1] [,2] [,3] #[1,] 1 3 1 #[2,] 2 4 1 #[3,] 1 3 2 #[4,] 2 4 2 #[5,] 1 3 3 #[6,] 2 4 3
La partie à l'intérieur de [] donne les index row / col / strata pour chaque valeur à remplacer:
arr[cbind(c(1,2),c(3,4),rep(seq_len(dim(arr)[[3]]), each=2))] <- c(80,100) arr #, , 1 # # [,1] [,2] [,3] [,4] #[1,] 1 0 80 0 #[2,] 0 NA 0 100 #[3,] 0 0 0 0 #[4,] 0 0 0 0 # #, , 2 # # [,1] [,2] [,3] [,4] #[1,] 1 0 80 0 #[2,] 0 NA 0 100 #[3,] 0 0 0 0 #[4,] 0 0 0 0 # #, , 3 # # [,1] [,2] [,3] [,4] #[1,] 1 0 80 0 #[2,] 0 NA 0 100 #[3,] 0 0 0 0 #[4,] 0 0 0 0
Si vous effectuez une mise à jour en fonction de valeurs, vous appliquez une condition:
arr <- array(c(1,0,0,0,0,NA,0,0,5,0,0,0,0,6,0,0), dim=c(4,4,3))
library(microbenchmark)
x = microbenchmark(
maur_improved = {
arr[1,3, ] <- 100
arr[2, 4, ] <- 100
},
latemail_all_at_once = {
arr[cbind(c(1,2),c(3,4),rep(seq_len(dim(arr)[[3]]), each=2))] <- c(80,100)
},
maur_for_loop = {
for (i in seq_len(dim(arr)[3])) {
arr[1, 3, i] <- 100; # Change entry (1, 3) of every 2d matrix
arr[2, 4, i] <- 100; # Change entry (2, 4) of every 2d matrix
}
},
cole_subset_mat = {
arr[arr > 4] <- 100
}
, cole_which = {
which_cond <- which(arr>4, arr.ind = T)
arr[which_cond] <- arr[which_cond] * which_cond[, 3]
}
)
print(x, signif = 3)
Ce qui se passe, c'est que l'intérieur arr> 4 génère un tableau:
#4x4x3 array
Unit: microseconds
expr min lq mean median uq max neval
maur_improved 2.4 3.55 5.42 4.90 5.95 24.4 100
latemail_all_at_once 6.4 8.70 14.00 15.20 18.40 25.3 100
maur_for_loop 3280.0 3510.00 3810.00 3630.00 3770.00 6430.0 100
cole_subset_mat 2.0 3.05 4.71 4.05 6.50 10.2 100
cole_which 27.9 34.50 47.70 45.40 54.80 228.0 100
#4x4x3E6 array
Unit: milliseconds
expr min lq mean median uq max neval
maur_improved 82.9 84.8 89.7 85.8 87.4 165 100
latemail_all_at_once 347.0 361.0 391.0 378.0 417.0 564 100
maur_for_loop 422.0 432.0 462.0 451.0 486.0 721 100
cole_subset_mat 304.0 330.0 369.0 354.0 395.0 527 100
cole_which 783.0 842.0 899.0 878.0 928.0 1370 100
Et puis nous disons simplement d'assigner une valeur aux conditions qui sont vraies. On peut aussi utiliser which (arr> 4, arr.ind = T) pour renvoyer une matrice similaire à la solution de @ thelatemail sans le typage. Cela nous permet d'accéder à la réponse d'origine de votre message:
which_cond <- which(arr>4, arr.ind = T)
arr[which_cond] <- arr[which_cond] * which_cond[, 3]
arr
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 0 5 0
[2,] 0 NA 0 6
[3,] 0 0 0 0
[4,] 0 0 0 0
, , 2
[,1] [,2] [,3] [,4]
[1,] 1 0 10 0
[2,] 0 NA 0 12
[3,] 0 0 0 0
[4,] 0 0 0 0
, , 3
[,1] [,2] [,3] [,4]
[1,] 1 0 15 0
[2,] 0 NA 0 18
[3,] 0 0 0 0
[4,] 0 0 0 0
which_cond
dim1 dim2 dim3
[1,] 1 3 1
[2,] 2 4 1
[3,] 1 3 2
[4,] 2 4 2
[5,] 1 3 3
[6,] 2 4 3
Performances:
, , 1
[,1] [,2] [,3] [,4]
[1,] FALSE FALSE TRUE FALSE
[2,] FALSE NA FALSE TRUE
[3,] FALSE FALSE FALSE FALSE
[4,] FALSE FALSE FALSE FALSE
, , 2
[,1] [,2] [,3] [,4]
[1,] FALSE FALSE TRUE FALSE
[2,] FALSE NA FALSE TRUE
[3,] FALSE FALSE FALSE FALSE
[4,] FALSE FALSE FALSE FALSE
, , 3
[,1] [,2] [,3] [,4]
[1,] FALSE FALSE TRUE FALSE
[2,] FALSE NA FALSE TRUE
[3,] FALSE FALSE FALSE FALSE
[4,] FALSE FALSE FALSE FALSE
Et code:
arr[arr > 4 ] <- 100
Il convient de noter dans ces benchmarks qu'une microseconde est absolument minuscule. Même avec 2 millions de groupes de baies, la différence entre le plus rapide et le plus lent n'est que de 0,2 seconde d'après mes tests.
La surcharge de la boucle for semble être un coup unique. Bon appel pour soulever cela - mais je suis toujours étonné que R puisse mettre à jour 3 millions de baies en moins de 90 ms. Je ferai plus attention aux horaires sur un si petit ensemble de données car les microsecondes sont presque dénuées de sens.
Pouvez-vous partager des données en utilisant
dputet afficher également la sortie attendue?@RonakShah Je n'ai pas vraiment de sortie
dputparce que je n'ai aucune idée de comment le coder même :( La sortie attendue est ce que j'ai donné dans le post ci-dessus