将空白单元格更改为“ NA”


79

这是我的数据的链接

我的目标是为所有空白单元格分配“ 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

使用文字而非图片/链接作为文字,包括表格和ERD。释义或引用其他文字。仅将图像用于不能表示为文本的内容或将其用作扩展文本。无法搜索或剪切和粘贴图像。在图像中包括图例/键和说明。使您的帖子自成体系。使用编辑功能插入图像/链接。
philipxy

Answers:


95

我假设您正在谈论第5行的“性别”。可能是这样的情况,在data2.csv文件中,单元格包含一个空格,因此R不认为该单元格为空。

另外,我注意到在第5行的“车轴”和“门”列中,从data2.csv读取的原始值为字符串“ NA”。您可能还希望将其视为na.strings。去做这个,

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

编辑:

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

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

34

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

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

2
也可以gsub("^$", NA, trimws(x))用于处理一个单元格中的多个空间。尽管请注意,这两种方法都将所有列都转换为字符串/字符变量(如果尚未转换)。
JWilliman

26

一个更友好的解决方案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)

如果表格中包含日期,则应考虑使用类型更安全ifelse


11
如何添加一个新的库,创建一个新的函数更友好?而且我认为您将需要ifelse(x %in% c(""," ","NA"), NA, x)
zx8754

4
与函数一起使用mutate_each可提供更大的灵活性和可重复使用的模式。dplyr在当今的R工作流程中无所不在,并且只是为了使答案独立而添加。我认为这x!=""是正确的,因为“”和“ NA”都不为空。此外,@ sclarky的答案对于包含数字的数据帧失败,而@Badoe的答案并不能真正解决现有data.frames的问题,因此似乎没有其他答案可以通用的方式回答问题。我很高兴了解更好的解决方案。
Holger Brandl

1
dplyr在当今的R工作流中无所不在-并非如此。而“和@ Badoe's并不能真正解决现有data.frames问题”又意味着什么呢?您可以在该陈述中扩大一点吗?
David Arenburg '16

10
Badoe详细介绍了如何read.csv从文件中读取表时配置为将空白单元格转换为NA。但是,由于问题的标题是“将空白单元格更改为“ NA””,因此完整的答案应涵盖环境中已经存在data.frame并且用户希望摆脱空白单元格的情况。
Holger Brandl

1
这可能不是OP想要的,但是它帮助我计算了缺失值,包括空字符串和NA。df %>% mutate_all(funs(empty_as_na)) %>% summarize_all(funs(sum(is.na(.))))尽管dplyr可能会被采用,也可能不会被广泛采用,但它确实在包括我在内的大部分R用户中都非常流行,因此感谢此解决方案。
丹妮德

22

这应该可以解决问题

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

1
我在sf对象上尝试了此操作,并引发了解析错误:未知的WKB类型12。似乎mutate尝试替换几何中的某些内容。
aae

15

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

如果变量是数字,则简单df$Var[df$Var == ""] <- NA就足够了。但是,如果变量是一个因数,则需要先将其转换为字符,然后""用所需的值替换单元格,然后将其转换回因数。因此,在这种情况下,您Sex可以假设变量是一个因素,如果您要替换空单元格,可以执行以下操作:

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

3

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

查看更多评论:

#' 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)
}

3

您也可以mutate_atdplyr

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(.))))

上面的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(.))))

2

尽管上面的许多选项都能正常运行,但我发现非目标变量的强制性存在chr问题。使用ifelsegrepl内部lapply解决此脱靶效应(在有限的测试中)。在以下位置使用slarky的正则表达式grepl

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]“数字”


2

我怀疑每个人都已经有了答案,尽管万一有人来找,dplyr na_if()从我的角度来看将比上述提到的效率更高:

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

这是利用阅读器的read_delim函数的另一种方法。我刚刚接了(可能广为人知,但我将在此处存档以供将来的用户使用)。这是非常简单的方法,比上面的方法更具通用性,因为您可以在csv文件中捕获所有类型的空白值和与NA相关的值:

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

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

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


0

你不能只用

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

应该在读取数据时将所有空格都转换为NA,并确保在报价之间留一个空格


如果您在引号之间没有空格,会发生什么?
Nneka

0

对于那些想知道使用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代替匹配项。

我将继续改进此功能以使其更快。


-3

dplyr通过cran在R中安装来调用软件包

library(dplyr)

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

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

如果该列包含“-”,“”,0,则根据空白单元格的类型在代码中进行更改

例如,如果我得到一个像“”而不是“-”的空白单元格,则使用以下代码:

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

1
该答案dplyr在加载后不会使用,并且无法很好地扩展到OP正在寻找的“所有列”。
格雷戈尔·托马斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.