17

所以早些时候我回答了我自己关于在 R 中思考向量的问题。但现在我遇到了另一个我无法“向量化”的问题。我知道向量更快,循环更慢,但我不知道如何在向量方法中做到这一点:

我有一个数据框(出于情感原因,我喜欢将其称为 my.data),我想对其进行全面的边际分析。我需要一次删除某些元素并对数据框“赋值”,然后我需要通过仅删除下一个元素来再次进行迭代。然后再做一次……再一次……这个想法是对我的数据子集进行全面的边际分析。无论如何,我无法想象如何以矢量有效的方式做到这一点。

我已经缩短了代码的循环部分,它看起来像这样:

for (j in my.data$item[my.data$fixed==0]) { # <-- selects the items I want to loop 
                                            #     through
    my.data.it <- my.data[my.data$item!= j,] # <-- this kicks item j out of the list
    sum.data <-aggregate(my.data.it, by=list(year), FUN=sum, na.rm=TRUE) #<-- do an
                                                                         # aggregation

    do(a.little.dance) && make(a.little.love) -> get.down(tonight) # <-- a little
                                                                   #  song and dance

    delta <- (get.love)                                         # <-- get some love
    delta.list<-append(delta.list, delta, after=length(delta.list)) #<-- put my love
                                                                    #    in a vector 
}

所以很明显我在中间砍掉了一堆东西,只是为了让它不那么笨拙。目标是使用更有效的向量来删除 j 循环。有任何想法吗?

4

3 回答 3

9

这似乎是另一种非常 R 型的生成总和的方法。生成一个与输入向量一样长的向量,只包含 n 个元素的重复总和。然后,从 sum 向量中减去原始向量。结果:一个向量(isums),其中每个条目都是您的原始向量减去第 i 个元素。

> (my.data$item[my.data$fixed==0])
[1] 1 1 3 5 7
> sums <- rep(sum(my.data$item[my.data$fixed==0]),length(my.data$item[my.data$fixed==0]))
> sums
[1] 17 17 17 17 17
> isums <- sums - (my.data$item[my.data$fixed==0])
> isums
[1] 16 16 14 12 10
于 2009-01-18T15:12:24.020 回答
9

奇怪的是,学习 R 中的向量化帮助我习惯了基本的函数式编程。一种基本技术是将循环内的操作定义为函数:

data = ...;
items = ...;

leave_one_out = function(i) {
   data1 = data[items != i];
   delta = ...;  # some operation on data1
   return delta;
}


for (j in items) {
   delta.list = cbind(delta.list, leave_one_out(j));
}

要矢量化,您只需将for循环替换为sapply映射函数:

delta.list = sapply(items, leave_one_out);
于 2009-05-07T09:54:05.627 回答
0

这不是答案,但我想知道这个方向是否有任何见解:

> tapply((my.data$item[my.data$fixed==0])[-1], my.data$year[my.data$fixed==0][-1], sum)

tapply 生成按作为第二个参数给出的参数分组的统计信息表(在本例中为总和;第三个参数)。例如

2001 2003 2005 2007
1    3    5    7

[-1] 表示法从选定的行中删除观察(行)之一。因此,您可以循环并在每个循环上使用 [-i]

for (i in 1:length(my.data$item)) {
  tapply((my.data$item[my.data$fixed==0])[-i], my.data$year[my.data$fixed==0][-i], sum)
}

请记住,如果您有任何年份只有 1 次观察,那么连续的 tapply 调用返回的表将不会有相同的列数。(即,如果您放弃 2001 年的唯一观察,那么 2003、2005 和 2007 年将是仅返回的列)。

于 2009-01-16T20:12:55.747 回答