如何使用多个内部函数和结果制作更优雅、更短的 for 循环
How to make a more elegant and shorter for loop with multiple internal functions and results
这些是我正在执行的步骤:
- 按比例范围(例如 80-85、85-90)对两个矩阵进行子集化
- 运行 每个数据子集的两个独立距离度量函数
- 运行 使用每个数据子集生成的距离矩阵的 mantel
- 生成每个测试结果的列表,每个都有一个唯一的名称
- 生成所有 mantel-r 结果及其结果的数据框
相应的 p 值
我已经编写了将完成此过程的代码,但我觉得有一种更优雅、更好的方法可以做到这一点。我的工作有效,但我想提高我的 R 技能,因此欢迎任何 advice/ideas。我对 R 并不陌生,但我离我想去的地方还很远。
此外,我的代码生成了不必要的对象(即下面代码中的 SS、HB、sp.dis、epa.dis 和 nam)。它们没什么大不了的,但是拥有不产生这种副作用的代码会很好。一个可重现的例子(根据我的数据格式化方式建模)和我使用的包如下:
library(tidyverse)
library(betapart)
library(vegan)
set.seed(2)
spe2<-data.frame(replicate(10,sample(0:100,100,replace=T)))
spe2$Ag<-round(runif(100, min=0.4, max=1),2)
epa2<-data.frame(replicate(3,sample(1:20,100,replace=T)))
epa2$Ag<-spe2$Ag
Mantel.List<-list()
List.names <- list()
for(i in seq(from=0.85, to=0.95,by=0.05 )){
SS<-spe2 %>%
filter(Ag >= i & Ag < i+0.05)
HB<-epa2 %>%
filter(Ag >= i & Ag < i+0.05)
sp.dis<-beta.pair(decostand(SS[,1:ncol(SS)-1],'pa'))
epa.dis<-vegdist(HB[,1:ncol(HB)-1],
method = 'euclidean')
mnt<-mantel(sp.dis$beta.sor,epa.dis)
Mantel.List[[length(Mantel.List)+1]] <- mnt
nam<-paste('M.tt',i*100,sep='')
List.names[[length(List.names)+1]] <- nam
}
names(Mantel.List)<-List.names
Mantel.Results<-cbind(sapply(Mantel.List, function(x) x$statistic),sapply(Mantel.List, function(x) x$signif))
colnames(Mantel.Results)<-c('Mantel-r', 'p-value')
Mantel.Results
谢谢!
我做了两件事,两件事是为了让这段代码更好一点。首先,我消除了所有不必要的对象,我通过使用 data.table 包来完成此操作,这通常是处理 data.frames 的最有效方法,因为它在子集化时不会复制自身.
其次,我没有使用 for 循环,而是使用了 apply 函数。请注意 doit()
内的分配器 <<-
,它将替换函数外的对象。
这是我的建议:
library(data.table)
set.seed(2)
spe2<-as.data.table(data.frame(replicate(10,sample(0:100,100,replace=T))))
spe2$Ag<-round(runif(100, min=0.4, max=1),2)
epa2<-as.data.table(data.frame(replicate(3,sample(1:20,100,replace=T))))
epa2$Ag<-spe2$Ag
doitAll=function(dt1,dt2){
Mantel.List<-list()
List.names <- list()
doit=function(x,dt1,dt2){
mnt<-mantel(beta.pair(decostand(dt1[Ag >= x & Ag < x+0.05,1:(ncol(dt1)-1),with=F],'pa'))$beta.sor,
vegdist(dt2[Ag >= x & Ag < x+0.05,1:(ncol(dt2)-1),with=F],
method = 'euclidean'))
Mantel.List[[length(Mantel.List)+1]] <<- mnt
nam<-paste('M.tt',x*100,sep='')
List.names[[length(List.names)+1]] <<- nam
}
sapply(seq(from=0.85, to=0.95,by=0.05 ),doit,dt1=dt1,dt2=dt2)
names(Mantel.List)<-List.names
Mantel.Results<-cbind(sapply(Mantel.List, function(x) x$statistic),sapply(Mantel.List, function(x) x$signif))
colnames(Mantel.Results)<-c('Mantel-r', 'p-value')
return(Mantel.Results)
}
doitAll(dt1=spe2,dt2=epa2)
它可能有点难读,但它肯定更有效率。
这些是我正在执行的步骤:
- 按比例范围(例如 80-85、85-90)对两个矩阵进行子集化
- 运行 每个数据子集的两个独立距离度量函数
- 运行 使用每个数据子集生成的距离矩阵的 mantel
- 生成每个测试结果的列表,每个都有一个唯一的名称
- 生成所有 mantel-r 结果及其结果的数据框 相应的 p 值
我已经编写了将完成此过程的代码,但我觉得有一种更优雅、更好的方法可以做到这一点。我的工作有效,但我想提高我的 R 技能,因此欢迎任何 advice/ideas。我对 R 并不陌生,但我离我想去的地方还很远。
此外,我的代码生成了不必要的对象(即下面代码中的 SS、HB、sp.dis、epa.dis 和 nam)。它们没什么大不了的,但是拥有不产生这种副作用的代码会很好。一个可重现的例子(根据我的数据格式化方式建模)和我使用的包如下:
library(tidyverse)
library(betapart)
library(vegan)
set.seed(2)
spe2<-data.frame(replicate(10,sample(0:100,100,replace=T)))
spe2$Ag<-round(runif(100, min=0.4, max=1),2)
epa2<-data.frame(replicate(3,sample(1:20,100,replace=T)))
epa2$Ag<-spe2$Ag
Mantel.List<-list()
List.names <- list()
for(i in seq(from=0.85, to=0.95,by=0.05 )){
SS<-spe2 %>%
filter(Ag >= i & Ag < i+0.05)
HB<-epa2 %>%
filter(Ag >= i & Ag < i+0.05)
sp.dis<-beta.pair(decostand(SS[,1:ncol(SS)-1],'pa'))
epa.dis<-vegdist(HB[,1:ncol(HB)-1],
method = 'euclidean')
mnt<-mantel(sp.dis$beta.sor,epa.dis)
Mantel.List[[length(Mantel.List)+1]] <- mnt
nam<-paste('M.tt',i*100,sep='')
List.names[[length(List.names)+1]] <- nam
}
names(Mantel.List)<-List.names
Mantel.Results<-cbind(sapply(Mantel.List, function(x) x$statistic),sapply(Mantel.List, function(x) x$signif))
colnames(Mantel.Results)<-c('Mantel-r', 'p-value')
Mantel.Results
谢谢!
我做了两件事,两件事是为了让这段代码更好一点。首先,我消除了所有不必要的对象,我通过使用 data.table 包来完成此操作,这通常是处理 data.frames 的最有效方法,因为它在子集化时不会复制自身.
其次,我没有使用 for 循环,而是使用了 apply 函数。请注意 doit()
内的分配器 <<-
,它将替换函数外的对象。
这是我的建议:
library(data.table)
set.seed(2)
spe2<-as.data.table(data.frame(replicate(10,sample(0:100,100,replace=T))))
spe2$Ag<-round(runif(100, min=0.4, max=1),2)
epa2<-as.data.table(data.frame(replicate(3,sample(1:20,100,replace=T))))
epa2$Ag<-spe2$Ag
doitAll=function(dt1,dt2){
Mantel.List<-list()
List.names <- list()
doit=function(x,dt1,dt2){
mnt<-mantel(beta.pair(decostand(dt1[Ag >= x & Ag < x+0.05,1:(ncol(dt1)-1),with=F],'pa'))$beta.sor,
vegdist(dt2[Ag >= x & Ag < x+0.05,1:(ncol(dt2)-1),with=F],
method = 'euclidean'))
Mantel.List[[length(Mantel.List)+1]] <<- mnt
nam<-paste('M.tt',x*100,sep='')
List.names[[length(List.names)+1]] <<- nam
}
sapply(seq(from=0.85, to=0.95,by=0.05 ),doit,dt1=dt1,dt2=dt2)
names(Mantel.List)<-List.names
Mantel.Results<-cbind(sapply(Mantel.List, function(x) x$statistic),sapply(Mantel.List, function(x) x$signif))
colnames(Mantel.Results)<-c('Mantel-r', 'p-value')
return(Mantel.Results)
}
doitAll(dt1=spe2,dt2=epa2)
它可能有点难读,但它肯定更有效率。