[英]looping with iterations over two lists of variables for a multiple regression in R
我想在 R 中編寫一個循環來運行具有一個因變量和兩個自變量列表(所有連續變量)的多元回歸。 該模型是可加的,循環應該通過迭代兩個變量列表來運行,以便它從第一個列表中獲取第一列+從第二個列表中獲取第一列,然后對兩個列表中的第二列進行相同的操作,等等。問題是我無法讓它正確地遍歷列表,而是我的循環運行的模型比它應該的多。
我在這里描述的數據框只是我實際上必須運行 3772 次的一個子集(我正在研究 RNA-seq 轉錄表達)。
我的數據框稱為dry,包含22 個變量(列)和87 個觀察值(行)。 第 1 列包含 genotypeID,第 2:11 列包含一組要迭代的自變量,第 12:21 列包含要迭代的第二組自變量,第 23 列包含我的稱為 FITNESS_DRY 的因變量。 這是結構的樣子:
str(dry)
'data.frame': 87 obs. of 22 variables:
$ geneID : Factor w/ 87 levels "e10","e101","e102",..: 12 15 17 24 25 30 35 36 38 39 ...
$ RDPI_T1 : num 1.671 -0.983 -0.776 -0.345 0.313 ...
$ RDPI_T2 : num -0.976 -0.774 -0.532 -1.137 1.602 ...
$ RDPI_T3 : num -0.197 -0.324 0.805 -0.701 -0.566 ...
$ RDPI_T4 : num 0.289 -0.92 1.117 -1.214 -0.447 ...
$ RDPI_T5 : num -0.671 1.963 NA -1.024 -0.295 ...
$ RDPI_T6 : num 2.606 -1.116 -0.383 -0.893 0.119 ...
$ RDPI_T7 : num -0.843 -0.229 -0.297 0.504 -0.712 ...
$ RDPI_T8 : num -0.227 NA NA -0.816 -0.761 ...
$ RDPI_T9 : num 0.754 -1.304 1.867 -0.514 -1.377 ...
$ RDPI_T10 : num 1.1352 -0.1028 -0.69 2.0242 -0.0925 ...
$ DRY_T1 : num 0.6636 -0.64508 -0.24643 -1.43231 -0.00855 ...
$ DRY_T2 : num 1.008 0.823 -0.658 -0.148 0.272 ...
$ DRY_T3 : num -0.518 -0.357 1.294 0.408 0.771 ...
$ DRY_T4 : num 0.0723 0.2834 0.5198 1.6527 0.4259 ...
$ DRY_T5 : num 0.1831 1.9984 NA 0.0923 0.1232 ...
$ DRY_T6 : num -1.55 0.366 0.692 0.902 -0.993 ...
$ DRY_T7 : num -2.483 -0.334 -1.077 -1.537 0.393 ...
$ DRY_T8 : num 0.396 NA NA -0.146 -0.468 ...
$ DRY_T9 : num -0.694 0.353 2.384 0.665 0.937 ...
$ DRY_T10 : num -1.24 -1.57 -1.36 -3.88 -1.4 ...
$ FITNESS_DRY: num 1.301 3.365 0.458 0.346 1.983 ...
目標是運行 10 次多元回歸,如下所示:
lm1<-lm(FITNESS_DRY~DRY_T1+RDPI_T1)
lm2<-lm(FITNESS_DRY~DRY_T2+RDPI_T2)
依此類推,遍歷兩個列表的所有十列 這在索引方面等效於以下內容
lm1<-lm(FITNESS_DRY~dry[,12]+dry[,2])
lm1<-lm(FITNESS_DRY~dry[,12]+dry[,2])
等等。
然后我的循環應該計算每個模型的摘要,並將所有 pvalues(lm 摘要的第 4 列)組合到一個輸出對象中。
我首先定義了我的變量列表
var_list<-list(
var1=dry[,12:21],
var2=dry[,2:11]
)
這是我嘗試過但無法正常工作的循環:
lm.test1<-name<-vector()
for (i in 12:length(var_list$var1)){
for (j in 2:length(var_list$var2)){
lm.tmp<-lm(FITNESS_DRY~dry[,i]+dry[,j], na.action=na.omit, data=dry)
sum.tmp<-summary(lm.tmp)
lm.test1<-rbind(lm.test1,sum.tmp$coefficients[,4]) }
}
循環返回此錯誤消息:
Warning message:
In rbind(lm.test6, sum.tmp$coefficients[, 4]) :
number of columns of result is not a multiple of vector length (arg 2)
我可以調用對象“lm.test1”,但該對象有 27 行而不是我想要的 10 行,因此迭代在這里無法正常工作。 任何人都可以幫忙嗎? 此外,如果我可以將每個變量列表的列名稱添加到摘要中,那就太好了。 我嘗試對每個變量列表使用它,但沒有成功:
name<-append(name, as.character(colnames(var_list$var1))
有任何想法嗎? 在此先感謝您的幫助!
UPDATE1:有關完整數據集的更多信息:我的實際數據仍將包含第一個列“geneID”,然后我有 3772 列名稱 DRY_T1....DRY_T3772,然后是另外 3772 列名稱 RDPI_T1...RDPI_T3772,最后是我的因變量“FITNESS_DRY”。 我仍然想像這樣運行所有的加法模型:
lm1<-lm(FITNESS_DRY~DRY_T1+RDPI_T1)
lm2<-lm(FITNESS_DRY~DRY_T2+RDPI_T2)
lm3772<-lm(FITNESS_DRY~DRY_T3772+RDPI_T3772)
我模擬了一個數據集:
set.seed(2)
dat3 = as.data.frame(replicate(7544, runif(20)))
names(dat3) = paste0(rep(c("DRY_T","RDPI_T"),each=3772), 1:3772)
dat3 = cbind(dat3, FITNESS_DRY=runif(20))
然后我運行 for 循環:
models = list()
for(i in 1:3772) {
vars = names(dat3)[grepl(paste0(i,"$"), names(dat3))]
models2[[as.character(i)]] = lm(paste("FITNESS_DRY ~ ", paste(vars, collapse="
+")),
data = dat3)
}
這在數據模擬上運行良好,但是當我在以完全相同的方式設置的真實數據集上嘗試時,它不起作用。 循環可能在處理兩位或更多位數字時遇到問題。 我收到此錯誤消息:
Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
0 (non-NA) cases
更新 2:確實,該模型在處理兩位或更多位數字時存在問題。 為了查看原始版本中的問題,我使用了這個:(我的數據集稱為“dry2”):
names(dry2)[grepl("2$", names(dry2))]
這返回了所有 DRY_T 和 RDPI_T 變量,其數字包含“2”,而不是只有一對 DRY_T 和 RDPI_T。
要解決此問題,此新代碼有效:
models = list()
for(i in 1:3772) {
vars = names(dry2)[names(dry2) %in% paste0(c("DRY_T", "RDPI_T"), i)]
models[[as.character(i)]] = lm(paste("FITNESS_DRY ~ ", paste(vars, collapse=" + ")),
data = dry2)
}
有多種方法可以為迭代設置模型公式。 這是一種方法,我們演示了使用purrr
包中的 for 循環或map
進行迭代。 然后我們使用broom
包中的tidy
來獲取系數和 p 值。
library(tidyverse)
library(broom)
# Fake data
set.seed(2)
dat = as.data.frame(replicate(20, runif(20)))
names(dat) = paste0(rep(c("DRY_T","RDPI_T"),each=10), 0:9)
dat = cbind(dat, FITNESS_DRY=runif(20))
# Generate list of models
# Using for loop
models = list()
for(i in 0:9) {
# Get the two column names to use for this iteration of the model
vars = names(dat)[grepl(paste0(i,"$"), names(dat))]
# Fit the model and add results to the output list
models[[as.character(i)]] = lm(paste("FITNESS_DRY ~ ", paste(vars, collapse=" + ")),
data = dat)
}
# Same idea using purrr::map to iterate
models = map(0:9 %>% set_names(),
~ {
vars = names(dat)[grepl(paste0(.x,"$"), names(dat))]
form = paste("FITNESS_DRY ~ ", paste(vars, collapse=" + "))
lm(form, data = dat)
})
# Check first two models
models[1:2]
#> $`0`
#>
#> Call:
#> lm(formula = form, data = dat)
#>
#> Coefficients:
#> (Intercept) DRY_T0 RDPI_T0
#> 0.4543 0.3025 -0.1624
#>
#>
#> $`1`
#>
#> Call:
#> lm(formula = form, data = dat)
#>
#> Coefficients:
#> (Intercept) DRY_T1 RDPI_T1
#> 0.64511 -0.33293 0.06698
# Get coefficients and p-values for each model in a single data frame
results = map_df(models, tidy, .id="run_number")
results
#> # A tibble: 30 x 6
#> run_number term estimate std.error statistic p.value
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 0 (Intercept) 0.454 0.153 2.96 0.00872
#> 2 0 DRY_T0 0.303 0.197 1.53 0.143
#> 3 0 RDPI_T0 -0.162 0.186 -0.873 0.395
#> 4 1 (Intercept) 0.645 0.185 3.49 0.00279
#> 5 1 DRY_T1 -0.333 0.204 -1.63 0.122
#> 6 1 RDPI_T1 0.0670 0.236 0.284 0.780
#> 7 2 (Intercept) 0.290 0.147 1.97 0.0650
#> 8 2 DRY_T2 0.270 0.176 1.53 0.144
#> 9 2 RDPI_T2 0.180 0.185 0.972 0.345
#> 10 3 (Intercept) 0.273 0.187 1.46 0.162
#> # … with 20 more rows
由reprex 包(v0.2.1) 於 2019 年 6 月 28 日創建
如果您不需要保存模型對象,您可以只返回系數和 p 值的數據框:
results = map_df(0:9 %>% set_names(),
~ {
vars = names(dat)[grepl(paste0(.x,"$"), names(dat))]
form = paste("FITNESS_DRY ~ ", paste(vars, collapse=" + "))
tidy(lm(form, data = dat))
}, .id="run_number")
更新:為了回答您的評論,如果您將0:9
所有實例替換為1:10
(抱歉,沒有注意到您的列后綴是從 1:10 而不是 0:9),並且所有dat
實例(我的假數據)與dry2
(或您用於數據框的任何名稱),代碼將與您的數據一起運行,只要列名與您在問題中使用的列名相同。 如果您使用不同的列名,則需要修改代碼,通過對新名稱進行硬編碼或創建一個函數來接受您用於模型的任何列名產生。
為了解釋代碼在做什么:首先,我們需要獲取我們想要在模型的每次迭代中使用的列的名稱。 例如,在 for 循環版本中:
vars = names(dry2)[grepl(paste0(i,"$"), names(dry2))]
例如,當i=2
,這將解析為:
vars = names(dry2)[grepl("2$", names(dry2))]
vars
[1] "RDPI_T2" "DRY_T2"
所以這是我們想要用來生成回歸公式的兩列。 "2$"
是一個正則表達式(正則表達式是一種字符串匹配語言),意思是:匹配names(dry2)
中以數字“2”結尾的值。
為了創建我們的公式,我們這樣做:
paste(vars, collapse=" + ")
[1] "RDPI_T2 + DRY_T2"
form = paste("FITNESS_DRY ~ ", paste(vars, collapse=" + "))
form
[1] "FITNESS_DRY ~ RDPI_T2 + DRY_T2"
現在我們有了我們在lm
使用的回歸公式。
每次迭代(使用for
或map
或者,在@RomanLuštrik 的建議中, mapply
)都會生成連續的模型。
更新 2:正如我在評論中指出的那樣,我意識到當最終數字超過一位時,正則表達式paste(i, "$")
將失敗(通過匹配多個類型的自變量列)。 所以,試試這個(對於map
版本也是如此):
models = list()
for(i in 1:3772) {
# Get the two column names to use for this iteration of the model
vars = names(dry2)[names(dry2) %in% paste0(c("DRY_T", "RDPI_T"), i)]
# Fit the model and add results to the output list
models[[as.character(i)]] = lm(paste("FITNESS_DRY ~ ", paste(vars, collapse=" + ")),
data = dry2)
}
要查看原始版本中的問題,請運行例如names(dry2)[grepl("2$", names(dry2))]
考慮使用reshape
將非常寬的數據幀reshape
為長格式,這通常是幾乎任何數據科學應用程序的首選數據格式。
根據您的需要,這需要對每個_T
指標進行兩次重塑。 重塑后,創建一個T_NUM
指標(即剝離DRY_T##
和RDPI_T##
)並將其與相應的FITNESS_DRY
一起使用以merge
兩個指標。
最后,使用by
按T_NUM分組對大型數據框進行切片以構建模型列表。 下面使用您在上面模擬的dat3 。 總而言之,所有基礎 R: reshape
-> TNUM <- ...
-> merge
-> by
-> lm
。 其他方法, lapply
, within
,並Reduce
對於DRY-ER代碼助手。
# TWO DATA FRAMES OF FOUR COLUMNS
df_list <- lapply(c("DRY_T", "RDPI_T"), function(i)
within(reshape(dat3[c(grep(i, names(dat3)), ncol(dat3))],
varying = list(names(dat3)[grep(i, names(dat3))]),
v.names = i,
times = names(dat3)[grep(i, names(dat3))],
timevar = "T_NUM",
direction = "long"), {
T_NUM <- as.integer(gsub(i, "", as.character(T_NUM)))
id <- NULL
})
)
# MERGE BOTH DFs
long_df <- Reduce(function(x, y) merge(x, y, by=c("T_NUM", "FITNESS_DRY")), df_list)
head(long_df, 10)
# T_NUM FITNESS_DRY DRY_T RDPI_T
# 1 1 0.1528837 0.9438393 0.87948274
# 2 1 0.1925344 0.7023740 0.65120186
# 3 1 0.2193480 0.2388948 0.29875871
# 4 1 0.2743660 0.1291590 0.60097630
# 5 1 0.2877732 0.9763985 0.66921847
# 6 1 0.3082835 0.7605133 0.22456361
# 7 1 0.5196165 0.1848823 0.79543965
# 8 1 0.5603618 0.1680519 0.08759412
# 9 1 0.5789254 0.8535485 0.37942053
# 10 1 0.6291315 0.5526741 0.43043940
# NAMED LIST OF 3,772 MODELS
model_list <- by(long_df, long_df$T_NUM, function(sub)
lm(FITNESS_DRY ~ DRY_T + RDPI_T, sub))
輸出
summary(model_list$`1`)$coefficients
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 0.7085512 0.1415849 5.0044269 0.0001085681
# DRY_T -0.1423601 0.1985256 -0.7170867 0.4830577281
# RDPI_T -0.1273237 0.2179249 -0.5842551 0.5667218157
summary(model_list$`2`)$coefficients
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 0.3907525 0.1524423 2.5632809 0.02015115
# DRY_T 0.1952963 0.1990449 0.9811672 0.34026853
# RDPI_T 0.1979513 0.1884085 1.0506492 0.30812662
summary(model_list$`3`)$coefficients
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 0.38836708 0.2076638 1.870172 0.07878049
# DRY_T 0.06995811 0.1965336 0.355960 0.72624947
# RDPI_T 0.27144752 0.2115787 1.282962 0.21672143
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.