Dans df1, je dois remplacer les valeurs de msec par les valeurs correspondantes dans df2.

df1 <- data.frame(ID=c('rs', 'rs', 'rs', 'tr','tr','tr'), cond=c(1,1,2,1,1,2), 
block=c(2,2,4,2,2,4), correct=c(1,0,1,1,1,0), msec=c(456,678,756,654,625,645))

df2 <- data.frame(ID=c('rs', 'rs', 'tr','tr'), cond=c(1,2,1,2), 
block=c(2,4,2,4), mean=c(545,664,703,765))

Dans df1, if correct==0, alors référence df2 avec les valeurs correspondantes de ID, cond et block. Remplacez la valeur de msec dans df1 par la valeur correspondante pour mean dans df2.

Par exemple, la deuxième ligne de df1 contient correct==0. Ainsi, dans df2 trouvez la ligne correspondante où ID=='rs', cond==1, block==2 et utilisez la valeur de mean (mean=545) pour remplacer la valeur de msec ( msec=678). Notez que dans df1, les combinaisons d'ID, de bloc et de cond peuvent se répéter, mais chaque combinaison ne se produit qu'une seule fois dans df2.

r
5
rds 21 avril 2017 à 17:31

2 réponses

Meilleure réponse

Utilisation du package data.table:

# load the 'data.table' package
library(data.table)

# convert the data.frame's to data.table's
setDT(df1)
setDT(df2)

# update df1 by reference with a join with df2
df1[df2[, correct := 0], on = .(ID, cond, block, correct), msec := i.mean]

Qui donne:

> df1
   ID cond block correct msec
1: rs    1     2       1  456
2: rs    1     2       0  545
3: rs    2     4       1  756
4: tr    1     2       1  654
5: tr    1     2       1  625
6: tr    2     4       0  765

Remarque: le code ci-dessus mettra à jour df1 au lieu de créer une nouvelle trame de données, qui est plus efficace en mémoire.

3
Jaap 21 avril 2017 à 16:07

Une option serait d'utiliser la base R avec un interaction() et un match(). Que diriez-vous:

df1[which(df1$correct==0),"msec"] <- df2[match(interaction(df1[which(df1$correct==0),c("ID","cond","block")]), 
                                               interaction(df2[,c("ID","cond", "block")])),
                                         "mean"]

df1
#        ID cond block correct msec
#1 rs    1     2       1  456
#2 rs    1     2       0  545
#3 rs    2     4       1  756
#4 tr    1     2       1  654
#5 tr    1     2       1  625
#6 tr    2     4       0  765 

Nous remplaçons les colonnes correct == 0 par leurs lignes correspondantes dans df2$mean

Modifier: Une autre option serait une fusion SQL qui pourrait ressembler à:

library(sqldf)
merged <- sqldf('SELECT l.ID, l.cond, l.block, l.correct,
                        case when l.correct == 0 then r.mean else l.msec end as msec
                FROM df1 as l
                LEFT JOIN df2 as r
                ON l.ID = r.ID AND l.cond = r.cond AND l.block = r.block')


merged
  ID cond block correct msec
1 rs    1     2       1  456
2 rs    1     2       0  545
3 rs    2     4       1  756
4 tr    1     2       1  654
5 tr    1     2       1  625
6 tr    2     4       0  765
2
Mike H. 21 avril 2017 à 14:47