2017-03-11 1 views
0

J'essaie de sous-créer mon ensemble de données en utilisant une boucle imbriquée. Malheureusement, cela ne semble pas fonctionner correctement: je reçois quelques avertissements et la boucle ne fonctionne pas aussi bien que je le souhaiterais.Boucle imbriquée dans R: le nombre d'éléments à remplacer n'est pas un multiple de la longueur de remplacement

Voici un exemple de code court. Les données présentées sont juste un exemple - l'ensemble de données réel est beaucoup plus grand: Toute solution qui implique de choisir manuellement des valeurs n'est pas réalisable.

# #Generate example data 
unique_test <- list() 
unique_test[[1]] <- c(178.5, 179.5, 180.5, 181.5) 
unique_test[[2]] <- c(269.5, 270.5, 271.5) 



tmp_dataframe1 <- data.frame(myID = c(268, 305, 268, 305, 268, 305, 306), 
          myvalue = c(1.150343, 2.830392, 1.150343, 2.830392, 1.150343, 2.830392, 1.150343), 
          myInter = c(178.5, 178.5, 179.5, 179.5, 180.5, 180.5, 181.5)) 

tmp_dataframe2 <- data.frame(myID = c(144, 188, 196, 300, 301, 302, 303, 97), 
          myvalue = c(1.293493, 3.286649, 1.408049, 0.469219, 11.143147, 0.687355, 0.508603, 0.654335), 
          myInter = c(269.5, 269.5, 269.5, 270.5, 270.5, 271.5, 185.5, 186.5)) 



mydata <- list() 
mydata[[1]] <- tmp_dataframe1 
mydata[[2]] <- tmp_dataframe2 
######################## 

# #Generate nested loop 
mysubset <- list() #Define list 

for(i in 1:length(unique_test)){ 
    #Prepare list of lists 
    mysubset[[i]] <- NaN 
    for(j in 1:length(unique_test[[i]])){ 
    #Select myvalues whose myInter data equals the one found in unique_test and assign them to a new subset 
    mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == unique_test[[i]][j]),][["myvalue"]] 
    } 
} 

# #There are warnings and the nested loop is not really doing, what it is supposed to do! 

R donne les avertissements suivants:

Warning messages: 
1: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == : 
    number of items to replace is not a multiple of replacement length 
2: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == : 
    number of items to replace is not a multiple of replacement length 
3: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == : 
    number of items to replace is not a multiple of replacement length 
4: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == : 
    number of items to replace is not a multiple of replacement length 
5: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == : 
    number of items to replace is not a multiple of replacement length 

Si je me bornerai à tout le premier élément dans mon jeu de données, la "normale" boucle (ie pas imbriqué) fonctionne sur:

# #If I don't use a nested loop (by just using the first element in both "mydata" and "unique_test"), things seem to work out 
# #But obviously, this is not really what I want to achieve (I can't just manually select every element in mydata and unique_test) 
mysubset <- list() 
for(i in 1:length(unique_test[[1]])){ 
    #Select myvalues whose myInter data equals the one found in unique_test and assign them to a new subset 
    mysubset[[i]] <- mydata[[1]][which(mydata[[1]]$myInter == unique_test[[1]][i]),][["myvalue"]] 
} 

Serait-ce que je dois d'abord lancer ma liste avec les dimensions appropriées? Mais comment ferais-je cela, si les dimensions ne sont pas les mêmes pour tous les éléments de mon ensemble de données (c'est pourquoi je dois utiliser la fonction length() en premier lieu)? Comme vous pouvez le voir mydata [[1]] n'a pas les mêmes dimensions que mydata [[2]]. Par conséquent, les solutions présentées dans les liens suivants ne sont pas applicables à cet ensemble de données:

Error in R :Number of items to replace is not a multiple of replacement length

Error in `*tmp*`[[k]] : subscript out of bounds in R

Je suis sûr qu'il est quelque chose d'évident que je suis absent, mais je ne peux pas le trouver. Toute aide est très appréciée!

S'il existe de meilleurs moyens de réaliser la même chose sans boucle (je suis sûr qu'il y en a, par exemple apply() ou quelque chose dans le sens du sous-ensemble()), j'apprécierais également ces commentaires. Malheureusement, je ne connais pas suffisamment les alternatives pour pouvoir les mettre en œuvre rapidement.

Répondre

1

Enroulez votre mission à list() que vous tentez d'attribuer un vecteur numérique à une liste imbriquée en raison de for boucles imbriquées et non un vecteur lui-même .

mysubset[[i]][j] <- list(mydata[[i]][which(mydata[[i]]$myInter == unique_test[[i]][j]),][["myvalue"]]) 

Ou plus court que which() n'est pas nécessaire, ni entre crochets extérieurs:

mysubset[[i]][j] <- list(mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")]) 

Vous pouvez également envisager une solution appliquer comme vous n'avez pas besoin d'attribuer d'abord une liste vide et développez itérativement pour lui lier des valeurs. lapply, sapply, mapply, même rapply pouvez créer les listes et les dimensions nécessaires en un appel. Le mapply suppose unique_test et mydata sont toujours des objets de longueur égale.

# NESTED LAPPLY 
mysubset2 <- lapply(seq(length(unique_test)), function(i) { 
    lapply(seq(length(unique_test[[i]])), function(j){ 
    mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")] 
    }) 
}) 

# NESTED SAPPLY 
mysubset3 <- sapply(seq(length(unique_test)), function(i) { 
    sapply(seq(length(unique_test[[i]])), function(j){ 
     mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")] 
    }) 
}, simplify = FALSE) 

# NESTED M/LAPPLY 
mysubset4 <- mapply(function(u, m){ 
    lapply(u, function(i) m[m$myInter == i, c("myvalue")]) 
}, unique_test, mydata, SIMPLIFY = FALSE) 

# NESTED R/LAPPLY 
mysubset5 <- rapply(unique_test, function(i){ 
    df <- do.call(rbind, mydata) 
    lapply(i, function(u) df[df$myInter == u, c("myvalue")])  
}, how="list") 

# ALL SUBSETS EQUAL EXACTLY 
all.equal(mysubset, mysubset2) 
# [1] TRUE  
all.equal(mysubset, mysubset3) 
# [1] TRUE  
all.equal(mysubset, mysubset4) 
# [1] TRUE 
all.equal(mysubset, mysubset5) 
# [1] TRUE 
+0

Merci beaucoup! Cela a résolu le problème! – user6475

0

Pouvez-vous publier ce que vous attendez de mysubset? Sur la base de ma compréhension, ce qui devrait sous-ensemble myvalue en utilisant des valeurs dans unique_test:

mysubset <- unique(unlist(lapply(unlist(unique_test),function(x) subset(mydata,myInter==x,select="myvalue"))))