编写间接引用变量以绕过硬编码的R代码效率低下吗?

时间:2019-06-07 15:57:29

标签: r

假设我有以下数据框:

x <- data.frame(id= c("a", "b", "c", "d", "e")
                , term= c(179, 192, 189, 182, 179)
                , f17= c(1, 2, 3, 4, 5)
                , s18= c(6, 7, 8, 9, 10)
                , f18 = c(11, 12, 13, 14, 15)
                , s19 = c(16, 17, 18, 19, 20))

在此数据框中,我想创建一个变量,该变量记录给定术语的相应列中每个id的值(f17对应术语179,s18对应术语182,f18对应术语189,f19对应至第192期)。

很显然,这可以通过一系列ifelse语句来轻松完成,但是每隔几个月我就会获得新的数据条款,并且我不想每次获得更多数据时都需要手动重新编码。另外,我发现这种带有大量嵌套ifelse语句的编码非常难以阅读。

我对R还是比较陌生,但是我是一个非常有经验的SAS和SAS宏程序员,所以我知道在SAS中,我想要做的事情可以很容易地通过几个数组和一个数据步骤中的do循环来完成。 ,这实际上是我试图在R中重新创建的东西。我最终要做的事情如下。

注意:我意识到下面的内容与一系列嵌套的ifelse语句不同,而是一系列的ifelse语句,以便覆盖相同的变量,但这确实为我提供了解决方案需要,并考虑我数据中的所有情况。

xTerms <- c(179, 182, 189, 192)
xVars <- c("f17", "s18", "f18", "s19")

x$startVal <- NA
for(i in 1:length(xTerms)){
  x$startVal <- ifelse(x$term == xTerms[i], x[[xVars[i]]], x$startVal)
}

我应该添加,这是期望的结果:

> x
  id term f17 s18 f18 s19 startVal
1  a  179   1   6  11  16        1
2  b  192   2   7  12  17       17
3  c  189   3   8  13  18       13
4  d  182   4   9  14  19        9
5  e  179   5  10  15  20        5

上面的代码的想法是,当我获得新数据时,我只需要更新xTerms和xVars的定义。或者,我什至可以根据x中术语变量和x中变量的值的唯一列表动态创建变量。

如果这是解决R中这类迭代问题的最佳方法,我很想从更多有经验的R用户那里获得反馈?您是否可以共享资源,以更好地利用R来进行这类事情?

3 个答案:

答案 0 :(得分:2)

可以使用match ...

xTerms <- c(179, 182, 189, 192)
xVars <- c("f17", "s18", "f18", "s19")

x$startVal <- sapply(1:nrow(x), function(i) x[i, xVars[match(x$term[i], xTerms)]])

x
  id term f17 s18 f18 s19 startVal
1  a  179   1   6  11  16        1
2  b  192   2   7  12  17       17
3  c  189   3   8  13  18       13
4  d  182   4   9  14  19        9
5  e  179   5  10  15  20        5

答案 1 :(得分:2)

如果您将xTermsxVars放在查找表lkp中,则可以使用melt将数据转换为长格式,并与lkp合并以获得起始值。然后,您可以重新加入x并将其添加为列。

library(data.table)
setDT(x)

lkp <- data.table(Terms = xTerms, Vars = xVars)

startvals <- melt(x, c('id', 'term'))[lkp, on = .(term == Terms, variable == Vars)]

x[startvals, on = .(id, term), startVal := value]


x  
#    id term f17 s18 f18 s19 startVal
# 1:  a  179   1   6  11  16        1
# 2:  b  192   2   7  12  17       17
# 3:  c  189   3   8  13  18       13
# 4:  d  182   4   9  14  19        9
# 5:  e  179   5  10  15  20        5

答案 2 :(得分:1)

一种选择是使用row/column索引

x$startVal <- x[3:6][cbind(seq_len(nrow(x)), 
             match(xVars[match(x$term, xTerms)], names(x)[3:6]))]
x
#  id term f17 s18 f18 s19 startVal
#1  a  179   1   6  11  16        1
#2  b  192   2   7  12  17       17
#3  c  189   3   8  13  18       13
#4  d  182   4   9  14  19        9
#5  e  179   5  10  15  20        5