我有一个包含n行观察的矩阵。观察是特征的频率分布。我想将频率分布转换为概率分布,其中每行的总和为1.因此,矩阵中的每个元素应除以元素行的总和。
我编写了以下R函数来完成这项工作但是对于大型矩阵来说它非常慢:
prob_dist <- function(x) {
row_prob_dist <- function(row) {
return (t(lapply(row, function(x,y=sum(row)) x/y)))
}
for (i in 1:nrow(x)) {
if (i==1) p_dist <- row_prob_dist(x[i,])
else p_dist <- rbind(p_dist, row_prob_dist(x[i,]))
}
return(p_dist)
}
B = matrix(c(2, 4, 3, 1, 5, 7), nrow=3, ncol=2)
B
[,1] [,2]
[1,] 2 1
[2,] 4 5
[3,] 3 7
prob_dist(B)
[,1] [,2]
[1,] 0.6666667 0.3333333
[2,] 0.4444444 0.5555556
[3,] 0.3 0.7
你能否建议R功能完成这项工作和/或告诉我如何优化我的功能以更快地执行?
答案 0 :(得分:5)
这是一次尝试,但是在数据框而不是矩阵上:
df <- data.frame(replicate(100,sample(1:10, 10e4, rep=TRUE)))
我尝试了dplyr
方法:
library(dplyr)
df %>% mutate(rs = rowSums(.)) %>% mutate_each(funs(. / rs), -rs) %>% select(-rs)
结果如下:
library(microbenchmark)
mbm = microbenchmark(
dplyr = df %>% mutate(rs = rowSums(.)) %>% mutate_each(funs(. / rs), -rs) %>% select(-rs),
t = t(t(df) / rep(rowSums(df), each=ncol(df))),
apply = t(apply(df, 1, prop.table)),
times = 100
)
#> mbm
#Unit: milliseconds
# expr min lq mean median uq max neval
# dplyr 123.1894 124.1664 137.7076 127.3376 131.1523 445.8857 100
# t 384.6002 390.2353 415.6141 394.8121 408.6669 787.2694 100
# apply 1425.0576 1520.7925 1646.0082 1599.1109 1734.3689 2196.5003 100
编辑:@David基准测试更符合OP,所以我建议你考虑他的方法,如果你要使用矩阵。
答案 1 :(得分:4)
没有应用,一行中的矢量化解决方案:
t(t(B) / rep(rowSums(B), each=ncol(B)))
[,1] [,2]
[1,] 0.6666667 0.3333333
[2,] 0.4444444 0.5555556
[3,] 0.3000000 0.7000000
或者:
diag(1/rowSums(B)) %*% B
答案 2 :(得分:2)
实际上我给了它一个快速的想法,最好的归化就是
B/rowSums(B)
# [,1] [,2]
# [1,] 0.6666667 0.3333333
# [2,] 0.4444444 0.5555556
# [3,] 0.3000000 0.7000000
实际上@Stevens基准测试具有误导性,因为OP有一个矩阵,而Steven基准测试数据框。
这是一个带矩阵的基准。因此,对于矩阵,两个向量化解决方案都将优于不使用矩阵的dplyr
set.seed(123)
m <- matrix(sample(1e6), ncol = 100)
library(dplyr)
library(microbenchmark)
Res <- microbenchmark(
dplyr = as.data.frame(m) %>% mutate(rs = rowSums(.)) %>% mutate_each(funs(. / rs), -rs) %>% select(-rs),
t = t(t(m) / rep(rowSums(m), each=ncol(m))),
apply = t(apply(m, 1, prop.table)),
DA = m/rowSums(m),
times = 100
)
答案 3 :(得分:0)
我不确定您的函数是否有任何价值,因为您可以使用hist
或density
函数来完成相同的结果。此外,使用apply
将如上所述。但它可以作为一个合理的编程示例。
您的代码中存在一些效率低下的问题。
您正在使用rbind
而不是为输出预先分配空间。这也非常昂贵。
out <- matrix(NA, nrow= n, ncol= ncol(B))
for (i in 1:nrow(B)) {
out[i,] <- row_prob_dist(B[i,])
}