2017-02-16 71 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]