2017-05-08 3 views
3

J'ai deux trames de données.Supprimer les lignes d'une trame de données qui ont une valeur spécifique dans une ligne correspondante d'une autre trame de données

Le premier contient mes données réelles, appelons-le . La seconde sert de matrice indicatrice, qui est construite en utilisant une instruction if-else qui vérifie l'occurrence d'une ligne de valeurs contenant au moins 1 ou 2, appelons-la indic.

Voici un exemple:

col1<-c(1,3,1,3,2) 
col2<-c(3,4,2,3,"") 
col3<-c(1,3,"","","") 
col4<-c(2,"","","","") 

data<-data.frame(cbind(col1,col2,col3,col4)) 

> data 
    col1 col2 col3 col4 
    1 3 1 2 
    3 4 3  
    1 2   
    3 3   
    2 

Les lignes de données doivent contenir au moins un 1 ou un 2, donc est ma fonction ici:

remove<-function(x){ 

    if (((x[1] == "1") | (x[1] == "2")) | ((x[2] == "1") | (x[2] == "2")) 
     | ((x[3] == "1") | (x[3] == "2")) | ((x[4] == "1") | (x[4] == "2"))){ 
    return(0) 
    } 

else{ 
    return(1) 
} 
} 

indic<-data.frame(apply(data,1,remove)) 

> indic 
     y 
1  0 
2  1 
3  0 
4  1 
5  0 

De regarder données, ligne 2 et ligne 4 ne contiennent pas au moins un 1 ou un 2, ce qui est confirmé par indicateur.

Je souhaite supprimer des lignes 2 et 4 dans données, qui correspondent aux lignes 2 et 4 dans indic. Je l'ai déjà essayé ce qui suit:

finalMatrix<-class(array) 

for(i in 1:nrow(indic)){ 
    if (indic[i,1] == "1"){ 
    finalMatrix = data[-i,] 
    } 
    else{ 
    data[i,] = data[i,] 
    } 
} 

Cependant, ma sortie est quelque chose comme ceci:

> finalMatrix 
    col1 col2 col3 col4 
    1 3 1 2 
    3 4 3  
    1 2     
    2  

qui élimine efficacement la quatrième ligne seulement. Je pense que cela pourrait avoir quelque chose à voir avec le fait que je dois créer une nouvelle base de données après chaque itération, mais le problème est que la longueur de l'itération change. Je me demande si je suis sur la bonne voie avec mon code ... toutes les suggestions seraient ravissantes. Cela fait un moment que je pense à cela.

-Soph

+3

Je ne suis pas sûr de comprendre la question. Voulez-vous quelque chose comme 'finalMatrix <- data [indic! =" 1 ",]'? – Vandenman

+1

'finalMatrix <- data [qui (indic == 0),]' serait également possible dans ce cas –

+1

Pourquoi pas simplement 'data [rowSums (data ==" 1 "| data ==" 2 ")> 0, ] '? Vous n'utilisez pas correctement la vectorisation et cette boucle 'for' est très mauvaise en termes d'efficacité. Aussi, il n'y a aucune raison de forcer vos valeurs à «caractère»; utilisez 'NA' pour les valeurs manquantes. – nicola

Répondre

1

Vous pouvez essayer de générer un vetor VRAI/FAUX au lieu de votre vecteur indic, qui contient 0/1. Cela rend le filtrage final plus évident.

> data 
    col1 col2 col3 col4 
1 1 3 1 2 
2 3 4 3  
3 1 2   
4 3 3   
5 2   

L'utilisation de any vous donnera un accès facile au contenu de la ligne de 1 ou 2. Un deuxième any vous dira si l'une des deux conditions a été remplie. Les apply() les pistes à travers toutes les lignes, si le second paramètre est réglé sur 1.

indic <- apply(data, 1, function(row) { 
    any(c(any(row == 1), any(row == 2))) 
}) 


> indic 
[1] TRUE FALSE TRUE FALSE TRUE 

> data[indic,] 
    col1 col2 col3 col4 
1 1 3 1 2 
3 1 2   
5 2 

Comme le titre de votre question suggère l'indic vecteur pourrait également être appliqué à une autre trame de données, mais ici il est important de faites attention à la trame de données et au vecteur indicateur ayant les mêmes dimensions ou visant le recyclage du vecteur.

Récupérer la suggestion de @ nicola pour utiliser la vectorisation.

data[rowSums(data=="1" | data=="2")>0,] 

Ce serait faire le travail en épargnant le plus efficacement possible les boucles et la création indic. Bien que le vecteur TRUE/FALSE émis par rowSums(data=="1" | data=="2")>0 puisse encore être enregistré dans une variable.