如何重复R代码指定两行100+次?求动物生长模型编程指导
解决重复执行问题&代码优化建议
嘿,很高兴你在做这个有趣的动物生长模型项目!先帮你搞定最核心的「重复执行x次最后两行代码」需求,再给你一些让代码更清晰、易维护的小建议。
一、先修正初始代码的小问题
我注意到你生成个体时,create.inds函数的参数是length0,但调用时写的是length=sample(...),这会导致参数不匹配,得改成length0=sample(...)才行;另外你没定义n.initial变量,也得补上:
# Generate starting lengths lengths <- seq(from=4.4, to=5.4, by =0.1) # Generate starting ks (growth rate) ks <- seq(from=0.0358, to=0.0437, by =0.0001) n.initial <- 100 # 补上个体数量定义 #Create individuals create.inds <- function(id = NaN, length0=NaN, k1=NaN){ inds <- data.frame(id=id, length0 = length0, k1=k1) inds } # Generate individuals(修正length参数为length0) inds <- create.inds(id=1:n.initial, length0=sample(lengths, n.initial, replace=TRUE), k1=sample(ks, n.initial, replace=TRUE))
二、自动重复执行x次生长计算
用for循环最直观,新手也容易理解。比如我们要重复5次(你可以把x改成任意需要的次数):
x <- 5 # 定义重复生长的次数 for (i in 1:x) { # 定位当前的生长率列和上一次的体型列 current_k_col <- ncol(inds) current_length_col <- current_k_col - 1 # 计算新体型 new_length <- 326*(1-exp(-inds[, current_k_col])) + (inds[, current_length_col]*exp(-inds[, current_k_col])) # 用明确的列名添加新体型(比如length2、length3...) inds[, paste0("length", i+1)] <- new_length # 生成新生长率,同样用清晰的列名(k2、k3...) inds[, paste0("k", i+1)] <- sample(ks, n.initial, replace=TRUE) }
循环结束后,你的inds数据框会有length0、k1、length2、k2……一直到length(x+1)、k(x+1)的列,每一列对应一个时间点的体型或生长率,一目了然。
三、代码优化建议
1. 把生长公式封装成函数
把计算新体型的逻辑写成单独函数,代码更易读,以后修改公式也更方便:
calculate_new_length <- function(prev_length, k) { 326*(1-exp(-k)) + (prev_length * exp(-k)) }
循环里就可以改成:
new_length <- calculate_new_length(inds[, current_length_col], inds[, current_k_col])
2. 改用「长格式」数据(更适合后续分析)
你现在用的是「宽格式」(每个时间点一列),如果以后要做统计分析或可视化,长格式(每个时间点一行)会更顺手。可以用tidyr包转换:
library(tidyr) # 宽格式转长格式 inds_long <- inds %>% pivot_longer( cols = -id, names_to = c(".value", "time_step"), names_pattern = "(length|k)(\\d+)" )
转换后的数据结构会是这样:
| id | time_step | length | k |
|---|---|---|---|
| 1 | 0 | 4.7 | 0.038 |
| 1 | 1 | ... | ... |
| 2 | 0 | 5.1 | 0.041 |
不管画生长曲线还是统计个体差异,都更容易操作。
3. 初始化个体可以更简洁
其实create.inds函数可以简化,甚至直接用data.frame创建(如果以后要扩展功能,函数还是有用的):
inds <- data.frame( id = 1:n.initial, length0 = sample(lengths, n.initial, replace=TRUE), k1 = sample(ks, n.initial, replace=TRUE) )
完整优化后的代码示例
# 加载必要的包(如果用长格式的话) library(tidyr) # 定义参数 n.initial <- 100 x <- 5 # 重复生长的次数 lengths <- seq(from=4.4, to=5.4, by =0.1) ks <- seq(from=0.0358, to=0.0437, by =0.0001) # 封装生长计算函数 calculate_new_length <- function(prev_length, k) { 326*(1-exp(-k)) + (prev_length * exp(-k)) } # 初始化个体 inds <- data.frame( id = 1:n.initial, length0 = sample(lengths, n.initial, replace=TRUE), k1 = sample(ks, n.initial, replace=TRUE) ) # 重复执行生长计算 for (i in 1:x) { current_k_col <- ncol(inds) current_length_col <- current_k_col - 1 # 计算新体型 new_length <- calculate_new_length(inds[, current_length_col], inds[, current_k_col]) inds[, paste0("length", i+1)] <- new_length # 生成新生长率 inds[, paste0("k", i+1)] <- sample(ks, n.initial, replace=TRUE) } # 转成长期格式(可选) inds_long <- inds %>% pivot_longer( cols = -id, names_to = c(".value", "time_step"), names_pattern = "(length|k)(\\d+)" )
希望这些建议能帮到你!如果还有其他问题,随时问~
内容的提问来源于stack exchange,提问作者lwhite3
相关产品推荐
相关产品推荐

