2013-05-27 6 views
2

Un de mes trame de données (DF1) a une colonne comme ceci:R fusionner deux trames de données, mais certaines valeurs ont deux points demi dans les

ID 
AB 
CD;EF 
IJ 
KL 
MN 
OP;WX 
WW 
YZ 

L'autre trame de données (DF2) a le format suivant (c'est une table de données très grande):

myIDColumn someName somevalue 
AB gsdfg 123 
CD tfgsdfg 234 
EF sfdgsf 365 
GH gdfgb 53453 
IJ sr 64564 
KL sfsdv 4234234 
MN ewrwe 5 
OP dsfsss 3453 
QR gggg 667 
ST dss 7567 
UV hhhhjf 55 
WX dfadasad 8657 
YZ ghfgh 1234 
ABC gdgfg 234455 
VCB hgjkk 5555667 

Je voudrais fusionner les dataframes en fonction de mon DF1, mais comment puis-je résoudre le problème du point-virgule sur cette jointure paticular. Existe-t-il un moyen de joindre ces données à l'aide d'expressions régulières?

Ma sortie désirée:

ID someName somevalue 
AB gsdfg 123 
CD;EF tfgsdfg,sfdgsf 234,365 
IJ sr 64564 
KL sfsdv 4234234 
MN ewrwe 5 
OP;WX dsfsss,dfadasad 3453,8657 
WW   
YZ dfadasad 8657 
TT 

Toute aide est vraiment apprécié. Merci!

Répondre

4

En deux étapes, similaire à la solution affichée, mais de manière plus compacte.

  1. fusionner les 2 data.frame
  2. transformer ensuite les lignes contenant ";"

Voici le code:

##step1 
mm <- merge(df2,df1,by.y='ID',by.x='myIDColumn',all.y=TRUE) 
## step2 
rr <- do.call(rbind,lapply(strsplit(mm$myIDColumn[grep(';',mm$myIDColumn)],';'), 
     function(x){ 
      res <- paste(df2[df2$myIDColumn==x[1],], 
        df2[df2$myIDColumn==x[2],], 
        sep=',') 
      res[1] <- paste(x,collapse=';') 
      res})) 
mm[grep(';',mm$myIDColumn),] <- rr 

myIDColumn  someName somevalue 
1   AB   gsdfg  123 
2  CD;EF tfgsdfg,sfdgsf 234,365 
3   IJ    sr  64564 
4   KL   sfsdv 4234234 
5   MN   ewrwe   5 
6  OP;WX dsfsss,dfadasad 3453,8657 
7   WW   <NA>  <NA> 
8   YZ   ghfgh  1234 
+0

Merci pour ce code. Lorsque je l'essaie sur mes données réelles, j'obtiens l'erreur suivante: Erreur dans strsplit (mm $ UniProtID [grep (";", mm $ UniProtID)], ";"): argument non-caractère – RnD

+1

Avez-vous essayé de le contraindre à caractère, 'mm $ UniProtID <- as.character (mm $ UniProtID)' – agstudy

+0

merci .. qui a résolu le problème, mais comme je débogue plus loin, je reçois cette erreur: Erreur dans '[<-. data.frame' ('* tmp *', grep (";", mm $ UniProtID),, valeur = c ("P05386; P05387",: remplacement a 6 articles, besoin de 10 – RnD

2

est ici une stratégie qui consiste à séparer df1 en deux nouveaux dataframes (celui que vous allez fusionner pour df2 sorte normalement et qui a des valeurs ID-virgule, ce qui est plus difficile à traiter).

l <- grep(";",df1$ID) # semicolon lines 
nl <- which(!grepl(";",df1$ID)) # non-semicolon lines 

# merge non-semicolon lines 
newdfA <- merge(df1[nl,],df2,all.x=TRUE) 

# merge semicolon lines 
tmpdf1 <- df1[l,] 
split <- strsplit(tmpdf1$ID,";") 

### This seems sloppy, but should work 
newdfB <- data.frame(t(sapply(split, FUN= 
    function(x){ 
    tmprows <- df2[df2$ID %in% x,] 
    return(c( paste0(tmprows[,1],collapse=";"), 
      paste0(tmprows[,2],collapse=","), 
      paste0(tmprows[,3],collapse=","))) 
    }))) 
colnames(newdfB) <- c("ID","someName","someValue") 

# merge everything back together 
newdf <- merge(newdfA, newdfB, all=TRUE) 
4

Voici une solution compacte. Méfiez-vous que tous les champs seront convertis en caractères puisqu'il n'y a pas d'autre moyen de stocker deux entiers dans un élément. Dans le cas où il y a des valeurs dans df1$ID qui manquent dans df2$miIDColumn vous obtiendrez une valeur "character(0)" là.

IDs <- strsplit(df1$ID, ";") 
mrg <- foreach(x=IDs, .combine=rbind) %do% { 
    pieces <- lapply(x, function(y) df2[df2$myIDColumn %in% y,]) 
    do.call(paste, c(pieces, list(sep=","))) 
} 
dimnames(mrg) <- list(NULL, colnames(df2)) 

est ici la sortie (mrg est une matrice BTW):

 myIDColumn  someName   somevalue 
[1,] "AB"   "gsdfg"   "123"  
[2,] "CD,EF"  "tfgsdfg,sfdgsf" "234,365" 
[3,] "IJ"   "sr"    "64564"  
[4,] "KL"   "sfsdv"   "4234234" 
[5,] "MN"   "ewrwe"   "5"   
[6,] "OP,WX"  "dsfsss,dfadasad" "3453,8657" 
[7,] "character(0)" "character(0)" "integer(0)" 
[8,] "YZ"   "ghfgh"   "1234" 
+0

Je suppose que vous utilisez le package 'foreach' ici. Aussi, prenez garde, vous changez le ";" ID à un ',' ceux. +1 parce que je trouve cette solution hors de la boîte. – agstudy

Questions connexes