需要简单的for-loop或lapply解决方案

时间:2016-02-16 19:48:29

标签: r data.table

我有一组如下所示的因素:

v.list <- c('AM','EM','SMH')

我想基于数据集中的先前列计算数据集中的新列,这些列都是由这些标识符之一无意识地定义的。以下是一些示例数据:

height.pre.AM   <- rnorm(10)
height.pre.EM   <- rnorm(10)
height.pre.SMH  <- rnorm(10)
height.post.AM  <- rnorm(10)
height.post.EM  <- rnorm(10)
height.post.SMH <- rnorm(10)
d<- data.table(height.pre.AM,height.pre.EM,height.pre.SMH,height.post.AM,height.post.EM,height.post.SMH)

然后,我想通过列表中的每个标识符计算3个新向量,前向量和后向量之间的高度变化。我可以用3行看起来像这样:

d[,delta_EM  := height.post.EM  - height.pre.EM ]
d[,delta_AM  := height.post.AM  - height.pre.AM ]
d[,delta_SMH := height.post.SMH - height.pre.SMH]

如何使用单行执行此操作,存储为v.list的矢量位于上方?

我尝试了一个构造为:

的for循环
for(i in 1:  length(v.list)){
  v   <- (noquote(paste(v.list[i]))) 
  pre <- paste("d[,delta_",v,":= height.post.",v," - height.pre.",v,"]",sep="")
  cat(noquote(pre), sep="\n")
}

然而,这只是打印线条,而不是执行它们。

5 个答案:

答案 0 :(得分:4)

另一种可能性是首先将数据转换为长格式。使用 data.table 中增强的melt函数,您可以按模式使用多个度量,从而创建多个值列(在本例中为 pre 帖子值列):

melt(d, measure.vars = patterns("pre","post"), 
     value.name = c("height.pre","height.post"))[, variable := v.list[variable]
                                                 ][, delta_height := height.post - height.pre][]

给出:

    variable  height.pre height.post delta_height
 1:       AM  1.51181796  0.20232291   -1.3094951
 2:       AM  0.65902517  0.51772371   -0.1413015
 3:       AM  1.12202807  1.67814321    0.5561151
 4:       AM -0.78464137  0.38524481    1.1698862
 5:       AM -0.42569229 -1.28188722   -0.8561949
 6:       AM  0.39299759 -0.58215074   -0.9751483
 7:       AM  0.03675713  1.77411869    1.7373616
 8:       AM -1.03208366 -0.21067198    0.8214117
 9:       AM -1.26486147 -0.35210691    0.9127546
10:       AM -0.22696529  0.58517233    0.8121376
11:       EM  0.74558930  1.01368470    0.2680954
12:       EM  0.33281918 -0.02256943   -0.3553886
.....

答案 1 :(得分:3)

可能有一种更好的方法,但是我提出的方法似乎有效。您可以在数据表中使用lapply()get()

d[, paste0("delta_", v.list) := lapply(v.list, function(x) {
    s <- sort(grep(x, names(d), fixed = TRUE, value = TRUE)) 
    get(s[1]) - get(s[2]) 
})]

或者,您可以解析并评估某些表达式。

cols <- lapply(v.list, function(x) {
    g <- grep(paste0("p(ost|re)\\.", x), names(d), value = TRUE)
    eval(parse(text = paste(g, collapse = "-")), envir = d)
})

d[, paste0("delta_", v.list) := cols]

答案 2 :(得分:3)

你走了:

for (v in v.list)
  d[, paste0('delta_', v) := get(paste0('height.post.', v)) -
                             get(paste0('height.pre.', v))]

答案 3 :(得分:2)

您可能需要考虑使用dplyrtidyr,因为这些软件包非常适合这些操作并生成可读且整洁的工作流代码。

Vectorize(require)(package = c("dplyr", "tidyr"),
                   character.only = TRUE)
dComplete <- d %>%
    gather(key = indPre, value = valPre, contains("pre")) %>% 
    gather(key = indPost, value = valPost, contains("post")) %>% 
    mutate(diff = valPost - valPre)

预览

数据

set.seed(1)表示可重复性:

原始数据

set.seed1(1)
height.pre.AM   <- rnorm(10)
height.pre.EM   <- rnorm(10)
height.pre.SMH  <- rnorm(10)
height.post.AM  <- rnorm(10)
height.post.EM  <- rnorm(10)
height.post.SMH <- rnorm(10)
d<- data.frame(height.pre.AM, height.pre.EM, height.pre.SMH,
               height.post.AM,height.post.EM,height.post.SMH)

结果预览

> head(dComplete)
         indPre     valPre        indPost    valPost       diff
1 height.pre.AM  0.2426995 height.post.AM -1.0155539 -1.2582534
2 height.pre.AM -0.7978763 height.post.AM  0.7602261  1.5581023
3 height.pre.AM -0.2440429 height.post.AM -1.7585200 -1.5144772
4 height.pre.AM -1.4228071 height.post.AM  0.7663306  2.1891377
5 height.pre.AM  1.6237066 height.post.AM  1.0676800 -0.5560266
6 height.pre.AM  0.3561212 height.post.AM -0.4366372 -0.7927584

如果需要,您可以稍后将spread您的值放入一列;取决于你想如何使用这些数据。

答案 4 :(得分:1)

这是一种方式:

FocusManager

如果你愿意,你可以把它塞进一行,但那不太可读。