应用功能不改变原始值

时间:2014-08-10 02:32:09

标签: r

与此页面上的问题相关:Randomly associate elements of two vectors given conditions 如果我有以下数据:

loss=c(45,10,5,1)

capitals = structure(list(capital = c(100L, 50L, 4L, 25L, 5L), loss = c(5L, 
10L, 10L, 1L, 45L)), .Names = c("capital", "loss"), class = "data.frame", row.names = c(NA, 
-5L))

capitals
  capital loss
1     100    5
2      50   10
3       4   10
4      25    1
5       5   45
> 

我正在尝试通过以下命令更正任何有损失>资本的行(从矢量损失中分配另一个随机值,以便损失< =资本):

apply(capitals, 1, function(x){while(x[2]>x[1]) {x[2] = sample(loss,1); print(x[2])} })

print函数显示函数中的值正在变化,但数据框大写中的值没有变化:

apply(capitals, 1, function(x){while(x[2]>x[1]) {x[2] = sample(loss,1); print(x[2])} })
loss 
   5 
loss 
  10 
loss 
  10 
loss 
   1 
loss 
   5 
NULL
> capitals
  capital loss
1     100    5
2      50   10
3       4   10
4      25    1
5       5   45
> 

为什么资本数据框架的价值不会改变,如何纠正?谢谢你的帮助。

1 个答案:

答案 0 :(得分:7)

apply正在评估函数,函数内的赋值不会影响封闭环境。正在修改副本,并在函数退出时销毁该副本。

相反,要使用apply,您应该构建一个对象,让apply返回每个元素。也许是这样的事情:

capitals$loss <- 
     apply(capitals, 1, 
            function(x){
              while(x[2]>x[1]) 
                x[2] <- sample(loss,1)
              x[2]
           }
     )

capitals
##   capital loss
## 1     100    5
## 2      50   10
## 3       4    1
## 4      25    1
## 5       5    5

此处,lossx[2])的新值从函数返回,并由apply收集到向量中。然后将其用于替换数据框中的列。

通过对while的所需子集进行采样,可以在没有loss循环的情况下完成此操作。需要if来确定是否需要抽样:

apply(capitals, 1, 
        function(x)
          if (x[2] > x[1]) 
            sample(loss[loss<=x[1]], 1) 
          else 
            x[2]
 )

更好的是,您可以只替换条件所在的行,而不是使用if

r <- capitals$capital < capitals$loss
capitals[r, 'loss'] <- 
     sapply(capitals[r,'capital'], 
        function(x) sample(loss[loss<=x], 1)
     )

这里,需要替换的行由r表示,并且只修改那些行(这与原始中while的条件相同,但元素的顺序有被交换 - 因此从大于小于大于小于。)。

sapply表达式为这些行循环显示capital的值,并从loss的那些不超过capital值的条目返回单个样本。