【问题标题】:Using same function on multiple datasets and using specific columns在多个数据集上使用相同的函数并使用特定的列
【发布时间】:2019-10-17 20:00:49
【问题描述】:

我有 8 个数据集,我想在每个数据集的 3 列(var1、var2、var3)上应用一个函数将任何小于 5 的数字转换为 NA。我怎样才能编写一个函数来有效和更快地做到这一点?我经历了很多关于堆栈溢出的此类问题,但我没有找到任何使用特定列的答案。我已经编写了要替换的函数,但无法弄清楚如何应用于所有数据集。

Input:
Data1
variable1 variable2 variable3 variable4
10           36        56        99
15           3         2         56
4            24        1         1

Expected output:
variable1 variable2 variable3 variable4
10           36         56        99
15           NA         NA        56
NA           24        NA         1

对另外 7 个数据集执行相同的操作。

到目前为止,我已将所需的变量和数据集存储在两个不同的列表中。

var1=enquo(variable1)
var2=enquo(variable2)
var3=enquo(variable3)
Total=3


listofdfs=list()
listofdfs_1=list()
for(i in 1:8) {
  df=sym((paste0("Data",i)))
listofdfs[[i]]=df
  }

for(e in 1:Ttoal) {    
listofdfs[[e]]= eval(sym(paste0("var",e)))
}

选中的列会经过这个函数:

temp_1=function(x,h) {
  h=enquo(h)
  for(e in 1:Total) {    
  if(substr(eval(sym(paste0("var",e))),1,3)=="var") {
 y= x %>% mutate_at(vars(!!h), ~ replace(., which(.<=5),NA))
 return(y)
  }

}
}

我期待着什么:

lapply(对于每个数据集的选定列,temp_1)

【问题讨论】:

  • @MrFlick 很抱歉给您带来不便!我已经编辑了问题。
  • @MrFlick 抱歉我已经编辑了!

标签: r function loops for-loop


【解决方案1】:

这是一个应该可行的简单方法:

cols_to_edit = paste0("var", 1:3)
result_list = lapply(list_of_dfs, function(x) {
  x[cols_to_edit][x[cols_to_edit] < 5] = NA
  return(x)
})

我假设您的起始数据位于名为 list_of_dfs 的列表中,要编辑的列的名称在所有数据框中都相同,并且您可以使用这些名称构造一个字符向量 cols_to_edit

【讨论】:

  • 我的变量名在所有数据集中都是相同的,但将来可能会改变,因此我尝试使用 like 宏。将来的变量名可以将变量3更改为变量4,因此我想使用宏。当我尝试你的代码时: cols_to_edit = eval(sym(paste0("var", 1:3))) result = lapply(list_of_dfs, function(x) { x[cols_to_edit][x[cols_to_edit] *tmp*[cols_to_edit] 中的错误:'symbol' 类型的对象不是子集
  • 是的,所以我的代码有效,但是当您将其更改为 eval(sym()) 时,它就不起作用了。为什么不直接创建字符串列名?似乎仍然是模块化的,但要简单得多。您可以轻松地将cols_to_edit = paste0("var", 1:3) 更改为cols_to_edit = paste0("var", 1:4) --- 除了其余代码也可以工作。
  • 但是 var1 可以类似于 variable1。我不想硬编码。将来,如果 var1 类似于某个不同的名称,那么如果它不是硬编码的话就很容易了。因此我需要使用 eval
【解决方案2】:

这是问题中问题的解决方案。
首先,创建一个测试数据集。

createData <- function(Total = 3){
  numcols <- Total + 1
  set.seed(1234)
  for(i in 1:8){
    tmp <- replicate(numcols, sample(10, 20, TRUE))
    tmp <- as.data.frame(tmp)
    names(tmp) <- paste0("var", seq_len(numcols))
    assign(paste0("Data", i), tmp, envir = .GlobalEnv)
  }
}

createData()

现在,数据转换。
如果许多数据帧都在 "list" 中,这会容易得多。

df_list <- mget(ls(pattern = "^Data"))

我将介绍解决方案,一个基本 R 解决方案和一个 tidyverse 解决方案。请注意,这两种解决方案都将使用函数temp_1,仅用基础 R 编写。

library(tidyverse)

temp_1 <- function(x, h){
  f <- function(v){
    is.na(v) <- v <= 5
    v
  }
  x[h] <- lapply(x[h], f)
  x
}

h <- grep("var[123]", names(df_list[[1]]), value = TRUE)

df_list1 <- lapply(df_list, temp_1, h)
df_list2 <- df_list %>% map(temp_1, h)

identical(df_list1, df_list2)
#[1] TRUE

【讨论】:

  • 您好,很抱歉,但我忘了提到我需要使用 vars 作为宏变量,这样当我使用 eval 时,它会解析为 Variable1、Variable2 和 Variable3。那你能帮忙吗?存储名称的变量 h 不会像您在代码中提到的那样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-25
  • 2016-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
相关资源
最近更新 更多