我试图在数据框的最后两列中对整数的数字求和。我找到了一个函数来进行求和,但我想我可能在应用函数时遇到问题 - 不确定吗?
Dataframe
a = c("a", "b", "c")
b = c(1, 11, 2)
c = c(2, 4, 23)
data <- data.frame(a,b,c)
#Digitsum function
digitsum <- function(x) sum(floor(x / 10^(0:(nchar(as.character(x)) - 1))) %% 10)
#Applying function
data[2:3] <- lapply(data[2:3], digitsum)
这是我得到的错误:
*Warning messages:
1: In 0:(nchar(as.character(x)) - 1) :
numerical expression has 3 elements: only the first used
2: In 0:(nchar(as.character(x)) - 1) :
numerical expression has 3 elements: only the first used*
答案 0 :(得分:2)
此时您的函数digitsum
适用于单个标量输入,例如,
digitsum(32)
# [1] 5
但是,它无法进行矢量输入,否则":"
会抱怨。您需要使用Vectorize
:
vec_digitsum <- Vectorize(digitsum)
然后它适用于矢量输入:
b = c(1, 11, 2)
vec_digitsum(b)
# [1] 1 2 2
现在您可以毫无困难地使用lapply
。
答案 1 :(得分:2)
lapply
的问题。虽然我想补充几点:
Vectorize
只是mapply
的包装器,它不能提供矢量化的性能。
可以改进功能本身以提高可读性:
见
digitsum <- function(x) sum(floor(x / 10^(0:(nchar(as.character(x)) - 1))) %% 10)
vec_digitsum <- Vectorize(digitsum)
sumdigits <- function(x){
digits <- strsplit(as.character(x), "")[[1]]
sum(as.numeric(digits))
}
vec_sumdigits <- Vectorize(sumdigits)
microbenchmark::microbenchmark(digitsum(12324255231323),
sumdigits(12324255231323), times = 100)
Unit: microseconds
expr min lq mean median uq max neval cld
digitsum(12324255231323) 12.223 12.712 14.50613 13.201 13.690 96.801 100 a
sumdigits(12324255231323) 13.689 14.667 15.32743 14.668 15.157 38.134 100 a
两个版本的性能相似,但第二个版本更容易理解。
有趣的是,Vectorize
包装器为单个输入增加了相当大的开销:
microbenchmark::microbenchmark(vec_digitsum(12324255231323),
vec_sumdigits(12324255231323), times = 100)
Unit: microseconds
expr min lq mean median uq max neval cld
vec_digitsum(12324255231323) 92.890 96.801 267.2665 100.223 108.045 16387.07 100 a
vec_sumdigits(12324255231323) 94.357 98.757 106.2705 101.445 107.556 286.00 100 a
这个函数的另一个优点是,如果你在字符串格式中有很大的数字,它仍然可以工作(删除as.character
的修改很少)。虽然第一个版本功能会出现大数字问题或者可能会引入错误。
注意:首先我的基准测试是比较OP函数的矢量化版本和我的函数的非矢量化版本,这给了我错误的印象,我的功能要快得多。原来这是由Vectorize
开销引起的。