[英]Log Transform many variables in R with loop
我有一个数据框,其中有一个用于诊断的二进制变量(第 1 列)和 165 个营养变量(第 2-166 列),用于 n=237。 我们称这个数据集为 nutr_all。 我需要创建 165 个新变量来获取每个营养变量的自然对数。 所以,我想得到一个包含 331 列的数据框 - 第 1 列 = 诊断,第 2-166 列 = 营养变量,第 167-331 列 = 对数转换后的营养变量。 我希望这些变量取旧变量的名称,但末尾带有“_log”
我尝试过使用 for 循环和 mutate 命令,但是,我对 r 不是很精通,所以,我有点挣扎。
for (nutr in (nutr_all_nomiss[,2:166])){
nutr_all_log <- mutate(nutr_all, nutr_log = log(nutr) )
}
当我这样做时,它只会创建一个名为 nutr_log 的新变量。 我知道我需要让 r 知道“nutr_log”中的“nutr”是 for 循环中的变量名,但我不确定如何。
对于最近遇到此页面的任何人, dplyr::across()
是在 2020 年底推出的,它正是为这个任务而构建的 - 一次对许多列应用相同的转换。
下面是一个简单的解决方案。
如果您需要选择要转换的列,请通过在 R 控制台中运行?tidyr_tidy_select
来查看tidyselect辅助函数。
library(tidyverse)
# create vector of column names
variable_names <- paste0("nutrient_variable_", 1:165)
# create random data for example
data_values <- purrr::rerun(.n = 165,
sample(x=100,
size=237,
replace = T))
# set names of the columns, coerce to a tibble,
# and add the diagnosis column
nutr_all <- data_values %>%
set_names(variable_names) %>%
as_tibble() %>%
mutate(diagnosis = 1:237) %>%
relocate(diagnosis, .before = everything())
# use across to perform same transformation on all columns
# whose names contain the phrase 'nutrient_variable'
nutr_all_with_logs <- nutr_all %>%
mutate(across(
.cols = contains('nutrient_variable'),
.fns = list(log10 = log10),
.names = "{.col}_{.fn}"))
# print out a small sample of data to validate
nutr_all_with_logs[1:5, c(1, 2:3, 166:168)]
就个人而言,与其将所有列添加到数据框中,我更愿意创建一个仅包含转换后的值的新数据框,并更改列名:
logs_only <- nutr_all %>%
mutate(across(
.cols = contains('nutrient_variable'),
.fns = log10)) %>%
rename_with(.cols = contains('nutrient_variable'),
.fn = ~paste0(., '_log10'))
logs_only[1:5, 1:3]
我们可以使用mutate_at
library(dplyr)
nutr_all_log <- nutr_all_nomiss %>%
mutate_at(2:166, list(nutr_log = ~ log(.)))
在base R
中,我们可以直接在data.frame
上执行此操作
nm1 <- paste0(names(nutr_all_nomiss)[2:166], "_nutr_log")
nutr_all_nomiss[nm1] <- log(nutr_all_nomiss[nm1])
在基础 R 中,我们可以使用lapply
:
nutr_all_nomiss[paste0(names(nutr_all_nomiss)[2:166], "_log")] <- lapply(nutr_all_nomiss[2:166], log)
这是仅使用基础 R 的解决方案:
首先,我将创建一个与您的数据集等效的数据集:
nutr_all <- data.frame(
diagnosis = sample(c(0, 1), size = 237, replace = TRUE)
)
for(i in 2:166){
nutr_all[i] <- runif(n = 237, 1, 10)
names(nutr_all)[i] <- paste0("nutrient_", i-1)
}
现在让我们创建新变量和 append 到数据框:
nutr_all_log <- cbind(nutr_all, log(nutr_all[, -1]))
这会处理名称:
names(nutr_all_log)[167:331] <- paste0(names(nutr_all[-1]), "_log")
给定 function 使用 dplyr 将完成您的任务,它可用于获取数据集中所有变量的日志转换,它还检查列是否具有 -ive 值。 目前,在这个 function 中,它不会计算这些参数的日志,
logTransformation<- function(ds)
{
# this function creats log transformation of dataframe for only varibles which are positive in nature
# args:
# ds : Dataset
require(dplyr)
if(!class(ds)=="data.frame" ) { stop("ds must be a data frame")}
ds <- ds %>%
dplyr::select_if(is.numeric)
# to get only postive variables
varList<- names(ds)[sapply(ds, function(x) min(x,na.rm = T))>0]
ds<- ds %>%
dplyr::select(all_of(varList)) %>%
dplyr::mutate_at(
setNames(varList, paste0(varList,"_log")), log)
)
return(ds)
}
您可以将其用于您的案例:
#assuming your binary variable has namebinaryVar
nutr_allTransformed<- nutr_all %>% dplyr::select(-binaryVar) %>% logTransformation()
如果你也想有负变量,替换 varlist 如下:
varList<- names(ds)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.