【问题标题】:Change the Blank Cells to "NA"将空白单元格更改为“NA”
【发布时间】:2014-08-02 01:16:14
【问题描述】:

这是我的数据的link

我的目标是将“NA”分配给所有空白单元格,而不考虑分类值或数值。我正在使用 na.strings=""。但它并没有将 NA 分配给所有空白单元格。

## reading the data
dat <- read.csv("data2.csv")
head(dat)
  mon hr        acc   alc sex spd axles door  reg                                 cond1 drug1
1   8 21 No Control  TRUE   F   0     2    2      Physical Impairment (Eyes, Ear, Limb)     A
2   7 20 No Control FALSE   M 900     2    2                                Inattentive     D
3   3  9 No Control FALSE   F 100     2    2 2004                                Normal     D
4   1 15 No Control FALSE   M   0     2    2      Physical Impairment (Eyes, Ear, Limb)     D
5   4 21 No Control FALSE      25    NA   NA                                                D
6   4 20 No Control    NA   F  30     2    4                Drinking Alcohol - Impaired     D
       inj1 PED_STATE st rac1
1     Fatal      <NA>  F <NA>
2  Moderate      <NA>  F <NA>
3  Moderate      <NA>  M <NA>
4 Complaint      <NA>  M <NA>
5 Complaint      <NA>  F <NA>
6  Moderate      <NA>  M <NA>


## using na.strings
dat2 <- read.csv("data2.csv", header=T, na.strings="")
head(dat2)
  mon hr        acc   alc sex spd axles door  reg                                 cond1 drug1
1   8 21 No Control  TRUE   F   0     2    2 <NA> Physical Impairment (Eyes, Ear, Limb)     A
2   7 20 No Control FALSE   M 900     2    2 <NA>                           Inattentive     D
3   3  9 No Control FALSE   F 100     2    2 2004                                Normal     D
4   1 15 No Control FALSE   M   0     2    2 <NA> Physical Impairment (Eyes, Ear, Limb)     D
5   4 21 No Control FALSE      25    NA   NA <NA>                                  <NA>     D
6   4 20 No Control    NA   F  30     2    4 <NA>           Drinking Alcohol - Impaired     D
       inj1 PED_STATE st rac1
1     Fatal        NA  F   NA
2  Moderate        NA  F   NA
3  Moderate        NA  M   NA
4 Complaint        NA  M   NA
5 Complaint        NA  F   NA
6  Moderate        NA  M   NA

【问题讨论】:

  • use text, not images/links, for text--including tables & ERDs. 转述或引用其他文本。仅将图像用于无法表达为文本或增强文本的内容。无法搜索或剪切和粘贴图像。在图像中包含图例/键和说明。使您的帖子自成一体。使用编辑功能插入图片/链接。

标签: r na


【解决方案1】:

我假设您在谈论第 5 行的“性别”列。可能是在 data2.csv 文件中,单元格包含一个空格,因此 R 不会将其视为空。

另外,我注意到在第 5 行的“axles”和“door”列中,从 data2.csv 读取的原始值是字符串“NA”。您可能也希望将它们视为 na.strings。为此,

dat2 <- read.csv("data2.csv", header=T, na.strings=c("","NA"))

编辑:

我下载了你的 data2.csv。是的,第 5 行“性别”列中有一个空格。所以你想要

na.strings=c(""," ","NA")

【讨论】:

    【解决方案2】:

    您可以使用 gsub 将多个空的突变(如“”或空格)替换为 NA:

    data= data.frame(cats=c('', ' ', 'meow'), dogs=c("woof", " ", NA))
    apply(data, 2, function(x) gsub("^$|^ $", NA, x))
    

    【讨论】:

    • 也可以使用gsub("^$", NA, trimws(x)) 处理单元格内的多个空格。不过,请注意这两种方法都将所有列转换为字符串/字符变量(如果还没有的话)。
    【解决方案3】:

    这应该可以解决问题

    dat <- dat %>% mutate_all(na_if,"")
    

    【讨论】:

    • 我在一个 sf 对象上尝试过,它抛出了一个解析错误:未知 WKB 类型 12。似乎 mutate 试图替换几何中的某些东西。
    【解决方案4】:

    使用dplyr 的更眼睛友好的解决方案是

    require(dplyr)
    
    ## fake blank cells
    iris[1,1]=""
    
    ## define a helper function
    empty_as_na <- function(x){
        if("factor" %in% class(x)) x <- as.character(x) ## since ifelse wont work with factors
        ifelse(as.character(x)!="", x, NA)
    }
    
    ## transform all columns
    iris %>% mutate_each(funs(empty_as_na)) 
    

    要将更正仅应用于列的子集,您可以使用 dplyr 的列匹配语法指定感兴趣的列。示例:mutate_each(funs(empty_as_na), matches("Width"), Species)

    如果您的表格包含日期,您应该考虑使用ifelsemore typesafe 版本

    【讨论】:

    • 添加一个新库,创建一个新函数如何更眼睛友好?我认为你需要ifelse(x %in% c(""," ","NA"), NA, x)
    • 将函数与mutate_each 一起使用提供了更大的灵活性和可重用的模式。 dplyr 在当今的 R 工作流程中无处不在,只是为了使答案自成一体而添加。我认为x!="" 在这里是正确的,因为“”和“NA”都不是空白的。此外,@sclarky 对包含数字的数据帧的回答失败了,@Badoe 并没有真正解决现有数据帧的问题,因此似乎还没有其他答案以通用方式回答这个问题。我很高兴了解更好的解决方案。
    • dplyr 在当今的 R 工作流程中无处不在——不,不是。 “and @Badoe's 并没有真正解决现有 data.frames 的问题”甚至意味着什么?你能扩展一下那个陈述吗?
    • Badoe 详细说明了如何配置 read.csv 在从文件中读取表格时将空白单元格转换为 NA。但是,由于问题的标题是“将空白单元格更改为“NA””,因此完整的答案应该涵盖 data.frame 已经在环境中并且用户想要摆脱空白单元格的情况。跨度>
    • 这可能不是 OP 想要的,但它帮助我计算了缺失值,包括空字符串和 NA。 df %&gt;% mutate_all(funs(empty_as_na)) %&gt;% summarize_all(funs(sum(is.na(.)))) 虽然 dplyr 可能会或可能不会被广泛采用,但它确实在包括我在内的大部分 R 用户中很受欢迎,所以感谢这个解决方案。
    【解决方案5】:

    我最近遇到了类似的问题,这对我有用。

    如果变量是数字,那么一个简单的df$Var[df$Var == ""] &lt;- NA 就足够了。但是如果变量是一个因子,那么你需要先将它转换为字符,然后将""单元格替换为你想要的值,然后再转换回因子。举个例子,你的 Sex 变量,我认为这将是一个因素,如果你想替换空单元格,我会执行以下操作:

    df$Var <- as.character(df$Var)
    df$Var[df$Var==""] <- NA
    df$Var <- as.factor(df$Var)
    

    【讨论】:

      【解决方案6】:

      (dplyr 1.0.0)开始,我们可以使用across()

      注意:有时在变量中使用NA 会导致问题,您可能需要指定NA 的类型——例如,在本例中为NA_character_。对于嵌套的ifelse() 语句,您可以使用case_when()

      对于所有列:

      dat <- dat %>%
         mutate(across(everything(), ~ifelse(.=="", NA, as.character(.))))
      

      对于单个列:

      dat <- dat %>%
         mutate(across(c("Age","Gender"), ~ifelse(.=="", NA, as.character(.))))
      

      (上面的dplyr 0.8.0)开始,应该写的方式已经改变。在此之前,funs().funs (funs(name = f(.)) 中。而不是funs,现在我们使用list (list(name = ~f(.)))

      请注意,还有一种更简单的方法来列出列名! (列名和列索引都起作用)

      dat <- dat %>%
      mutate_at(.vars = c("Age","Gender"),
          .funs = list(~ifelse(.=="", NA, as.character(.))))
      

      原答案:

      你也可以在dplyr中使用mutate_at

      dat <- dat %>%
      mutate_at(vars(colnames(.)),
              .funs = funs(ifelse(.=="", NA, as.character(.))))
      

      选择要更改的单个列:

      dat <- dat %>%
      mutate_at(vars(colnames(.)[names(.) %in% c("Age","Gender")]),
              .funs = funs(ifelse(.=="", NA, as.character(.))))
      

      【讨论】:

      • ~ifelse(.=="", NA, as.character(.)))) 你能告诉我.== 是什么意思吗?
      • == 用于相等性测试,. 引用它正在测试的变量 - 例如 across(c("Age","Gender"). 将引用 "Age",然后是 "Gender"
      【解决方案7】:

      如果您使用have或foreign包读取外部文件,我的函数会考虑因素,字符向量和潜在属性。它还允许匹配不同的自定义 na.strings。要转换所有列,只需使用 lappy:df[] = lapply(df, blank2na, na.strings=c('','NA','na','N/A','n/a','NaN','nan'))

      查看更多cmets:

      #' Replaces blank-ish elements of a factor or character vector to NA
      #' @description Replaces blank-ish elements of a factor or character vector to NA
      #' @param x a vector of factor or character or any type
      #' @param na.strings case sensitive strings that will be coverted to NA. The function will do a trimws(x,'both') before conversion. If NULL, do only trimws, no conversion to NA.
      #' @return Returns a vector trimws (always for factor, character) and NA converted (if matching na.strings). Attributes will also be kept ('label','labels', 'value.labels').
      #' @seealso \code{\link{ez.nan2na}}
      #' @export
      blank2na = function(x,na.strings=c('','.','NA','na','N/A','n/a','NaN','nan')) {
          if (is.factor(x)) {
              lab = attr(x, 'label', exact = T)
              labs1 <- attr(x, 'labels', exact = T)
              labs2 <- attr(x, 'value.labels', exact = T)
      
              # trimws will convert factor to character
              x = trimws(x,'both')
              if (! is.null(lab)) lab = trimws(lab,'both')
              if (! is.null(labs1)) labs1 = trimws(labs1,'both')
              if (! is.null(labs2)) labs2 = trimws(labs2,'both')
      
              if (!is.null(na.strings)) {
                  # convert to NA
                  x[x %in% na.strings] = NA
                  # also remember to remove na.strings from value labels 
                  labs1 = labs1[! labs1 %in% na.strings]
                  labs2 = labs2[! labs2 %in% na.strings]
              }
      
              # the levels will be reset here
              x = factor(x)
      
              if (! is.null(lab)) attr(x, 'label') <- lab
              if (! is.null(labs1)) attr(x, 'labels') <- labs1
              if (! is.null(labs2)) attr(x, 'value.labels') <- labs2
          } else if (is.character(x)) {
              lab = attr(x, 'label', exact = T)
              labs1 <- attr(x, 'labels', exact = T)
              labs2 <- attr(x, 'value.labels', exact = T)
      
              # trimws will convert factor to character
              x = trimws(x,'both')
              if (! is.null(lab)) lab = trimws(lab,'both')
              if (! is.null(labs1)) labs1 = trimws(labs1,'both')
              if (! is.null(labs2)) labs2 = trimws(labs2,'both')
      
              if (!is.null(na.strings)) {
                  # convert to NA
                  x[x %in% na.strings] = NA
                  # also remember to remove na.strings from value labels 
                  labs1 = labs1[! labs1 %in% na.strings]
                  labs2 = labs2[! labs2 %in% na.strings]
              }
      
              if (! is.null(lab)) attr(x, 'label') <- lab
              if (! is.null(labs1)) attr(x, 'labels') <- labs1
              if (! is.null(labs2)) attr(x, 'value.labels') <- labs2
          } else {
              x = x
          }
          return(x)
      }
      

      【讨论】:

        【解决方案8】:

        更新答案 在@camnesia 利用dplyr 的cross() 的出色选项的基础上,我发现一些有用的附加选项:

        使用 na_if()

        mutate(across(c("Age","Gender"), ~na_if(., ""))).

        另外也许值得逛的人注意一下,除了用 c("") 指定列外,还可以使用 dplyr 选择器:

        mutate(across(starts_with("x_"), ~na_if(., ""))).

        最后,如果你想用 NA 替换多个值,我也喜欢这里的 replace():

        使用替换():

        mutate(across(everything(), ~replace(., . %in% c("N.A.", "NA", "N/A", ""), NA)))

        原答案 我怀疑每个人都已经有了答案,但万一有人来看, dplyr na_if() (从我的角度来看)将是提到的那些更有效的:

        # Import CSV, convert all 'blank' cells to NA
        dat <- read.csv("data2.csv") %>% na_if("")
        

        这是一种利用 readr 的 read_delim 函数的附加方法。我刚刚拿起(可能广为人知,但我会在这里存档以供将来的用户使用)。这比上面的更简单,更通用,因为您可以在 csv 文件中捕获所有类型的空白和 NA 相关值:

        dat <- read_csv("data2.csv", na = c("", "NA", "N/A"))
        

        请注意阅读器版本与 Base R 中的下划线“。”在 read_csv 中。

        希望这可以帮助那些在帖子上徘徊的人!

        【讨论】:

          【解决方案9】:

          我认为 data.table 是您最好的选择(为了代码的简单性和速度)。以下将用 NA 替换名为“data”的数据集中的所有空白:

          data[data==""] <- NA
          

          【讨论】:

            【解决方案10】:

            虽然上面的许多选项运行良好,但我发现将非目标变量强制转换为 chr 是有问题的。在lapply 中使用ifelsegrepl 可以解决这种脱靶效应(在有限的测试中)。在grepl中使用slarky的正则表达式:

            set.seed(42)
            x1 <- sample(c("a","b"," ", "a a", NA), 10, TRUE)
            x2 <- sample(c(rnorm(length(x1),0, 1), NA), length(x1), TRUE)
            
            df <- data.frame(x1, x2, stringsAsFactors = FALSE)
            

            对字符类的强制问题:

            df2 <- lapply(df, function(x) gsub("^$|^ $", NA, x))
            lapply(df2, class)
            

            $x1 [1] “人物”

            $x2 [1] “人物”

            使用 ifelse 的解决方法:

            df3 <- lapply(df, function(x) ifelse(grepl("^$|^ $", x)==TRUE, NA, x))
            lapply(df3, class)
            

            $x1 [1] “人物”

            $x2 [1] “数字”

            【讨论】:

              【解决方案11】:

              你不能直接使用

              dat <- read.csv("data2.csv",na.strings=" ",header=TRUE)
              

              在读入数据时应将所有空白转换为 NA 一定要在你的引文之间留一个空格

              【讨论】:

              • 引号之间不加空格会怎样?
              【解决方案12】:

              对于那些想知道使用 data.table 方式的解决方案的人,这是我为其编写的函数,可在我的 Github 上找到:

              library(devtools)
              source_url("https://github.com/YoannPa/Miscellaneous/blob/master/datatable_pattern_substitution.R?raw=TRUE")
              dt.sub(DT = dat2, pattern = "^$|^ $",replacement = NA)
              dat2
              

              该函数遍历每一列,以确定哪一列包含模式匹配项。然后gsub() 仅应用于包含与模式"^$|^ $" 匹配的列,以用NAs 替换匹配。

              我会不断改进这个功能,让它更快。

              【讨论】:

                【解决方案13】:

                这对我有用。

                dataset <- read.csv(file = "data.csv",header=TRUE,fill = T,na.strings = "")
                

                【讨论】:

                  【解决方案14】:

                  通过从cran in r 安装调用dplyr

                  library(dplyr)
                  
                  (file)$(colname)<-sub("-",NA,file$colname) 
                  

                  它将特定列中的所有空白单元格转换为NA

                  如果列包含“-”,“”,0这样根据空白单元格的类型在代码中更改它

                  例如如果我得到一个像“”而不是“-”这样的空白单元格,那么使用这个代码:

                  (file)$(colname)<-sub("", NA, file$colname)
                  

                  【讨论】:

                  • 这个答案在加载后不使用dplyr,并且不能很好地扩展到“所有列”,就像 OP 正在寻找的那样。
                  猜你喜欢
                  • 2014-04-26
                  • 2017-03-15
                  • 1970-01-01
                  • 2019-03-27
                  • 2016-05-24
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多