如何为R中的hashmap分配值列表?

时间:2016-02-17 00:57:23

标签: r hashmap

基本上,我们的想法是让值n=10,20,30,...100取10,000个随机样本的平均值,节省10,000个以供日后使用的方法。

在我更习惯使用的语言中,我会使用每个n作为键创建一个hashmap,并使用means列表作为值。

以javascript为例:

var mydata
var map = {}

for (int i = 10; i <= 100; i += 10 ) {
  map[i] = [] // create list
  for (int j = 0; j < 10000; j++) {
    map[i][j] = mean(sample(mydata, i))
  }
}

现在我尝试在R中这样做(这是我第一次使用它),我最终得到了:

hashmap  <- new.env()
sunspots <- read.table("sunspots.txt")

for (i in seq(10, 100, by=10)) {
  hashmap[[i]] <- c()
  for (j in 1:10000) {
    hashmap[[i]][j] <- mean(sample(sunspots$x, i))
  }
}

然而,这会引发错误:

wrong args for environment subassignment

即使它没有抛出这个错误,我也不能完全确定我是否以正确的方式接近它。

有人可以帮我理解正确的方法吗?

2 个答案:

答案 0 :(得分:2)

这里的问题是i是一个数字,环境必须用字符串键入。因此,当i变量用于索引hashmap时,可以通过简单的as.character()强制解决您的直接问题。

我还建议你将内部循环重构为向量化函数调用,例如replicate()。以下是我将如何做到这一点:

set.seed(1L);
test.data <- 1:200;
N <- 3L;
e <- new.env();
for (i in seq(10L,100L,10L)) e[[as.character(i)]] <- replicate(N,mean(sample(test.data,i)));

结果:

ls(e);
##  [1] "10"  "100" "20"  "30"  "40"  "50"  "60"  "70"  "80"  "90"
for (i in seq(10L,100L,10L)) print(e[[as.character(i)]]);
## [1] 108.3 109.4  82.4
## [1] 108.50  93.65 106.20
## [1] 103.3333  96.0000 101.2333
## [1] 98.075 95.250 83.275
## [1] 106.68  97.48 107.34
## [1]  97.48333 105.95000  98.76667
## [1] 101.8857 102.4857 114.6000
## [1]  99.5875 107.0875  96.0750
## [1]  92.9000 103.0889 100.7889
## [1]  91.19  99.80 101.57

您可以将N更改为10000,将test.data更改为sunspots以获取真实数据。

此外,这是一个产生矩阵输出的替代方法,它围绕sapply()的便捷功能构建,它返回来自FUN()的多元素返回值的矩阵:

set.seed(1L);
sapply(seq(10L,100L,10L),function(i) replicate(N,mean(sample(test.data,i))));
##       [,1]   [,2]     [,3]   [,4]   [,5]      [,6]     [,7]     [,8]     [,9]  [,10]
## [1,] 108.3 108.50 103.3333 98.075 106.68  97.48333 101.8857  99.5875  92.9000  91.19
## [2,] 109.4  93.65  96.0000 95.250  97.48 105.95000 102.4857 107.0875 103.0889  99.80
## [3,]  82.4 106.20 101.2333 83.275 107.34  98.76667 114.6000  96.0750 100.7889 101.57

答案 1 :(得分:1)

这不是一样的,但更简单,更易读吗?

set.seed(123)
N = 10000
sunspots <- rnorm(N, 10, 2)

sim <- lapply(seq(10, 100, by=10), function(i){
  sapply(1:N, function(j){
    mean(sample(sunspots, i))
   })
})

lapply(sim, head)

这是有道理的,因为复制只是一个sapply电话。

> replicate
function (n, expr, simplify = "array") 
sapply(integer(n), eval.parent(substitute(function(...) expr)), 
    simplify = simplify)
<bytecode: 0x19b0b7108>
<environment: namespace:base>

编辑

如评论中所述。

simulation <- function(data, i){
  sapply(1:N, function(j) mean(sample(data, i)))
}

sim <- lapply(seq(10, 100, by=10), function(i) simulation(sunspots, i))

# This would give the same output. 
do.call(cbind, lapply(sim, head))

# You could potentially use sapply on the first level also. 
sim <- sapply(seq(10, 100, by=10), function(i) simulation(sunspots, i))

str(sim)