有人能帮我使这段R代码更加高效吗?
我正在尝试编写一个函数,将字符串列表转换为字符串向量,或将数字列表转换为数字向量,将类型元素列表转换为特定类型的向量。
如果列表具有以下属性,我想要将它们更改为特定类型的向量:
They are homogenously typed. Every element of the list is of type 'character', or 'complex' or so on.
Each element of the list is length-one.
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重写它以获得真正的性能。
as.numeric(list(1,2,3))
或as.character
...? - agstudylist(1, 'a', 2)
的预期结果是什么? - agstudy