我的数据采用以下格式:
country gdp digits
US 100 2657
Aus 50 123
NZ 40 11
对于每个国家/地区中存储在digits
列中的单个数字,我想取平均值。
这就是我所追求的:
country gdp digits mean_digits
US 100 2657 5
Aus 50 123 2
NZ 40 11 1
我想我应该将digits
列拆分为单独的列中的各个数字,然后取算术平均值,但是我有点不确定,因为不同的行在{{1}中具有不同的位数}字段。
以下可复制数据的代码:
digits
答案 0 :(得分:4)
我们需要一个将数字分解为数字并取均值的函数:
mean_digits = function(x) {
sapply(strsplit(as.character(x), split = "", fixed = TRUE),
function(x) mean(as.integer(x)))
}
df$mean_digits = mean_digits(df$digits)
df
# country gdp digits mean_digits
# 1 US 100 2657 5
# 2 AUS 50 123 2
# 3 NZ 40 11 1
as.character()
将数字输入转换为character
,strsplit
将数字分为单个数字(结果为list
),然后使用sapply
转换为我们将每个列表元素转换为整数并取均值。
我们使用fixed = TRUE
可以提高效率,因为我们不需要任何特殊的正则表达式来将每一位数字分开。
如果您经常使用此功能,则可能要round
或检查输入是否为整数,如果由于NA
而使输入具有小数,它将返回.
答案 1 :(得分:3)
1)捆扎:这种单行代码在gsubfn中使用strapply
。它将每个数字转换为数字,然后取每个数字的平均值。
library(gsubfn)
transform(df, mean = sapply(strapply(digits, ".", as.numeric, simplify = TRUE), mean))
2)这有点长,但仍然是一个语句,不使用任何软件包。它在数字之间插入一个空格,使用read.table
读取它们,然后应用rowMeans
。
transform(df,
mean = rowMeans(read.table(text = gsub("\\b", " ", digits), fill = NA), na.rm = TRUE))
答案 2 :(得分:2)
一种val foo:Future[Result] = aCoupleOfFutures.transform (
options => Created(json.Json.toJson(options)),
exc => exc
)
可能是:
val result:Future[Result] = aCoupleOfFutures. someKindOfTransform {
case Success(options) => Created(json.Json.toJson(options))
case Failure(e) => BadRequest(e.getMessage)
}
或者:
tidyverse
答案 3 :(得分:2)
这里是stringr
的替代方案。它使用sapply
和str_extract_all
来为每一行提取df$digits
的字符并计算平均值。
library(stringr)
df$mean_digits <- sapply(str_extract_all(df$digits, ".{1}"), function(x) mean(as.numeric(x)))
df
country gdp digits mean_digits
1 US 100 2657 5
2 AUS 50 123 2
3 NZ 40 11 1
或者,如果您确实想要,可以使用str_extract_all
和rowMeans
的矩阵输出来完成。注意:对于str_extract_all
,simplify = FALSE
是默认设置。
extracted_mat <- str_extract_all(df$digits, ".{1}", simplify = TRUE)
class(extracted_mat) <- "numeric"
df$mean_digits <- rowMeans(extracted_mat, na.rm = T)
编辑:大规模运行基准测试(即使用@Gregor的示例建议)。
# Packages
library(stringr)
library(gsubfn)
# Functions
mean_digits = function(x) {
sapply(strsplit(as.character(x), split = "", fixed = TRUE),
function(x) mean(as.integer(x)))
}
mnDigit <- function(x) {
n <- nchar(x)
sq <- as.numeric(paste0("1e", n:0))
mean((x %% sq[-length(sq)]) %/% sq[-1])
}
mnDigit2 <- function(a) {
dig <- ceiling(log10(a + 1))
vec1 <- 10^(dig:1)
vec2 <- vec1 / 10
mean((a %% vec1) %/% vec2)
}
# Creating x
set.seed(1)
x = sample(1:1e7, size = 5e5)
microbenchmark::microbenchmark(mnDigit2=sapply(x, mnDigit2),
mnDigit=sapply(x, mnDigit),
stringr=sapply(str_extract_all(x, ".{1}"), function(x) mean(as.numeric(x))),
stringr_matrix = {
extracted_mat <- str_extract_all(x, ".{1}", simplify = TRUE)
class(extracted_mat) <- "numeric"
rowMeans(extracted_mat, na.rm = T)
},
strsplit=mean_digits(x),
rowMeans=rowMeans(read.table(text = gsub("\\b", " ", x), fill = NA), na.rm = TRUE),
#strapply=sapply(strapply(x, ".", as.numeric, simplify=TRUE), mean),
times = 10)
Unit: milliseconds
expr min lq mean median uq max neval cld
mnDigit2 3154.4249 3226.633 3461.847 3445.867 3612.690 3840.691 10 c
mnDigit 6403.7460 6613.345 6876.223 6736.304 6965.453 7634.197 10 d
stringr 3277.0188 3628.581 3765.786 3711.022 3808.547 4347.229 10 c
stringr_matrix 944.5599 1029.527 1136.334 1090.186 1169.633 1540.976 10 a
strsplit 3087.6628 3259.925 3500.780 3416.607 3585.573 4249.027 10 c
rowMeans 1354.5196 1449.871 1604.305 1594.297 1745.088 1828.070 10 b
identical(sapply(x, mnDigit2), sapply(x, mnDigit))
[1] TRUE
identical(sapply(x, mnDigit2), sapply(str_extract_all(x, ".{1}"), function(x) mean(as.numeric(x))))
[1] TRUE
identical(sapply(x, mnDigit2), {
extracted_mat <- str_extract_all(x, ".{1}", simplify = TRUE)
class(extracted_mat) <- "numeric"
rowMeans(extracted_mat, na.rm = T)
})
[1] TRUE
identical(sapply(x, mnDigit2), mean_digits(x))
[1] TRUE
identical(sapply(x, mnDigit2), rowMeans(read.table(text = gsub("\\b", " ", x), fill = NA), na.rm = TRUE))
[1] TRUE
答案 4 :(得分:2)
另一个tidyverse
单线,没有其他依赖项:
df %>% mutate(mean_digits = map_dbl(strsplit(as.character(df$digits), ""),
~ mean(as.numeric(.x))))
# country gdp digits mean_digits
# 1 US 100 2657 5
# 2 AUS 50 123 2
# 3 NZ 40 11 1
strsplit
将数字拆分为一个数字。这会为您提供一个列表,其中每个元素都包含个位数。mean
。在这里,我们使用map_dbl
中的purrr
,但是简单的sapply
也可以解决问题。或基于算术而非字符串拆分的解决方案:
df %>% mutate(mean_digits =
map_dbl(digits,
~ mean((.x %/% 10 ^ (0:(nchar(as.character(.x)) - 1)) %% 10))))
您将每个数字整数(%/%
除以10的幂(即10^0
,10^1
,10^2
,...
,10^i
直到数字位数,然后将结果取10
取模(精确地给您原始位数),然后计算平均值。
split_based <- function(x) {
sapply(strsplit(as.character(x), ""),
function(.x) mean(as.numeric(.x)))
}
## split_based(df$digits)
arithmetic_based <- function(.x) {
mean((.x %/% 10 ^ (0:(nchar(as.character(.x)) - 1)) %% 10))
}
## sapply(df$digits, arithmetic_based)
答案 5 :(得分:2)
使用算术可以更有效地完成此操作。
受this solution的启发,我们可以做到:
mnDigit <- function(x) {
n <- nchar(x)
sq <- as.numeric(paste0("1e", n:0))
mean((x %% sq[-length(sq)]) %/% sq[-1])
}
sapply(df$digits, mnDigit)
# [1] 5 2 1
说明:在函数nchar
中,首先对数字进行计数并创建10
的幂矢量。最后一行基本上以模为单位计算10
的每个幂。
应用链接的答案中提到的“更通用的解决方案”看起来像这样(为修正错误,向 @thothal 致谢):
mnDigit2 <- function(a) {
dig <- ceiling(log10(a + 1))
vec1 <- 10^(dig:1)
vec2 <- vec1 / 10
mean((a %% vec1) %/% vec2)
}
让我们看一下基准:
Unit: milliseconds
expr min lq mean median uq max neval cld
mnDigit2 140.65468 152.48952 173.7740 171.3010 179.23491 248.25977 10 a
mnDigit 130.21340 151.76850 185.0632 166.7446 193.03661 292.59642 10 a
stringr 112.80276 116.17671 129.7033 130.6521 137.24450 149.82282 10 a
strsplit 106.64857 133.76875 155.3771 138.6853 148.58234 257.20670 10 a
rowMeans 27.58122 28.55431 37.8117 29.5755 41.82507 66.96972 10 a
strapply 6260.85467 6725.88120 7673.3511 6888.5765 8957.92438 10773.54486 10 b
split_based 363.59171 432.15120 475.5603 459.9434 528.20592 623.79144 10 a
arithmetic_based 137.60552 172.90697 195.4316 183.1395 208.44365 292.07671 10 a
注意:我删除了tidyverse
解决方案,因为它们太嵌套了其他数据帧操作。
但是,这似乎是否。实际上,rowMeans
-read.table
方法似乎是最快的。
数据
df <- structure(list(country = c("US", "AUS", "NZ"), gdp = c(100, 50,
40), digits = c(2657, 123, 11)), class = "data.frame", row.names = c(NA,
-3L))
基准代码
set.seed(42)
evav <- sample(1:1e5, size=1e4)
library(stringr) # for str_extract_all
library(gsubfn) # for strapply
microbenchmark::microbenchmark(mnDigit2=sapply(evav, mnDigit2),
mnDigit=sapply(evav, mnDigit2),
stringr=sapply(str_extract_all(evav, ".{1}"), function(x) mean(as.numeric(x))),
strsplit=mean_digits(evav),
rowMeans=rowMeans(read.table(text = gsub("\\b", " ", evav), fill = NA), na.rm = TRUE),
strapply=sapply(strapply(evav, ".", as.numeric, simplify=TRUE), mean),
split_based=sapply(evav, split_based),
arithmetic_based=sapply(evav, arithmetic_based),
times=10L,
control=list(warmup=10L))
# see `mean_digits` `split_based` & `arithmetic_based` functions in other answers