新手问题:这个关于大约50K元素的data.frame的双循环慢慢评估非常,花费超过30秒。我在网上看到我应该使用某种形式的apply函数来解决这个问题,但到目前为止还无法使代码正确。从第一个获得结果的data.frame开始,目标是获得第二个data.frame,其中只填充大于目标的值,其他所有值都为0.
此代码有效:
ExcessGain = function(Value, Target){
max(0,Value - Target)
}
Pcnt_O_O_x = data.frame()
for (j in 1:ncol(Pcnt_O_O)){
for (i in 1:nrow(Pcnt_O_O)){
Pcnt_O_O_x[i,j] = ExcessGain(Pcnt_O_O[i,j], GainTargetPcnt)
}
}
我可以使用apply函数而不是内部循环以某种方式加快速度吗?
答案 0 :(得分:3)
您的函数看起来只是从数组中每个单元格的值中减去目标值。任何负值都替换为0.在这种情况下,您不需要任何循环,您可以使用R的内置向量化来执行此操作:
set.seed(123)
# If you have a data.frame of all numeric elements turn it into a matrix first
df <- as.matrix( data.frame( matrix( runif(25) , nrow = 5 ) ) )
target <- 0.5
df
# X1 X2 X3 X4 X5
#1 0.2875775 0.0455565 0.9568333 0.89982497 0.8895393
#2 0.7883051 0.5281055 0.4533342 0.24608773 0.6928034
#3 0.4089769 0.8924190 0.6775706 0.04205953 0.6405068
#4 0.8830174 0.5514350 0.5726334 0.32792072 0.9942698
#5 0.9404673 0.4566147 0.1029247 0.95450365 0.6557058
df2 <- df - target
df2
# X1 X2 X3 X4 X5
#1 -0.21242248 -0.45444350 0.45683335 0.3998250 0.3895393
#2 0.28830514 0.02810549 -0.04666584 -0.2539123 0.1928034
#3 -0.09102308 0.39241904 0.17757064 -0.4579405 0.1405068
#4 0.38301740 0.05143501 0.07263340 -0.1720793 0.4942698
#5 0.44046728 -0.04338526 -0.39707532 0.4545036 0.1557058
df2[ df2 < 0 ] <- 0
df2
# X1 X2 X3 X4 X5
#1 0.0000000 0.00000000 0.4568333 0.3998250 0.3895393
#2 0.2883051 0.02810549 0.0000000 0.0000000 0.1928034
#3 0.0000000 0.39241904 0.1775706 0.0000000 0.1405068
#4 0.3830174 0.05143501 0.0726334 0.0000000 0.4942698
#5 0.4404673 0.00000000 0.0000000 0.4545036 0.1557058
以下是一些基准测试,用于显示matrix
上的操作速度与data.frame
上的操作速度的差异。 f.df( df )
和f.m( m )
是在data.frame和matrix上运行的两个函数,其中包含100万个元素:
require( microbenchmark )
microbenchmark( f.df( df ) , f.m( m ) , times = 10L )
#Unit: milliseconds
# expr min lq median uq max neval
# f.df(df) 6944.09808 9009.39684 9233.18528 9533.75089 10036.5963 10
# f.m(m) 37.26433 39.00189 40.46229 41.15626 130.6983 10
当矩阵很大时,在矩阵上运算的速度要快两个。
如果确实需要使用应用函数,您可以像这样对矩阵的每个单元格进行处理:
m <- matrix( runif(25) , nrow = 5 )
target <- 0.5
apply( m , 1:2 , function(x) max(x - target , 0 ) )
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.4575807 0.0000000 0.15935928 0.0000000 0.1948637
#[2,] 0.0000000 0.0000000 0.00000000 0.0000000 0.0000000
#[3,] 0.0000000 0.0000000 0.00000000 0.0000000 0.0000000
#[4,] 0.3912719 0.0000000 0.06155316 0.1533290 0.0000000
#[5,] 0.3228921 0.4697041 0.23554353 0.1352888 0.0000000