簡體   English   中英

使用循環對 R 中的許多變量進行日志轉換

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM