gpt4 book ai didi

r - 有效转换为R中的向量

转载 作者:行者123 更新时间:2023-12-04 16:44:26 25 4
gpt4 key购买 nike

谁能帮助我提高此R代码的效率?

我正在尝试编写一个将字符串列表更改为字符串矢量的函数,或者
通常,数字列表是数字的向量,类型元素列表是某种类型的向量。

我希望能够将列表更改为特定类型的矢量(如果它们具有以下属性):


它们是同类型的。列表中的每个元素的类型均为“字符”或“复杂”
上。
列表中的每个元素长度为1。

as_atomic <- local({

assert_is_valid_elem <- function (elem, mode) {

if (length(elem) != 1 || !is(elem, mode)) {
stop("")
}
TRUE
}

function (coll, mode) {

if (length(coll) == 0) {
vector(mode)
} else {
# check that the generic vector is composed only
# of length-one values, and each value has the correct type.

# uses more memory that 'for', but is presumably faster.
vapply(coll, assert_is_valid_elem, logical(1), mode = mode)

as.vector(coll, mode = mode)
}
}
})



例如,

as_atomic(list(1, 2, 3), 'numeric')
as.numeric(c(1,2,3))

# this fails (mixed types)
as_atomic( list(1, 'a', 2), 'character' )
# ERROR.

# this fails (non-length one element)
as_atomic( list(1, c(2,3,4), 5), 'numeric' )
# ERROR.

# this fails (cannot convert numbers to strings)
as_atomic( list(1, 2, 3), 'character' )
# ERROR.


上面的代码可以正常工作,但是它非常慢,并且我看不出没有对其进行优化的任何方法
函数的行为。重要的是函数“ as_atomic”的行为方式;我不能切换
到我熟悉的基本函数(例如,取消列表),因为我需要为错误列表抛出错误。

require(microbenchmark)

microbenchmark(
as_atomic( as.list(1:1000), 'numeric'),
vapply(1:1000, identity, integer(1)),
unit = 'ns'
)


在我的(相当快)的计算机上,基准测试的频率约为40Hz,因此此功能几乎总是在我的代码中限制速率。 vapply控制基准具有约1650Hz的频率,这仍然相当慢。

有什么方法可以大大提高该操作的效率?任何建议表示赞赏。

如果需要任何澄清或修改,请在下面留下评论。

编辑:

大家好,

很抱歉收到迟来的答复;我必须先参加考试,然后才能尝试
重新实现这一点。

谢谢大家提供的性能提示。我的性能从可怕的40Hz提高到了
使用普通的R代码更可接受的600hz。

最大的加速来自于使用typeof或mode而不是is;这真的加快了
紧密的内部检查循环。

我可能不得不硬着头皮,用rcpp重写它,以使其真正发挥作用。

最佳答案

此问题有两个部分:


检查输入是否有效
将列表强制为向量


检查有效输入

首先,我会避免使用is(),因为众所周知它很慢。这给出了:

check_valid <- function (elem, mode) {
if (length(elem) != 1) stop("Must be length 1")
if (mode(elem) != mode) stop("Not desired type")

TRUE
}


现在,我们需要弄清楚循环还是应用变体更快。
我们将在所有输入均有效的最坏情况下进行基准测试。

worst <- as.list(0:101)

library(microbenchmark)
options(digits = 3)
microbenchmark(
`for` = for(i in seq_along(worst)) check_valid(worst[[i]], "numeric"),
lapply = lapply(worst, check_valid, "numeric"),
vapply = vapply(worst, check_valid, "numeric", FUN.VALUE = logical(1))
)

## Unit: microseconds
## expr min lq median uq max neval
## for 278 293 301 318 1184 100
## lapply 274 282 291 310 1041 100
## vapply 273 284 288 298 1062 100


这三种方法基本上是并列的。 lapply()非常轻微
更快,可能是因为它使用了特殊的C技巧

将列表强制转换为矢量

现在让我们看看将列表强制转换为向量的几种方法:

change_mode <- function(x, mode) {
mode(x) <- mode
x
}

microbenchmark(
change_mode = change_mode(worst, "numeric"),
unlist = unlist(worst),
as.vector = as.vector(worst, "numeric")
)

## Unit: microseconds
## expr min lq median uq max neval
## change_mode 19.13 20.83 22.36 23.9 167.51 100
## unlist 2.42 2.75 3.11 3.3 22.58 100
## as.vector 1.79 2.13 2.37 2.6 8.05 100


因此,看来您已经在使用最快的方法了,
费用以支票为主。

替代方法

另一个想法是,我们可以通过循环来获得更快的速度
在向量上一次,而不是一次检查和一次强制:

as_atomic_for <- function (x, mode) {
out <- vector(mode, length(x))

for (i in seq_along(x)) {
check_valid(x[[i]], mode)
out[i] <- x[[i]]
}

out
}
microbenchmark(
as_atomic_for(worst, "numeric")
)

## Unit: microseconds
## expr min lq median uq max neval
## as_atomic_for(worst, "numeric") 497 524 557 685 1279 100


那绝对更糟。

总而言之,我认为这建议您是否要执行此功能
更快,您应该尝试对Rcpp中的检查功能进行矢量化处理。

关于r - 有效转换为R中的向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22515175/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com