循环子集,获取文件并将结果保存在数据框中

Posted

技术标签:

【中文标题】循环子集,获取文件并将结果保存在数据框中【英文标题】:Loop over a subset, source a file and save results in a dataframe 【发布时间】:2016-08-03 18:09:58 【问题描述】:

已经提出了类似的问题,但没有一个能够解决我的具体问题。我有一个.R 文件(“Mycalculus.R”),其中包含许多我需要应用于数据框子集的基本微积分:每年的一个子集,其中“年”的模态是因子(yearA、yearB、yearC)不是数值。该文件生成一个新的数据框,我需要将其保存在 Rda 文件中。这是我希望代码看起来像 for 循环(这个显然不起作用):

id <- identif(unlist(df$year))
for (i in 1:length(id))
    data <- subset(df, year == id[i])
    source ("Mycalculus.R", echo=TRUE)
    save(content_df1,file="myresults.Rda")

这是主要 data.frame df 的确切内容:

obs    year    income    gender   ageclass    weight
 1     yearA    1000       F         1          10
 2     yearA    1200       M         2          25
 3     yearB    1400       M         2           5
 4     yearB    1350       M         1          11

源文件“Mycalculus.R”的作用如下:它将大量基本微积分应用于数据帧的“数据”列,并基于 df1 创建两个新数据帧 df1 和 df2。以下是摘录:

data <- data %>% 
   group_by(gender) %>% 
   mutate(Income_gender = weighted.mean(income, weight))
data <- data %>% 
   group_by(ageclass) %>% 
   mutate(Income_ageclass = weighted.mean(income, weight))

library(GiniWegNeg)
gini=c(Gini_RSV(data$Income_gender, weight), Gini_RSV(data$Income_ageclass,weight))

df1=data.frame(gini)
colnames(df1) <- c("Income_gender","Income_ageclass")
rownames(df1) <- c("content_df1")

df2=(1/5)*df1$Income_gender+df2$Income_ageclass
colnames(df2) <- c("myresult")
rownames(df2) <- c("content_df2")

所以最后,我得到两个这样的数据框:

                    Income_Gender  Income_Ageclass    
content_df1           ....             ....     

对于 df2:

                    myresult      
content_df2           ....          

但我需要将 df1 和 Rf2 保存为 Rda 文件,其中 content_df1 和 content_df2 的行名按子集给出,如下所示:

                    Income_Gender  Income_Ageclass    
content_df1_yearA     ....             ....     
content_df1_yearB     ....             ....     
content_df1_yearC     ....             ....     

                    myresult
content_df2_yearA     ....   
content_df2_yearB     ....    
content_df2_yearC     ....   

目前,我的程序没有使用任何循环并且正在完成这项工作,但很混乱。基本上代码是2500多行代码。 (请不要向我扔西红柿)。

任何人都可以帮助我解决这个特定的请求吗? 提前谢谢你。

【问题讨论】:

用一个可重复的例子简单地说明你的问题。提供两个带有 yearA 和 yearB 的简单 data.frame,并在您的示例 Mycalculus.R 文件中执行一个简单的功能。这将使其他人更容易理解您的问题的性质。 【参考方案1】:

考虑将所有内容与所需参数的定义函数合并到一个脚本中,由lapply() 调用。然后,Lapply 返回一个数据帧列表,您可以将这些数据帧绑定到一个最终的 df 中。

library(dplyr)
library(GiniWegNeg)

runIncomeCalc <- function(data, y)      
  data <- data %>% 
    group_by(gender) %>% 
    mutate(Income_gender = weighted.mean(income, weight))
  data <- data %>% 
    group_by(ageclass) %>% 
    mutate(Income_ageclass = weighted.mean(income, weight))      

  gini <- c(Gini_RSV(data$Income_gender, weight), Gini_RSV(data$Income_ageclass,weight))

  df1 <- data.frame(gini)
  colnames(df1) <- c("Income_gender","Income_ageclass")
  rownames(df1) <- c(paste0("content_df1_", y))

  return(df1)


runResultsCalc <- function(df, y)
  df2 <- (1/5) * df$Income_gender + df$Income_ageclass
  colnames(df2) <- c("myresult")
  rownames(df2) <- c(paste0("content_df2_", y)

  return(df2)


dfIncList <- lapply(unique(df$year), function(i)       
  yeardata <- subset(df, year == i)
  runIncomeCalc(yeardata, i)      
)

dfResList <- lapply(unique(df$year), function(i)       
  yeardata <- subset(df, year == i)
  df <- runIncomeCalc(yeardata, i) 
  runResultsCalc(df, i)      
)

df1 <- do.call(rbind, dfIncList)
df2 <- do.call(rbind, dfResList)

现在,如果您需要跨脚本获取资源。在 Mycalculus.R 中创建相同的两个函数,runIncomeCalcrunResultsCalc,然后在其他脚本中调用:

library(dplyr)
library(GiniWegNeg)

if(!exists("runIncomeCalc", mode="function")) source("Mycalculus.R")

dfIncList <- lapply(unique(df$year), function(i)       
  yeardata <- subset(df, year == i)
  runIncomeCalc(yeardata, i)      
)

dfResList <- lapply(unique(df$year), function(i)       
  yeardata <- subset(df, year == i)
  df <- runIncomeCalc(yeardata, i) 
  runResultsCalc(df, i)      
)

df1 <- do.call(rbind, dfIncList)
df2 <- do.call(rbind, dfResList)

【讨论】:

您的解决方案完美运行,但前提是我的微积分仅生成一个数据帧 (df1)。如果我的微积分生成第二个数据帧(基于 df1 的 df2),它就不再起作用了。这里的代码甚至不再为 df1 生成结果。我编辑了我的问题,以便在这一点上更清楚。 使用相同的 fct 和 args 进程查看更新。只需添加另一个接收 df1 作为输入的函数,然后在结尾处使用lapply 迭代到rbind。并从其他脚本中获取这两个函数。 在您的更新中,您在 runResultsCalc 部分中写了 df 而不是 df1。它应该是df2 &lt;- (1/5) * df1$Income_gender + df1$Income_ageclass,因为 df2 演算是基于 df1 的结果。这是故意的吗?如果不是,这对您提供的其余代码有什么影响? 不正确,因为df 是作为参数传递的函数的本地参数。在dfResList lapply() 中,其本地dfrunIncomeCalc() 的返回值,然后将其结果集传递给runResultsCalc()。使用df1 会出错或返回空数据,因为它在全局环境中除了最后之外没有创建。当然要测试确认。更改重复的df 的名称以避免混淆。【参考方案2】:

如果您将步骤功能化,您可以创建如下工作流:

calcFunc <- function(df) 
  ## Do something to the df, then return it
  df


processFunc <- function(fname) 
  ## Read in your table
  x <- read.table(fname)

  ## Do the calculation
  x <- calcFunc(x)

  ## Make a new file name (remember to change the file extension)
  new_fname <- sub("something", "else", fname)

  ## Write the .RData file
  save(x, file = new_fname)


### Your workflow
## Generate a vector of files
my_files <- list.files()

## Do the work
res <- lapply(my_files, processFunc)

或者,不要保存文件。省略processFunc 中的save 调用,并返回data.frame 对象列表。然后使用data.table::rbindlist(res)do.call(rbind, list) 制作一个大的data.frame 对象。

【讨论】:

鉴于我当前的 .R 演算文件(我必须首先对其进行功能化)是指演算中的主要 data.frame,恐怕子设置会被覆盖。我在尝试使用by 命令时遇到了这个问题。我基本上是要求程序按组“做某事”,但“某事”指的是主数据框。因此,它与 by group 指令相矛盾,导致程序运行的次数与子集的数量一样多,但在主数据帧上。我害怕在这里遇到同样的问题。你怎么看?

以上是关于循环子集,获取文件并将结果保存在数据框中的主要内容,如果未能解决你的问题,请参考以下文章

如何从 imdb 获取更多信息并将其保存在 pandas 数据框中? [复制]

在字典上循环 SQL 查询

在 C++ 中获取多个输入文件并将其保存在数组中

循环获取,保持结果顺序

迭代列表并通过函数传递结果并将结果保存在数据框中

如何从 Javascript 提示框中获取值并将其传递给 PHP 变量以便能够保存在 SQL 中?