【问题标题】:In R how to loop through csv files and safe outputs of linear regression in new dataframe?在 R 中,如何遍历 csv 文件并将线性回归的输出保存在新的数据框中?
【发布时间】:2021-01-06 09:20:31
【问题描述】:

我的脚本和前 3 个 csv 文件之一可以在我的 Github 文件夹中找到

我已将 NDVI 和气候数据列表拆分为小 csv。每个文件都有 34 年的数据。

然后应根据冲突年份将每 34 年分为两部分,保存在同一张表和特定时间范围内。但是这部分代码已经可以了。

现在我想用第一部分的气候数据来控制列表的第二部分,通过使用多元线性回归,这也是这样做的。

我基本上需要做一个循环来存储一个csv的lm函数每一轮的所有系数。新列表中的文件。

我知道我可以使用 lapply 循环并将输出作为列表获取。但是有一些缺失的部分实际上循环通过 csv。文件。

#load libraries
library(ggplot2)
library(readr)
library(tidyr)
library(dplyr)
library(ggpubr)
library(plyr)
library(tidyverse)
library(fs)


file_paths <- fs::dir_ls("E:\\PYTHON_ST\\breakCSV_PYTHON\\AIM_2_regions\\Afghanistan")
file_paths

#create empty list and fill with file paths and loop through them
file_contents <- list()
for (i in seq_along(file_paths)) { #seq_along for vectors (list of file paths is a vector)
  file_contents[[i]] <- read_csv(file = file_paths[[i]])
                  
                for (i in seq_len(file_contents[[i]])){ # redundant?
                  
                 # do all the following steps in every file                                        
                 
                 # Step 1) 
                 # Define years to divide table
                 
                 #select conflict year in df 
                 ConflictYear = file_contents[[i]][1,9]
                 ConflictYear
                 
                 # select Start year of regression in df
                 SlopeYears = file_contents[[i]][1,7] #to get slope years (e.g.17)
                 BCStartYear = ConflictYear-SlopeYears #to get start year for regression
                 BCStartYear
                 
                 #End year of regression
                 ACEndYear = ConflictYear+(SlopeYears-1) # -1 because the conflict year is included
                 ACEndYear
                 
                 
                 # Step 2
                 
                 #select needed rows from df
                 #no headers but row numbers. NDVI.Year = [r1-r34,c2]
                 NDVI.Year <- file_contents[[i]][1:34,2]
                 NDVI <- file_contents[[i]][1:34,21]
                 T.annual.max <- file_contents[[i]][1:34,19]
                 Prec.annual.max <- file_contents[[i]][1:34,20]
                 soilM.annual.max <- file_contents[[i]][1:34,18]
                 
                 #Define BeforeConf and AfterConf depending on Slope Year number and Conflict Years
                 #Go through NDVI.Year till Conflict.Year (-1 year) since the conflict year is not included in bc
                 BeforeConf1 <- file_contents[[i]][ which(file_contents[[i]]$NDVI.Year >= BCStartYear & file_contents[[i]]$NDVI.Year < ConflictYear),] #eg. 1982 to 1999
                 BeforeConf2 <-  c(NDVI.Year, NDVI, T.annual.max, Prec.annual.max, soilM.annual.max) #which columns to include
                 BeforeConf <- BeforeConf1[BeforeConf2] #create table
                 
                 AfterConf1 <- myFiles[ which(file_contents[[i]]$NDVI.Year >= ConflictYear & file_contents[[i]]$NDVI.Year <= ACEndYear),] #eg. 1999 to 2015
                 AfterConf2 <-  c(NDVI.Year, NDVI, T.annual.max, Prec.annual.max, soilM.annual.max)
                 AfterConf <- AfterConf1[AfterConf2]
                 
                 #Step 3)a)
                 #create empty list, to fill with coefficient results from each model results for each csv file and safe in new list
                 
                 #Create an empty df for the output coefficients
                 names <- c("(Intercept)","BeforeConf$T.annual.max","BeforeConf$Prec.annual.max","BeforeConf$soilM.annual.max")
                 coef_df <- data.frame()
                 for (k in names) coef_df[[k]] <- as.character() 
                 
                 #Apply Multiple Linear Regression
                 plyrFunc <- function(x){
                   model <- lm(NDVI ~ T.annual.max + Prec.annual.max + soilM.annual.max, data = BeforeConf)
                   return(summary(model)$coefficients[1,1:4])
                 }
                 
                 coef_df <- ddply(BeforeConf, .(), x)
                 coef_DF
    }}

【问题讨论】:

  • 有一些缺失的部分不太清楚。请具体说明在您的长代码块中什么不起作用。
  • 因此该代码之前仅适用于一个 csv 文件。主要问题是将其更改为循环遍历 csv 文件列表并为所有文件执行任务。为此,我将以前的文件名更改为“file_contents[[i]]”。但我不知道它是否像那样工作。第二个问题是将系数存储在新的df中。那必须在循环内吗?同样的问题,它适用于单个文件,但我不知道如何将其更改为循环。

标签: r csv for-loop linear-regression plyr


【解决方案1】:

由于您的代码适用于单个 CSV,因此请考虑分离进程和循环。具体来说:

  1. 创建一个接收单个 csv 路径作为输入参数的函数,并为 单个 文件执行您需要的所有操作。

    get_coeffs <- function(csv_path) {
      df <- read.csv(csv_path)
    
      ### Step 1
      # select conflict year, start year, and end year in df 
      ConflictYear <- df[1,9]
      SlopeYears <- df[1,7]                       # to get slope years (e.g.17)
      BCStartYear <- ConflictYear - SlopeYears    # to get start year for regression
      ACEndYear <- ConflictYear + (SlopeYears-1)  # -1 because the conflict year is included
    
      ### Step 2
      # select needed rows from df
      #no headers but row numbers. NDVI.Year = [r1-r34,c2]
      NDVI.Year <- df[1:34, 2]
      NDVI <- df[1:34, 21]
      T.annual.max <- df[1:34, 19]
      Prec.annual.max <- df[1:34, 20]
      soilM.annual.max <- df[1:34, 18]
    
      # Define BeforeConf and AfterConf depending on Slope Year number and Conflict Years
      # Go through NDVI.Year till Conflict.Year (-1 year) since the conflict year is not included in bc
      BeforeConf1 <- df[ which(df$NDVI.Year >= BCStartYear & df$NDVI.Year < ConflictYear),]
      BeforeConf2 <- c(NDVI.Year, NDVI, T.annual.max, Prec.annual.max, soilM.annual.max)
      BeforeConf  <- BeforeConf1[BeforeConf2] #create table
    
      AfterConf1 <- myFiles[ which(df$NDVI.Year >= ConflictYear & df$NDVI.Year <= ACEndYear),]
      AfterConf2 <- c(NDVI.Year, NDVI, T.annual.max, Prec.annual.max, soilM.annual.max)
      AfterConf  <- AfterConf1[AfterConf2]
    
      ### Step 3
      tryCatch({
          # Run model and return coefficients
          model <- lm(NDVI ~ T.annual.max + Prec.annual.max + soilM.annual.max, data = BeforeConf) 
          return(summary(model)$coefficients[1,1:4])
      }, error = function(e) {
          print(e)
          return(rep(NA, 4))
      })
    }
    
  2. 遍历 csv 路径,将每个文件传递到您的函数中,构建一个结果列表,您可以使用lapply 处理列表返回或sapply(或指定长度和类型的vapply)以简化返回,例如作为向量,矩阵/数组(如果适用)。

    mypath <- "E:\\PYTHON_ST\\breakCSV_PYTHON\\AIM_2_regions\\Afghanistan"
    file_paths <- list.files(pattern=".csv", path=mypath)
    
    # LIST RETURN
    result_list <- lapply(file_paths, get_coeffs)
    
    # MATRIX RETURN
    results_matrix <- sapply(file_paths, get_coeffs)
    results_matrix <- vapply(file_paths, get_coeffs, numeric(4))
    

【讨论】:

  • 我用你的 cmets 调整了代码。对于一个文件,它正在工作。但是当我调用 results_matrix 函数时,它会为所有文件返回相同的四个系数值,而不是为每个文件计算新系数。我添加了这个:file_contents &lt;- list() for (i in seq_along(file_paths)) { #seq_along for vectors (list of file paths is a vector) file_contents[[i]] &lt;- read_csv(file = file_paths[[i]])} 它没有用。但我认为它只是将文件路径添加到重复系数中,而不是实际使用文件中的数据。
  • 我相信您将file_contents[[i]] 的代码保留在应该替换为df(第一行分配)的函数中。明确地说,我用更完整的代码而不是缩写 ... 进行编辑,这可能需要测试。再试一次,因为 apply 函数应该有效地遍历文件。
  • 我现在根据您的调整更改了脚本,它似乎有效。但是,我现在收到此Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) : 0 (non-NA) cases 错误消息。可能是我的代码中有零或缺少数据。我通过添加na.action=na.exclude 更改了公式。 model &lt;- lm(NDVI ~ T + Prec + soilM, data = BeforeConf, na.action=na.exclude) 但它仍在发生。你知道如何解决它吗?
  • 这可能是数据问题,因为模型无法运行。请参阅更新包装您的lmtryCatch 中运行。如果出错,将打印错误并在 CSV 的最终矩阵中生成 NA
  • 非常感谢。有效!我现在有一个 coefs 的数据表,并且还打印了 NA,所以我可以排除它们。但我意识到,对于我的分析,我需要在循环中再走一步。而不是将它们打印在列表中。我需要每一轮的 ceof,将它们放入一个公式中并用它们计算一个新的 NDVI 值。这些新值需要打印或放入新列中。如果我没有完成它,我应该把它作为一个新问题发布吗?这是错误 rn:Error in match.fun(FUN) : argument "FUN" is missing, with no default
猜你喜欢
  • 2021-11-01
  • 1970-01-01
  • 2020-03-15
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多