计算数据框特定列中的数字和

Compute digit-sums in specific columns of a data frame

我正在尝试对数据框最后两列中的整数位求和。我找到了一个可以求和的函数,但我想我在应用该函数时可能会遇到问题 - 不确定?

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*

您的函数 digitsum 目前可以很好地处理单个标量输入,例如

digitsum(32)
# [1] 5

但是,它不能接受向量输入,否则":"会报错。您需要使用 Vectorize:

向量化此函数
vec_digitsum <- Vectorize(digitsum)

然后它适用于矢量输入:

b = c(1, 11, 2)
vec_digitsum(b)
# [1] 1 2 2

现在您可以毫无问题地使用 lapply

@Zheyuan Li 的回答解决了你使用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 开销引起的。