Vlookup-match就像R中的函数一样

时间:2015-07-12 09:59:33

标签: r dataframe lookup

我对R来说很陌生,而且我目前正在应用我对R必须进行分析工作的一点知识。

我有两个数据框 - 数据框A包含交易详情,而数据框B包含各种货币的每月结算汇率。

数据框A - 交易详情

    TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY  LODG_DATE
1           0001              INR         305000 Mar 2014 2014-03-01
2           0002              USD          15000 Oct 2014 2014-10-31
3           0003              JPY          85000 Feb 2015 2015-02-09
4           0004              CNY        1800000 Mar 2015 2015-03-27

structure(list(TRANSACTION_ID = c("0001", "0002", "0003", "0004"), 
COLLECTION_CRNCY = c("INR", "USD", "JPY", "CNY"), COLLECTION_AMT = c(305000, 
15000, 85000, 1800000), MMYYYY = structure(c(2014.16666666667, 
2014.75, 2015.08333333333, 2015.16666666667), class = "yearmon"),
LODG_DATE = structure(c(16130, 16374, 16475, 16521), class = "Date")), 
row.names = c(NA, -4L), class = "data.frame")

数据框B - 汇率

    MMYYYY       Date    CNY    INR     JPY       USD
1 Mar 2014 2014-03-31 4.9444 47.726 82.0845 0.7951654
2 Oct 2014 2014-10-31 4.7552 47.749 87.2604 0.7778469
3 Feb 2015 2015-02-27 4.5990 45.222 87.7690 0.7338372
4 Mar 2015 2015-03-31 4.5179 45.383 87.5395 0.7287036

structure(list(MMYYYY = structure(c(2014.16666666667, 
2014.75, 2015.08333333333, 2015.16666666667), class = "yearmon"), 
Date = structure(c(16160, 16374, 16493, 16525), class = "Date"), CNY = 
c(4.9444, 4.7552, 4.599, 4.5179), INR = c(47.726, 47.749, 45.222, 45.383), 
JPY = c(82.0845, 87.2604, 87.769, 87.5395), USD = c(0.795165394, 0.77784692, 
0.733837235, 0.728703636)), .Names = c("MMYYYY", "Date", "CNY", "INR", "JPY", 
"USD"), class = "data.frame", row.names = c(NA, -4L))

我想要做的是在数据框A中创建一个可能名为Exchange Rate的新列。我希望通过将数据框A中的COLLECTION_CRNCYMMYYYY与数据框B相匹配来查看数据框B来获得此汇率值。即:

TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY  LODG_DATE exchange.rate
1           0001              INR         305000 Mar 2014 2014-03-01    47.7260000
2           0002              USD          15000 Oct 2014 2014-10-31     0.7778469
3           0003              JPY          85000 Feb 2015 2015-02-09    87.7690000
4           0004              CNY        1800000 Mar 2015 2015-03-27     4.5179000

我可以使用vlookup和匹配通过Excel轻松完成此操作,但我想知道如何使用R来实现相同的结果,因为我的交易详细信息文件非常庞大。

4 个答案:

答案 0 :(得分:4)

这是一种可能的data.table方法。基本上你需要做的是将df2转换为长格式,然后将一个简单的(二进制)左连接转换为df1

library(data.table)
temp <- melt(setDT(df2[-2]), "MMYYYY", variable.name = "COLLECTION_CRNCY")
setkey(setDT(df1), MMYYYY, COLLECTION_CRNCY)[temp, exchange.rate := i.value]
df1
#    TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY  LODG_DATE exchange.rate
# 1:           0001              INR         305000 2014.167 2014-03-01    47.7260000
# 2:           0002              USD          15000 2014.750 2014-10-31     0.7778469
# 3:           0003              JPY          85000 2015.083 2015-02-09    87.7690000
# 4:           0004              CNY        1800000 2015.167 2015-03-27     4.5179000

或者,您可以使用“Hadleyverse”执行类似操作,但dplyr无法在zoo类列上合并(暂时),因此您需要先将其取消分类< / p>

library(dplyr)
library(tidyr)
df2[-2] %>% 
  gather(COLLECTION_CRNCY, exchange.rate, -MMYYYY) %>%
  mutate(MMYYYY = as.numeric(MMYYYY)) %>%
  left_join(df1 %>% mutate(MMYYYY = as.numeric(MMYYYY)), .,
                           by = c("MMYYYY", "COLLECTION_CRNCY"))
#   TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY  LODG_DATE exchange.rate
# 1           0001              INR         305000 2014.167 2014-03-01    47.7260000
# 2           0002              USD          15000 2014.750 2014-10-31     0.7778469
# 3           0003              JPY          85000 2015.083 2015-02-09    87.7690000
# 4           0004              CNY        1800000 2015.167 2015-03-27     4.5179000

答案 1 :(得分:1)

您可以使用Rapply使用基础merge来解决此问题。

要解决问题,

  1. 将两个数据集合并在一起
  2. 提取相关专栏
  3. <强> 1

    要合并数据,只需使用:

    merge(dfa, dfb, by="MMYYYY")

    2

    要提取相关字段,我们可以按行方式使用apply函数。

    apply(df, 1, function(x) ...)

    其中df是data.frame,1以行方式发出信号。

    总而言之,我们可以像这样在一行中提取汇率:

    dfa$exchange.rate <- apply(df, 1, function(x) x[x[['COLLECTION_CRNCY']]])

    x[x[['COLLECTION_CRNCY']]]行正在做的只是查找列COLLECTION_CRNCY,然后使用该值查询相应的货币列。

    最终代码:

    dfa$exchange.rate <- apply(merge(dfa, dfb, by="MMYYYY"), 1, function(x) x[x[['COLLECTION_CRNCY']]])
    dfa$exchange.rate <- as.numeric(dfa$exchange.rate) # since it isn't numeric format.
    #    TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY  LODG_DATE exchange.rate
    #  1           0001              INR         305000 2014.167 2014-03-01    47.7260000
    #  2           0002              USD          15000 2014.750 2014-10-31     0.7778469
    #  3           0003              JPY          85000 2015.083 2015-02-09    87.7690000
    #  4           0004              CNY        1800000 2015.167 2015-03-27     4.5179000
    

答案 2 :(得分:1)

另一种参考方式:

res <- numeric(nrow(dfA))
for(i in seq_len(nrow(dfA))) {
    res[i] <- dfB[match(dfA$MMYYYY[i], dfB$MMYYY), 
                  match(dfA$COLLECTION_CRNCY[i], names(dfB))]}
dfA$Exchange<- res
#   TRANSACTION_ID COLLECTION_CRNCY COLLECTION_AMT   MMYYYY
# 1           0001              INR         305000 2014.167
# 2           0002              USD          15000 2014.750
# 3           0003              JPY          85000 2015.083
# 4           0004              CNY        1800000 2015.167
#    LODG_DATE   Exchange
# 1 2014-03-01 47.7260000
# 2 2014-10-31  0.7778469
# 3 2015-02-09 87.7690000
# 4 2015-03-27  4.5179000

答案 3 :(得分:0)

可以使用reshape()从宽格式转换为长格式。它可能是R中最烦人的功能,但是如果你足够长时间玩它的选项,你通常可以到达你想去的地方。一旦你有长格式的B,对merge()的简单调用就会获得所需的输出。

B.id <- c('MMYYYY','Date');
B.time <- setdiff(names(B),B.id);
B.long <- reshape(B,dir='l',idvar=B.id,varying=B.time,times=B.time,timevar='COLLECTION_CRNCY',v.names='exchange.rate',new.row.names=1:(length(B.time)*nrow(B)));
B.long;
##      MMYYYY       Date COLLECTION_CRNCY exchange.rate
## 1  2014.167 2014-03-31              CNY     4.9444000
## 2  2014.750 2014-10-31              CNY     4.7552000
## 3  2015.083 2015-02-27              CNY     4.5990000
## 4  2015.167 2015-03-31              CNY     4.5179000
## 5  2014.167 2014-03-31              INR    47.7260000
## 6  2014.750 2014-10-31              INR    47.7490000
## 7  2015.083 2015-02-27              INR    45.2220000
## 8  2015.167 2015-03-31              INR    45.3830000
## 9  2014.167 2014-03-31              JPY    82.0845000
## 10 2014.750 2014-10-31              JPY    87.2604000
## 11 2015.083 2015-02-27              JPY    87.7690000
## 12 2015.167 2015-03-31              JPY    87.5395000
## 13 2014.167 2014-03-31              USD     0.7951654
## 14 2014.750 2014-10-31              USD     0.7778469
## 15 2015.083 2015-02-27              USD     0.7338372
## 16 2015.167 2015-03-31              USD     0.7287036
merge(A,B.long[c('MMYYYY','COLLECTION_CRNCY','exchange.rate')],all.x=T);
##   COLLECTION_CRNCY   MMYYYY TRANSACTION_ID COLLECTION_AMT  LODG_DATE exchange.rate
## 1              CNY 2015.167           0004        1800000 2015-03-27     4.5179000
## 2              INR 2014.167           0001         305000 2014-03-01    47.7260000
## 3              JPY 2015.083           0003          85000 2015-02-09    87.7690000
## 4              USD 2014.750           0002          15000 2014-10-31     0.7778469