R 函数中的 dplyr::summarise() 失败并出现 "argument not numeric or logical" 错误

dplyr::summarise() in an R function fails with "argument not numeric or logical" error

我对 R 比较陌生,我正在尝试编写我的第一个多步函数。本质上,我想创建一个函数,它接受一个目录并在该目录中搜索以找到特定的列(在本例中为污染物)。然后找到该列的平均值并删除 NA。这是我目前所拥有的:

pollutantmean <- function(directory , pollutant , min_id = 1, max_id = 332) {

setwd(directory)

dirdata <- list.files(path=getwd() , pattern='*.csv' , full.names = TRUE) %>% lapply(read_csv) %>% bind_rows

specdata <- dirdata %>% filter(between(ID,min_id,max_id))

polspecdata <- specdata %>% select(pollutant)

polspecdatamean <- polspecdata %>% summarize(mean_pollutant=mean(pollutant,na.rm=TRUE))
} 

感觉自己好接近,结果报错:Warning message:In mean.default(pollutant, na.rm = TRUE) : argument is not numeric or logical:返回 NA。我认为错误是由于列 class 为 col_double。这可能是因为 dirdata 是从多个 csv 文件创建的。任何帮助将不胜感激。谢谢!

这是数据:zipfile_data

原始post中的代码失败,因为它在一个函数中使用了dplyr,但没有使用dplyr quoting functions。当我们通过 RStudio 调试器 运行 代码并停在第 7 行时,我们看到以下内容:

dplyr 没有按预期呈现 mean(pollutant, na.rm = TRUE) 中的函数参数,因此第 9 行失败。 mean() 函数失败,因为 pollutant 参数呈现为文本字符串,而不是 polspecdata 数据框中的列。

修复错误的一种方法是调整第 9 行以显式引用通过 %>% 管道运算符从先前函数传递的数据帧,使用提取运算符的 [[ 形式使用参数的字符串版本。

polspecdatamean <- polspecdata %>% summarize(mean_pollutant=mean(.data[[pollutant]],na.rm=TRUE))

最后,由于函数应该 return 父环境的平均值,我们在函数末尾添加第 9 行中创建的对象的打印。

polspecdatamean

由于这是 Coursera 上约翰霍普金斯大学 R 编程 课程的编程作业,我不会 post 一个完整的答案,因为这违反了 Coursera 的荣誉代码.

简化解决方案

在第 5 行过滤数据后,函数可以简单地 return 平均值如下。

mean(specdata[[pollutant]],na.rm=TRUE)

结论

对于这个特定的作业,使用 dplyr 会使作业比需要的更难,因为 dplyr 使用非标准评估而 dplyr 不是'直到序列中的第三门课程,它甚至都包含在 JHU 课程中。

该代码还有其他一些细微的缺陷,我们将对其进行更正作为 reader 的练习。例如,给定分配要求,函数应该能够处理以下输入:

pollutantmean("specdata","sulfate",23) # calc mean for sensor 23
pollutantmean("specdata","nitrate",70:72) # calc mean for sensors 70 - 72 
pollutantmean("specdata","sulfate",c(3,5,7,9)) # calc mean for sensors 3, 5, 7, and 9 

假设您将 pollutant 变量作为字符串传递,请尝试使用以下函数。

library(tidyverse)

pollutantmean <- function(directory , pollutant , min_id = 1, max_id = 332) {

  dirdata <- list.files(path=directory, pattern='*.csv' , full.names = TRUE) %>% 
                  map_df(read_csv)
   dirdata %>% 
      filter(between(ID,min_id,max_id)) %>%
      summarise(mean_pollutant= mean(!!sym(pollutant),na.rm=TRUE))
} 

所以你可以称它为

pollutantmean('/path', 'sulfate', 1, 10)

使用 !!sym 我们将 sulfate 评估为列而不是字符串。