我有一个空数据框T_modelled
,包含2784列和150行。
T_modelled <- data.frame(matrix(ncol = 2784, nrow = 150))
names(T_modelled) <- paste0("t=", t_sec_ERT)
rownames(T_modelled) <- paste0("z=", seq(from = 0.1, to = 15, by = 0.1))
,其中
t_sec_ERT <- seq(from = -23349600, to = 6706800, by = 10800)
z <- seq(from = 0.1, to = 15, by = 0.1)
我使用嵌套的for循环按列填充T_modelled
,基于以下公式:
for (i in 1:ncol(T_modelled)) {
col_tmp <- colnames(T_modelled)[i]
for (j in 1:nrow(T_modelled)) {
z_tmp <- z[j]-0.1
T_tmp <- MANSRT+As*e^(-z_tmp*(omega/(2*K))^0.5)*sin(omega*t_sec_ERT[i]-((omega/(2*K))^0.5)*z_tmp)
T_modelled[j ,col_tmp] <- T_tmp
}
}
,其中
MANSRT <- -2.051185
As <- 11.59375
omega <- (2*pi)/(347.875*24*60*60)
c <- 790
k <- 0.00219
pb <- 2600
K <- (k*1000)/(c*pb)
e <- exp(1)
我确实得到了预期的结果,但我一直认为必须有一种更有效的方法来填充数据框。循环非常慢,对我来说看起来很麻烦。我想有机会利用R的矢量化计算方法。我只是无法看到自己如何以更简单的方式填充T_modelled
。
任何人都有任何想法如何以更快,更像“R”的方式获得相同的结果?
答案 0 :(得分:2)
我相信这样做。
在创建T_modelled
之后立即运行第一条指令,将需要测试结果是否相等。
Tm <- T_modelled
现在运行您的代码,然后运行下面的代码。
z_tmp <- z - 0.1
for (i in 1:ncol(Tm)) {
T_tmp <- MANSRT + As*exp(-z_tmp*(omega/(2*K))^0.5)*sin(omega*t_sec_ERT[i]-((omega/(2*K))^0.5)*z_tmp)
Tm[ , i] <- T_tmp
}
all.equal(T_modelled, Tm)
#[1] TRUE
您不需要内循环,这只是唯一的差异。
(我也直接使用exp
,但这是次要的。)
答案 1 :(得分:2)
就像您之前接受的问题solution一样,只需使用sapply
,迭代向量 t_sec_ERT ,其长度与您想要的数据帧号相同列。但首先要将z的每个元素调整0.1。另外,不需要事先创建空数据帧。
z_adj <- z - 0.1
T_modelled2 <- data.frame(sapply(t_sec_ERT, function(ert)
MANSRT+As*e^(-z_adj*(omega/(2*K))^0.5)*sin(omega*ert-((omega/(2*K))^0.5)*z_adj)))
colnames(T_modelled2) <- paste0("t=", t_sec_ERT)
rownames(T_modelled2) <- paste0("z=", z)
all.equal(T_modelled, T_modelled2)
# [1] TRUE
答案 2 :(得分:1)
Rui当然是正确的,我只想在编写这样的循环时建议一种推理方式。
你有两个数字向量。 R中的数字函数通常是矢量化的。我的意思是你可以做这样的事情
x <- c(1, 6, 3)
sum(x)
不需要这样的东西
x_ <- 0
for (i in x) {
x_ <- i + x_
}
x_
也就是说,不需要在R中循环。当然,循环也会发生,它只发生在底层的C,Fortran等代码中,它可以更有效地完成。这通常是我们调用函数向量化时的意思:循环发生在“引擎盖下”。因此,Vectorize()
的输出并未严格按照此定义进行矢量化。
当你想要循环的两个数字向量时,你必须首先看看组成函数是否被矢量化,通常是通过阅读文档。
如果是,则继续构建该中心向量化复合函数,并开始使用一个向量和一个标量对其进行测试。在你的情况下,它将是这样的(仅使用t_sec_ERT
的第一个元素进行测试。)
z_tmp <- z - 0.1
i <- 1
T_tmp <- MANSRT + As *
exp(-z_tmp*(omega/(2*K))^0.5) *
sin(omega*t_sec_ERT[i] - ((omega/(2*K))^0.5)*z_tmp)
看起来不错。然后开始循环遍历t_sec_ERT
。
T_tmp <- matrix(nrow=length(z), ncol=length(t_sec_ERT))
for (i in 1:length(t_sec_ERT)) {
T_tmp[, i] <- MANSRT + As *
exp(-z_tmp*(omega/(2*K))^0.5) *
sin(omega*t_sec_ERT[i] - ((omega/(2*K))^0.5)*z_tmp)
}
或者你可以使用通常更整洁的sapply()
。
f <- function(x) {
MANSRT + As *
exp(-z_tmp*(omega/(2*K))^0.5) *
sin(omega*x - ((omega/(2*K))^0.5)*z_tmp)
}
T_tmp <- sapply(t_sec_ERT, f)
答案 3 :(得分:0)
我希望将数据放在长格式中,将z
和t_sec_ERT
的所有组合作为两列,以便利用向量化。虽然我通常更喜欢tidyr
在长格式和宽格式之间切换,但我试图将其作为基本解决方案:
t_sec_ERT <- seq(from = -23349600, to = 6706800, by = 10800)
z <- seq(from = 0.1, to = 15, by = 0.1)
v <- expand.grid(t_sec_ERT, z)
names(v) <- c("t_sec_ERT", "z")
v$z_tmp <- v$z-0.1
v$T_tmp <- MANSRT+As*e^(-v$z_tmp*(omega/(2*K))^0.5)*sin(omega*v$t_sec_ERT-((omega/(2*K))^0.5)*v$z_tmp)
T_modelled <- data.frame(matrix(v$T_tmp, nrow = length(z), ncol = length(t_sec_ERT), byrow = TRUE))
names(T_modelled) <- paste0("t=", t_sec_ERT)
rownames(T_modelled) <- paste0("z=", seq(from = 0.1, to = 15, by = 0.1))