2015-12-09 2 views
1

J'ai deux trames de données df1 et df2.R: comment sélectionner des données à partir d'une trame de données en fonction de règles spécifiques et ajouter les données en tant que nouvelles colonnes à une trame de données existante

df1 <- data.frame(x1=c("A35", "A41", "A49"), 
        x2=c(8, 24, 33), 
        x3=c(15, 63, 54)) 

df2 <- data.frame(y1=c("A35", "A38", "A41", "A41", "A49"), 
        y2 = c(9, 20, 24, 32, 84)) 

Je veux sélectionner les lignes de la DF2 en fonction des trois critères suivants

(1) Le y1 de DF2 correspond x1 de DF1;

(2) Le y2 de DF2> = x2 de DF1

(3) Le y2 de DF2 = < x3 de DF1

La réunion de données, les critères seront ajoutés à DF1 de nouvelles colonnes. Si la ou les lignes de df1 ont plus d'une correspondance, ces correspondances supplémentaires seront également ajoutées en tant que nouvelles colonnes.

Les résultats attendus sont

data.frame(x1=c("A35", "A41", "A49"), 
      x2=c(8, 24, 33), 
      x3=c(15, 63, 54), 
      z1 = c("A35", "A41", ""), 
      z2 = c(9, 24,""), 
      z3 = c("", "A41", ""), 
      z4 = c("", 32, "")) 

x1 x2 x3 z1 z2 z3 z4 
A35 8 15 A35 9 
A41 24 63 A41 24 A41 32 
A49 33 54 

Merci à l'avance!

+0

Pourquoi 'df2' ont 5 lignes, mais la trame de données résultante a seulement 4 nouvelles colonnes? –

+0

df2 a 5 lignes, mais seulement 3 lignes correspondent à df1. La ligne 1 de df1 a une correspondance df2 et la ligne 2 de df1 a deux correspondances df2. La correspondance de ligne 1 et la première correspondance de ligne 2 de df2 sont ajoutées en tant que nouvelles colonnes (z1, z2). La deuxième ligne 2 correspond aux nouvelles colonnes (z3 et z4). J'espère que je l'ai clarifié. – mi3567

+0

comment pouvez-vous comparer y2 de df2> = x2 de df1 s'il y a plus de valeurs y2 que de valeurs x2? vous ne pouvez pas aller élément par élément ... ou êtes-vous en train de dire que la condition 1 est vraie, alors la condition 2 et 3 doivent également être maintenues. ou est-ce que 1 ou 2 ou 3 doit tenir? –

Répondre

0

si je comprends bien votre question cela devrait fonctionner:

### we use the matches to pick our values from df1 
### we use our conditions to pick our values from df2 
matches <- match(df2$y1,df1$x1) 
matches <- matches[!is.na(matches)] 
condition1 <- df2$y1 %in% df1$x1 
condition2 <- df2$y2[condition1] >= df1$x2[matches] 
condition3 <- df2$y2[condition1] <= df1$x3[matches] 

### i create these tmp variables so you can see step by step 
### what each line of code is doing 
### here i am finding the values that meet all the conditions 
### then i am pulling the associated y2 values 
tmp <- data.frame(x1=df1$x1[matches],y2=df2$y2[condition1]) 
tmp <- tmp[condition2&condition3,] 
tmp <- droplevels(tmp) 

### now that we have the values we want 
### we are organizing the data in the desired output you 
### specified. 
x <- split(tmp[-1], tmp[[1]]) 
tmp2 <- data.frame() 
for(i in 1:length(x)){ 

    df <- data.frame(t(unlist(x[[i]], use.names=FALSE))) 
    colnames(df) <- seq(1,nrow(x[[i]])) 
    tmp2 <- rbind.fill(tmp2,df) 

} 
colnames(tmp2) <- paste(rep("z",ncol(tmp2)),1:ncol(tmp2),sep="") 
res <- data.frame(df1[df1$x1 %in% names(x),],tmp2) 
res <- rbind.fill(res,df1[!df1$x1 %in% names(x),]) 

>res 
    x1 x2 x3 z1 z2 
1 A35 8 15 9 NA 
2 A41 24 63 24 32 
3 A49 33 54 NA NA 
0

Il n'est pas vraiment recommandé de travailler avec des données de longueur inégale, l'utilisation de listes devrait fonctionner mieux à cette fin.

J'ai créé un code qui fait le travail, même si je ne suis pas sûr que ce soit le moyen le plus efficace.

Vous devez d'abord comparer chaque ligne des deux données. Cela peut être fait en utilisant une fonction apply au sein d'une fonction apply (fondamentalement: pour chaque ligne de df1, comparez avec chaque ligne de df2) et en retournant les valeurs correspondantes, avec leur index.

Cela sera stocké dans une liste désordonnée pleine d'éléments vides qui ne correspondent pas. Ainsi, après avoir nettoyé la liste, les résultats obtenus peuvent être ajoutés à chaque ligne individuelle de df1 en utilisant la fonction spply.

df1 <- data.frame(x1=c("A35", "A41", "A49"), 
       x2=c(8, 24, 33), 
       x3=c(15, 63, 54)) 

df2 <- data.frame(y1=c("A35", "A38", "A41", "A41", "A49"), 
        y2 = c(9, 20, 24, 32, 84)) 

matches <- apply(df2,1,function(x) apply(df1,1,function(y) 
    if(x[1]==y[1]&&x[2]>=y[2]&&x[2]<=y[3]){ 
    c(which(df1==x[1]),x[1:2]) 
    })) 
addedelem <- t(array(unlist(matches), dim=c(3,length(unlist(matches))/3))) 
result <- sapply(1:length(df1$x1), function(x) (c(as.matrix(df1[x,]),t(addedelem[which(addedelem[,1]==x),2:3])))) 

La liste qui en résulte est ce que vous cherchez. Si nécessaire, vous pouvez le transformer à nouveau en un dataframe.

> result 
[[1]] 
[1] "A35" "8" "15" "A35" " 9" 

[[2]] 
[1] "A41" "24" "63" "A41" "24" "A41" "32" 

[[3]] 
[1] "A49" "33" "54"