【问题标题】:filter(!is.na(column)) is not removing NA's from column in Rfilter(!is.na(column)) 没有从 R 中的列中删除 NA
【发布时间】:2023-03-13 02:29:01
【问题描述】:

我正在重做一项学习作业,看看我是否可以改进它并重新开始。任务是编写一个函数,给定 2 个变量“state”和“outcome”,返回给定结果/疾病死亡率最低的州医院名称。 由于某种原因,我的 filter(!is.na()) 行似乎不起作用。我感觉这与我使用粘贴来选择列名这一事实有关,但在我的测试中这似乎并不重要。

代码如下:

library(dplyr)
data <- read.csv("outcome-of-care-measures.csv", colClasses = "character")

dataSelected <- data %>%
        select("Hospital.Name", "State", "Hospital.30.Day.Death..Mortality..Rates.from.Heart.Attack", "Hospital.30.Day.Death..Mortality..Rates.from.Heart.Failure", "Hospital.30.Day.Death..Mortality..Rates.from.Pneumonia")

colnames(dataSelected) <- c("HostpitalName","State","DeathRateHeartAttack","DeathRateHeartFailure","DeathRatePneumonia")

dataSelected[,3] <- as.numeric(dataSelected[,3])
dataSelected[,4] <- as.numeric(dataSelected[,4])
dataSelected[,5] <- as.numeric(dataSelected[,5])


best <- function(state,outcome){
        column <- paste('DeathRate',outcome, sep = "")
        if (state %in% dataSelected$State < 1){
                return('Invalid state')
        } else if (column %in% colnames(dataSelected) < 1){
                return('Invalid outcome')
        } else{
        BestHospitals <- dataSelected %>%
                select(HostpitalName,State,column) %>%
                filter(!is.na(column)) %>%
                filter(State == state) %>%
                arrange(column,HostpitalName)
        return(BestHospitals[1,1])
        }
}

我的函数调用

best("AL","HeartAttack")

版本信息

平台 x86_64-apple-darwin15.6.0
拱 x86_64
操作系统 darwin15.6.0
系统 x86_64、darwin15.6.0
状态
专业 3
次要 6.1
2019 年
07月
第 5 天
svn 版本 76782
语言 R
version.string R 版本 3.6.1 (2019-07-05) 昵称 脚趾动作

dput(head(dataSelected)) 的输出:

structure(list(HostpitalName = c("SOUTHEAST ALABAMA MEDICAL CENTER", 
"MARSHALL MEDICAL CENTER SOUTH", "ELIZA COFFEE MEMORIAL HOSPITAL", 
"MIZELL MEMORIAL HOSPITAL", "CRENSHAW COMMUNITY HOSPITAL", "MARSHALL MEDICAL CENTER NORTH"
), State = c("AL", "AL", "AL", "AL", "AL", "AL"), DeathRateHeartAttack = c(14.3, 
18.5, 18.1, NA, NA, NA), DeathRateHeartFailure = c(11.4, 15.2, 
11.3, 13.6, 13.8, 12.5), DeathRatePneumonia = c(10.9, 13.9, 13.4, 
14.9, 15.8, 8.7)), row.names = c(NA, 6L), class = "data.frame")

【问题讨论】:

  • 欢迎来到 SO!我们确实需要查看(部分)您的数据。请将dput(dataSelected)(或dput(head(dataSelected)))的输出添加到您的问题中,以及您对best 函数的实际调用。两个建议:您确定您的数据包含NA 而不是字符"NA"?您不能将列名作为字符串传递给dplyr 动词。您需要注意非标准评估NSE
  • 感谢您的快速回答!我已经添加了你的建议。可以看出:数据确实包含实际的 NA。我实际上相当确定您的第二个建议(将字符串作为列名传递)是问题所在。但是,如何优雅地解决将“结果”参数转换为列名的问题,以便可以将其与 dplyr 一起使用?

标签: r dplyr filter


【解决方案1】:

按列号而不是名称过滤怎么样?

best <- function(state,outcome){
        column <- paste('DeathRate',outcome, sep = "")
        if (state %in% dataSelected$State < 1){
                return('Invalid state')
        } else if (column %in% colnames(dataSelected) < 1){
                return('Invalid outcome')
        } else{
        BestHospitals <- dataSelected %>%
                select(HostpitalName,State,column) %>%
                filter(!is.na(.[,3])) %>%
                filter(State == state) %>%
                arrange(desc(.[3])))
        return(BestHospitals[1,1])
        }
}

【讨论】:

  • 感谢您的回答!这不会导致 select 出现同样的问题吗?
  • 不,不会的!感谢您的优雅回答。对于文档:我删除了“排列”行中的一个括号并删除了 desc,因为它会返回最高死亡率而不是最低死亡率。
【解决方案2】:

我冒昧地重写了你的函数。

# it is usually a bad idea to insert a global variable (like your data frame) inside a function. 
best <- function(dat=NULL,state=NULL,outcome=NULL){ 
  
  column <- paste('DeathRate',outcome, sep = "")
  
  if (!state %in% dat$State | !column %in% colnames(dat)){
    stop('Invalid input')
  } # negating and using or "|" makes it easier to read
  else{
    BestHospitals <- dat %>%
      select(HostpitalName,State,column) %>%
      na.omit() %>% # for your purpose the much more concise na.omit() is a better option
      filter(State == state) %>%
      arrange(column,HostpitalName) %>% 
      filter(row_number()==1) #dplyr way to choose the first row
    
    return(BestHospitals)
  }
}

best(dat = dataSelected, state = "AL", outcome = "HeartAttack")

                   HostpitalName State DeathRateHeartAttack
1 ELIZA COFFEE MEMORIAL HOSPITAL    AL                 18.1

【讨论】:

  • 谢谢 :) 这有助于我学习
【解决方案3】:

这是您的函数的类似 tidyverse 的版本。

作为 D.J. cmets,在函数中包含对全局对象 (dataSelected) 的引用不是一个好习惯。将其作为参数传递要好得多。这还具有允许您在管道中使用该函数的有益副作用。

另外,HostpitalName 可能是一个错字。你的意思是HospitalName吗?由于您不止一次使用了奇怪的拼写,所以我保留了它。

虽然我理解您为什么允许用户通过将公共前缀 "DeathRate" 粘贴到 outcome 中传递的值来缩短所需结果的名称,但这可能不是最佳做法,因为用户需要了解此约定,并将函数的使用限制为遵循此约定的数据框和列。它也不适合 tidyverse 语法。

best <- function(d, state, outcome){
  # By adding d as the first parameter, you make it easy to use the function in
  # a pipe.  And on data frames other than dataSelected.
  qOutcome <- enquo(outcome)
  # calling stop is better than returning an error message as 
  # it stops processing immediately.
  if (!(state %in% (d %>% distinct(State) %>% pull(State) ))) {
    stop('Invalid state')
  }
  if (!(as_label(qOutcome) %in% colnames(d)) ){
    stop('Invalid outcome')
  }
  # Converting original code to equivalent tidyverse idioms.
  # HostpitalName should perhaps be HospitalName in the source data frame
  d %>%
    select(HostpitalName, State, !! qOutcome) %>%
    filter(!is.na(!! qOutcome)) %>%
    filter(State == state) %>%
    arrange(!! qOutcome, HostpitalName) %>% 
    pull(HostpitalName) %>% 
    head(1)
}

所以我们可以写

dataSelected %>% best("AL", DeathRateHeartFailure)
[1] "ELIZA COFFEE MEMORIAL HOSPITAL"

或者说,

dataSelected %>% best("AL", DeathRatePneumonia)
[1] "MARSHALL MEDICAL CENTER NORTH"

【讨论】:

  • 非常感谢,这一切都很有趣。拼写确实很奇怪,不幸的是创建原始数据集的人犯了一个错字。
猜你喜欢
  • 1970-01-01
  • 2022-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
相关资源
最近更新 更多