2017-02-16 84 views
5

让我们创建示例数据:映射值画面R

df <- data.frame(date=c("2017-01-01","2017-01-02", "2017-01-03", "2017-01-04", "2017-01-05"), X1=c("A", "B", "C", "D", "F"), 
       X2=c("B", "A", "D", "F", "C")) 
df2 <- data.frame(date=c("2017-01-01","2017-01-02", "2017-01-03", "2017-01-04", "2017-01-05"), 
        A=c("3", "4", "2", "1", "5"), 
        B=c("6", "2", "5", "1", "1"), 
        C=c("1", "4", "5", "2", "3"), 
        D=c("67", "67", "63", "61", "62"), 
        F=c("31", "33", "35", "31", "38")) 

所以,我有两个数据帧,我要匹配DF2值按日期和X1,X2为DF和创造这些新的变量。对我来说这很棘手的问题是,df2中的匹配值是在colname中。最终的结果应该是这样的:

> result 
     date X1 X2 Var1 Var2 
1 2017-01-01 A B 3 6 
2 2017-01-02 B A 2 4 
3 2017-01-03 C D 5 63 
4 2017-01-04 D F 61 31 
5 2017-01-05 F C 38 3 

result <- data.frame(date=c("2017-01-01","2017-01-02", "2017-01-03", "2017-01-04", "2017-01-05"), 
        X1=c("A", "B", "C", "D", "F"), 
        X2=c("B", "A", "D", "F", "C"), 
        Var1=c("3", "2", "5", "61", "38"), 
        Var2=c("6", "4", "63", "31", "3")) 

我想用mapvalues,但不能弄明白。第二个想法是用df2进行长格式化(融化),然后尝试,但是在那里也失败了。

好吧,这里是我最好的尝试,只是觉得可以有更高效的方式,如果你必须创建多个(> 50)新的变量数据框架。

df2.long <- melt(df2, id.vars = c("date")) 

df$Var1 <- na.omit(merge(df, df2.long, by.x = c("date", "X1"), by.y = c("date", "variable"), all.x = FALSE, all.y = TRUE))[,4] 
df$Var2 <- na.omit(merge(df, df2.long, by.x = c("date", "X2"), by.y = c("date", "variable"), all.x = FALSE, all.y = TRUE))[,5] 
+0

所有好的答案,非常感谢! – Viitama

回答

2

与一种可能性:

df$Var1 <- mapply(function(day, col) df2[df2$date==day, as.character(col)], 
        day=df$date, col=df$X1) 
df$Var2 <- mapply(function(day, col) df2[df2$date==day, as.character(col)], 
        day=df$date, col=df$X2) 

df 
#  date X1 X2 Var1 Var2 
#1 2017-01-01 A B 3 6 
#2 2017-01-02 B A 2 4 
#3 2017-01-03 C D 5 63 
#4 2017-01-04 D F 61 31 
#5 2017-01-05 F C 38 3 

NB:
如果你有更多的列进行修改(不只是喜欢在你的例子),你可以使用lapply遍历列X.

df[, paste0("Var", 1:2)] <- lapply(df[,paste0("X", 1:2)], 
            function(value) { 
             mapply(function(day, col) df2[df2$date==day, as.character(col)], 
              day=df$date, col=value)}) 
+1

是的,谢谢。因为我的原始数据是data.table data.frame,所以我已经头疼了,所以函数只返回X1到新变量,但是只把它转换成数据帧。我无法理解为什么。 – Viitama

+0

@Viitama如果你真的在使用'data.table's,David的答案可能更合适。 – Cath

+0

我是noob,当它从一个变为另一个时,我不会。如果没有匹配,我应该怎么做才能获得NA而不是'numeric(0)'。我以后可以随时纠正它们,或者从中构建一个函数,但是我可以在mapply里面做些什么? – Viitama

2

我们可以使用match从“X1”和“X2”栏目,cbind与行的顺序获得“DF2”的列索引,使用行/列索引中提取的价值“ DF2' ,并分配输出以创建 '瓦尔' 列

df[paste0("Var", 1:2)] <- lapply(df[2:3], function(x) 
      df2[-1][cbind(1:nrow(df2), match(x, names(df2)[-1]))]) 
df 
#  date X1 X2 Var1 Var2 
#1 2017-01-01 A B 3 6 
#2 2017-01-02 B A 2 4 
#3 2017-01-03 C D 5 63 
#4 2017-01-04 D F 61 31 
#5 2017-01-05 F C 38 3 
+1

为了说明顺序不匹配的日期,我猜可能是'i = match(df $ date,df2 $ date); ... cbind(我,匹配(..))''(而不是'1:nrow') –

4

使用dplyrtidyr

df2_m <- group_by(df2, date) %>% 
    gather('X1', 'var', -date) 

left_join(df, df2_m) %>% 
    left_join(df2_m, by = c('date', 'X2' = 'X1')) %>% 
    rename(Var1 = var.x, Var2 = var.y) -> result 
3

使用data.table

library(data.table) # v>=1.10.0 
dcast(
    melt(setDT(df), 1L)[ # melt the first table by date 
    melt(setDT(df2), 1L), # melt the second table by date 
    on = .(date, value = variable), # join by date and the letters 
    nomatch = 0L], # remove everything that wasn't matched 
    date ~ variable, # convert back to long format 
    value.var = c("value", "i.value")) # take both values columns 

#   date value_X1 value_X2 i.value_X1 i.value_X2 
# 1: 2017-01-01  A  B   3   6 
# 2: 2017-01-02  B  A   2   4 
# 3: 2017-01-03  C  D   5   63 
# 4: 2017-01-04  D  F   61   31 
# 5: 2017-01-05  F  C   38   3 
+0

不错,只是打败了我 – C8H10N4O2

1
利用熔融和匹配

df2l<-melt(df2, measure=c("A","B","C","D","F")) 
Indices <- match(paste(df$date, df$X1), paste(df2l$date,df2l$variable)) 
df$Var1 <- df2l$value[Indices] 
Indices2 <- match(paste(df$date, df$X2), paste(df2l$date,df2l$variable)) 
df$Var2 <- df2l$value[Indices2]