在大矩阵中执行单元计算的有效方法

时间:2018-01-17 21:23:36

标签: r binary sapply

我试图从NASA的云掩模中间产品中获得2位8位值。

矩阵的尺寸为3200 x 3248.我必须对数千个数据集进行此转换。

这是我想要进行此转换的数据集之一。 dataset

这是我的代码:

library(binaryLogic)
test = as.logical(c(0,0))
#n_row <- nrow(cmask_1)
n_row <- 100
cmask_2bits  <- matrix(nrow=n_row, ncol=ncol(cmask_1))

t1 <- Sys.time()

for(i in 1:n_row){
  cmask_2bits[i,] <- sapply(cmask_1[i,], function (x) ifelse(identical(as.logical(as.binary(x, n=8)[5:6]), test), 0, 1))
}

t2 <- Sys.time()

time <- difftime(t2, t1)


t1_mthd2 <- Sys.time()

cmask_2bits_mthd2  <- matrix(nrow=n_row, ncol=ncol(cmask_1))

cmask_2bits_mthd2 <- mapply(function (x) 
ifelse(identical(as.logical(as.binary(x, n=8)[5:6]), test), 0, 1), cmask_1[1:n_row,])

cmask_2bits_mthd2 <- matrix(cmask_2bits_mthd2, nrow=n_row, ncol=ncol(cmask_1))

t2_mthd2 <- Sys.time()

time_mthd2 <- difftime(t2_mthd2, t1_mthd2)

time_mthd2 - time

我已尝试使用mapplysapply以及for循环的这两行代码。我想知道ifelse语句是否也可以改进以获得更快的结果。

我的第二个问题是这项工作(获得成千上万的矩阵)是否应该在Hadoop平台上完成。

对于前10行和10列,我的结果应该是这样的:

enter image description here

任何建议都将不胜感激。

编辑:例如,as.binary(15,n = 8)给出结果为 0 0 0 0 1 1 1 1为8位无符号字符。从右边读取这个二进制值,这样我感兴趣的2位就是第3位和第4位,它们是1 1.因为as.binary(15,n = 8)给了我一个&#34;二进制&#34; &#34;逻辑&#34;向量,我可以通过请求此代码结果的第5和第6个值来获取这些位。

3 个答案:

答案 0 :(得分:1)

对于更广泛的问题,当对每个单元的操作相同时,对大矩阵进行单元操作的最有效方法是使用内置向量化操作。 R中的矩阵实际上只是一个带有一些维度元数据的向量。对于您的特定问题,除了向量化之外,看起来binaryLogic.asBinary的计算效率不高。对于第5位和第6位在8位整数中为零的简单情况,只需使用整数数学:

(((cmask_1 %% 128) %% 64) < 16) + 0

模数清零第7位和第8位,并且从那里第5位和第6位等于零的所有值将小于16.将0添加到结果将逻辑矢量转换为0/1。

编辑:回顾一下您的示例,当第5位和第6位都为零时,您希望结果为零。那将是:

(((cmask_1 %% 128) %% 64) > 15) + 0

答案 1 :(得分:1)

我认为最快的方法是使用按位逻辑运算符。如果要从整数X中提取第3位和第4位,可以使用“X AND 12”(4 + 8 = 12)。结果,如果第3位置位则为“4”,第4位为“8”,第3和第4位置为“12”。

在R中有一个“bitops”包,它支持你需要的操作:

library(bitops)
mat_cmask = as.matrix(df_cmask)
v = as.vector(mat_cmask, mode="integer")
v1 = bitAnd(v, 12) # there are still values 4, 8 and 12
v2 = as.integer(v1>0)
result = matrix(v2, nrow=nrow(cmask), ncol(cmask)) 
result[1:10, 1:10]

Best,Stefan

答案 2 :(得分:0)

感谢@W。墨菲为这个简单明了的答案。整数除法后的正确答案应为

(((((((cmask_1 %% 256)%% 128)%% 64)%% 32)%% 16)&lt; 16)&amp;(3&lt;(((((cmask_1 %% 256) )%% 128)%% 64)%% 32)%% 16)))+ 0,

我想限制3到16之间的余数,这样在这个区间内的数字将除以8或4或两者。

再次感谢。

相关问题