谁能帮我让这个 R 代码更有效率?
我正在尝试编写一个函数,将字符串列表更改为字符串向量,或将数字列表更改为数字向量,将类型化元素列表更改为特定类型的向量。
如果它们具有以下属性,我希望能够将列表更改为特定类型的向量:
它们是同质类型的。列表中的每个元素都是“字符”或“复杂”等类型。
列表的每个元素都是长度为一的。
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”的行为方式。我无法切换到我熟悉的基本函数(例如 unlist),因为我需要为坏列表抛出错误。
require(microbenchmark)
microbenchmark(
as_atomic( as.list(1:1000), 'numeric'),
vapply(1:1000, identity, integer(1)),
unit = 'ns'
)
在我的(相当快的)机器上,基准的频率约为 40Hz,所以这个函数在我的代码中几乎总是速率限制。vapply 控制基准的频率约为 1650Hz,仍然相当慢。
有什么方法可以显着提高此操作的效率吗?任何建议表示赞赏。
如果需要任何澄清或编辑,请在下面发表评论。
编辑:
大家好,
很抱歉很晚才回复;在我可以尝试重新实施之前,我需要参加一些考试。
谢谢大家的性能提示。我使用纯 R 代码将性能从糟糕的 40hz 提高到更可接受的 600hz。
最大的加速来自使用 typeof 或 mode 而不是 is;这确实加快了紧密的内部检查循环。
不过,我可能不得不硬着头皮在 rcpp 中重写它以使其真正发挥作用。