Змініть порожні клітини на “NA”


80

Ось посилання на мої дані.

Моя мета - призначити "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. Перефразовуйте або цитуйте з іншого тексту. Використовуйте зображення лише для того, що не можна висловити як текст, або для збільшення тексту. Зображення не можна шукати, вирізати та вставляти. Включіть легенду / ключ та пояснення із зображенням. Зробіть свою публікацію автономною. Вставляйте зображення / посилання за допомогою функцій редагування.
Філіпсія

Відповіді:


98

Я припускаю, що ви говорите про рядок 5 рядка "стать". Може бути так, що у файлі data2.csv клітинка містить пробіл, і, отже, R. не вважається порожнім.

Крім того, я помітив, що в рядку 5 стовпців "осі" та "двері" вихідні значення, прочитані з data2.csv, є рядком "NA". Ви, ймовірно, хочете також поводитись із ними як із na.strings. Зробити це,

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

РЕДАГУВАТИ:

Я завантажив ваші дані2.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

27

Більш зручне для очей рішення 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 "? Чи можете ви трохи розширити це твердження?
Девід Аренбург

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. Здається, мутація намагалася замінити щось у геометріях.
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_atвdplyr

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проблемних. Використання ifelseі greplвсередині 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 читача. Я щойно взяв (можливо, широко відомо, але я буду архівувати тут для майбутніх користувачів). Це дуже прямо і універсально, ніж вище, оскільки ви можете захопити всі типи порожніх значень та значень, пов'язаних з NA, у своєму файлі csv:

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

Зверніть увагу на підкреслення у версії readr порівняно з базою R "." у read_csv.

Сподіваємось, це допомагає тому, хто блукає по посту!


0

Не могли б ви просто використовувати

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

слід перетворити всі порожні значення на NA, оскільки дані зчитуються, обов’язково вставте пробіл між вашим котируванням


що трапиться, якщо не розставити пробіл між цитатами?
Ннека,

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.
Грегор Томас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.