Заменить все 0 значений на NA


152

У меня есть фреймворк с несколькими числовыми столбцами. Некоторая строка имеет значение 0, которое при статистическом анализе следует рассматривать как нулевое. Каков самый быстрый способ заменить все значения 0 на NULL в R?


17
Я не думаю, что вы хотите / можете заменить значения NULL, но NA служит этой цели в R lingo.
Чейз

Ответы:


260

Замена всех нулей на NA:

df[df == 0] <- NA



Объяснение

1. Это не NULLто, чем вам следует заменять нули. Как говорится в ?'NULL',

NULL представляет нулевой объект в R

который уникален и, я думаю, может рассматриваться как самый неинформативный и пустой объект. 1 Тогда неудивительно, что

data.frame(x = c(1, NULL, 2))
#   x
# 1 1
# 2 2

То есть R не резервирует места для этого нулевого объекта. 2 В то же время, глядя ?'NA'мы видим , что

NA - логическая константа длины 1, содержащая индикатор пропущенного значения. NA может быть приведен к любому другому векторному типу, кроме raw.

Важно отметить, NAчто его длина равна 1, поэтому R резервирует для него место. Например,

data.frame(x = c(1, NA, 2))
#    x
# 1  1
# 2 NA
# 3  2

Кроме того, структура фрейма данных требует, чтобы все столбцы имели одинаковое количество элементов, чтобы не было «дыр» (т. Е. NULLЗначений).

Теперь вы можете заменить нули на NULLв кадре данных в смысле полного удаления всех строк, содержащих хотя бы один ноль. При использовании, например, var, cov, или cor, что фактически эквивалентно первой замены нулей с NAи устанавливая значение , useкак "complete.obs". Однако обычно это неудовлетворительно, поскольку приводит к дополнительной потере информации.

2. Вместо того, чтобы запускать какой-то цикл, в решении я использую df == 0векторизацию. df == 0возвращает (попробуйте) матрицу того же размера, что и df, с элементами TRUEи FALSE. Далее нам также разрешено передавать эту матрицу в подмножество [...](см. ?'['). Наконец, хотя результат df[df == 0]интуитивно понятен, то, что df[df == 0] <- NAдает желаемый эффект , может показаться странным . Оператор присваивания <-действительно не всегда так умен и не работает таким образом с некоторыми другими объектами, но он работает с фреймами данных; см ?'<-'.


1 Пустое множество в теории множеств кажется каким-то образом связанным.
2 Еще одно сходство с теорией множеств: пустое множество - это подмножество каждого множества, но мы не резервируем для него места.


3
Каким будет эквивалентный синтаксис для объекта data.table?
itpetersen 07

6
Я вижу, что вы получили много голосов, но не думаю, что это должным образом покрывает крайние случаи нечисловых столбцов со значениями «0», которые не запрашивались для установки в <NA>.
IRTFM

38

Позвольте предположить, что ваш data.frame представляет собой смесь разных типов данных, и не все столбцы нужно изменять.

чтобы изменить только столбцы с 12 по 18 (из всего 21), просто сделайте это

df[, 12:18][df[, 12:18] == 0] <- NA

Это работает для меня, в то время как принятый ответ - нет
Патрик Куломб,

Это работает и является более гибким, чем принятый ответ.
drT

Двойное подмножество с []отличным! Такой очевидный и все еще такой скрытый :)
батискаф

25

dplyr::na_if() это вариант:

library(dplyr)  

df <- data_frame(col1 = c(1, 2, 3, 0),
                 col2 = c(0, 2, 3, 4),
                 col3 = c(1, 0, 3, 0),
                 col4 = c('a', 'b', 'c', 'd'))

na_if(df, 0)
# A tibble: 4 x 4
   col1  col2  col3 col4 
  <dbl> <dbl> <dbl> <chr>
1     1    NA     1 a    
2     2     2    NA b    
3     3     3     3 c    
4    NA     4    NA d

23

Альтернативный способ без [<-функции:

Образец кадра данных dat(беззастенчиво скопированный из ответа @Chase):

dat

  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

Нули можно заменить NAна is.na<-функцию:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

14
#Sample data
set.seed(1)
dat <- data.frame(x = sample(0:2, 5, TRUE), y = sample(0:2, 5, TRUE))
#-----
  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

#replace zeros with NA
dat[dat==0] <- NA
#-----
   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

12

Поскольку кто-то попросил эту версию Data.Table и данное решение data.frame не работает с data.table, я предлагаю решение ниже.

В основном используйте :=оператор ->DT[x == 0, x := NA]

library("data.table")

status = as.data.table(occupationalStatus)

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1  0
 8:      8           1  0
 9:      1           2 19
10:      2           2 40


status[N == 0, N := NA]

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1 NA
 8:      8           1 NA
 9:      1           2 19
10:      2           2 40

2
Или for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). См. Здесь более подробное обсуждение использования data.table для поиска и замены значений.
JWilliman

4

Вы можете заменить 0на NAтолько числовые поля (т.е. исключая такие вещи, как факторы), но он работает по столбцам:

col[col == 0 & is.numeric(col)] <- NA

С помощью функции вы можете применить это ко всему фрейму данных:

changetoNA <- function(colnum,df) {
    col <- df[,colnum]
    if (is.numeric(col)) {  #edit: verifying column is numeric
        col[col == -1 & is.numeric(col)] <- NA
    }
    return(col)
}
df <- data.frame(sapply(1:5, changetoNA, df))

Хотя вы можете заменить 1:5число столбцов во фрейме данных или на 1:ncol(df).


Я не уверен, что это правильное решение. Насчет столбцов 6 и больше. Их порежут.
userJT

Вот почему я предложил заменить 1:5с 1:ncol(df)в конце. Я не хотел делать уравнение слишком сложным или трудным для чтения.
Alium Britt

но что, если в столбцах 6 и 7 - тип данных char и замену производить не следует. В моей проблеме мне нужна замена только в столбцах с 12 по 15, но весь df имеет 21 столбец (многие вообще нельзя трогать).
userJT

Для вашего фрейма данных , вы можете просто изменить 1:5на номера столбцов , которые вы хотите изменились, как 12:15, но если вы хотите , чтобы подтвердить , что он будет воздействовать только на числовые столбцы , то просто завернуть вторую строчку функции в , если заявление, как это: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt

1

Если кто-то прибывает сюда через Google и ищет обратное (например, как заменить все NA в data.frame на 0), ответ будет

df[is.na(df)] <- 0

ИЛИ

Использование dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.