Как заменить значения NA в таблице для выбранных столбцов


82

Есть много сообщений о замене ценностей NA. Я знаю, что можно заменить NA в следующей таблице / кадре следующим:

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

Но что, если я хочу ограничить его только определенными столбцами? Я покажу вам пример.

Во-первых, давайте начнем с набора данных.

set.seed(1234)
x <- data.frame(a=sample(c(1,2,NA), 10, replace=T),
                b=sample(c(1,2,NA), 10, replace=T), 
                c=sample(c(1:5,NA), 10, replace=T))

Который дает:

    a  b  c
1   1 NA  2
2   2  2  2
3   2  1  1
4   2 NA  1
5  NA  1  2
6   2 NA  5
7   1  1  4
8   1  1 NA
9   2  1  5
10  2  1  1

Хорошо, поэтому я хочу ограничить замену только столбцами «a» и «b». Моя попытка была:

x[is.na(x), 1:2]<-0

и:

x[is.na(x[1:2])]<-0

Что не работает.

Моя попытка data.table, где y<-data.table(x), очевидно, никогда не сработала:

y[is.na(y[,list(a,b)]), ]

Я хочу передать столбцы внутри аргумента is.na, но это явно не сработает.

Я хотел бы сделать это в data.frame и data.table. Моя конечная цель - перекодировать 1: 2 в 0: 1 в 'a' и 'b', сохраняя при этом 'c' таким, какой он есть, поскольку это не логическая переменная. У меня куча столбцов, поэтому я не хочу делать это одну за другой. И я просто хотел бы знать, как это сделать.

У вас есть какие-нибудь предложения?

Ответы:


115

Ты можешь сделать:

x[, 1:2][is.na(x[, 1:2])] <- 0

или лучше (IMHO), используйте имена переменных:

x[c("a", "b")][is.na(x[c("a", "b")])] <- 0

В обоих случаях 1:2или c("a", "b")может быть заменен заранее заданным вектором.


Это делает работу. Что если я хочу искать "1"? Я пытался изменить его, но не смог заставить его работать.
jnam27

5
Наверное, вот так:x[, 1:2][x[, 1:2] == 1] <- 0
flodel

@flodel, почему datatable xпринимает матрицу в качестве своего первого члена только при назначении? Эта функция где-то задокументирована? Также я думаю, что вы забыли поставить запятую перед векторами с именами столбцов во втором примере.
ChiseledAbs

@ChiseledAbs, я думаю, вы имеете в виду матричную индексацию (см. Это, например, stackoverflow.com/a/13999583/1201032 ), но это не ограничивается назначениями, его также можно использовать для извлечения данных. По поводу пропущенной запятой: нет. Data.frames - это списки столбцов, поэтому, если вы используете один аргумент [, он извлечет указанные столбцы (см. Stackoverflow.com/a/21137524/1201032 ). Я надеюсь, что это ответит на ваш вопрос, но в будущем, пожалуйста, избегайте комментировать очень старые ответы, подобные этому; вместо этого разместите новый вопрос.
flodel

In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.Когда я использовал такой предопределенный вектор, x[Vpredefined][is.na(x[Vpredefined])] <- 0это дает мне ошибку
Рохит Салуджа

30

Изменить 2020-06-15

Начиная с data.table1.12.4 (октябрь 2019 г.), для этого были data.tableдобавлены две функции: nafillи setnafill.

nafill работает с колоннами:

cols = c('a', 'b')
y[ , (cols) := lapply(.SD, nafill, fill=0), .SDcols = cols]

setnafill работает с таблицами (замены происходят по ссылке / на месте)

setnafill(y, cols=cols, fill=0)
# print y to show the effect
y[]

Это также будет более эффективным, чем другие варианты; см. ?nafillдля получения дополнительной информации, версии NAвменения для временных рядов с переносом последнего наблюдения (LOCF) и переносом следующего наблюдения назад (NOCB) .


Это будет работать для вашей data.tableверсии:

for (col in c("a", "b")) y[is.na(get(col)), (col) := 0]

В качестве альтернативы, как указывает ниже Дэвид Аренбург, вы можете использовать set(побочное преимущество - вы можете использовать его либо на, data.frameлибо data.table):

for (col in 1:2) set(x, which(is.na(x[[col]])), col, 0)

Спасибо за это. Просто хотел знать, спустя 3 года, есть ли способы сделать это без цикла for? Думаю, команда data.table сделала бы это более кратким? Благодарю.
info_seekeR

1
@info_seekeR Я не знаю более лаконичного способа
eddi

это лучшее решение, чем выбранный ответ flodel. Подход Флоделя использует оператор присваивания <- и, следовательно, включает ненужное копирование данных.
Майкл

@MichaelChirico В первой части вашего комментария вы добавили шаг, out <- xчтобы избежать недопонимания с x data.frame из вопроса? В противном случае это еще более короткая команда: y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]пропуск имени переменной 'out' и использование 'x'.
Йоанн Пейджод

@MichaelChirico Верно! Я совершенно забыл о нафилле ()
Йоанн Пейджо

22

Основываясь на ответе @Robert McDonald tidyr::replace_na(), вот несколько dplyrвариантов управления тем, какие столбцы NAзаменяются:

library(tidyverse)

# by column type:
x %>%
  mutate_if(is.numeric, ~replace_na(., 0))

# select columns defined in vars(col1, col2, ...):
x %>%
  mutate_at(vars(a, b, c), ~replace_na(., 0))

# all columns:
x %>%
  mutate_all(~replace_na(., 0))

1
С помощью этой функции я получаю ошибку: Error in replace_na(., 0) : argument "value" is missing, with no default. Есть предложения, что изменить?
Tim M. Schendzielorz

17

Теперь это тривиально в tidyr с помощью replace_na (). Похоже, что функция работает как с data.tables, так и с data.frames:

tidyr::replace_na(x, list(a=0, b=0))

2

Не уверен, что это более сжато, но эта функция также найдет и разрешит замену NA (или любого другого значения) в выбранных столбцах таблицы data.table:

update.mat <- function(dt, cols, criteria) {
  require(data.table)
  x <- as.data.frame(which(criteria==TRUE, arr.ind = TRUE))
  y <- as.matrix(subset(x, x$col %in% which((names(dt) %in% cols), arr.ind = TRUE)))
  y
}

Чтобы применить это:

y[update.mat(y, c("a", "b"), is.na(y))] <- 0

Функция создает матрицу выбранных столбцов и строк (координаты ячеек), которые соответствуют критериям ввода (в данном случае is.na == TRUE).


1

Мы можем решить эту проблему data.tableс помощью tidyr::repalce_naфункции иlapply

library(data.table)
library(tidyr)
setDT(df)
df[,c("a","b","c"):=lapply(.SD,function(x) replace_na(x,0)),.SDcols=c("a","b","c")]

Таким образом, мы также можем решить вставить столбцы со NAстрокой. Сначала мы replace_na(x,""), потом можем использовать stringr::str_cдля объединения столбцов!


1
Спасибо за этот фрагмент кода, который может оказать некоторую немедленную помощь. Надлежащее объяснение будет значительно улучшить свою долгосрочную ценность, показывая , почему это является хорошим решением проблемы и сделает его более полезным для читателей будущих с другими подобными вопросами. Пожалуйста , измените свой ответ , чтобы добавить некоторые объяснения, в том числе допущений , которые вы сделали.
CertainPerformance 01

0

Для конкретного столбца есть альтернатива с sapply

DF <- data.frame(A = letters[1:5],
             B = letters[6:10],
             C = c(2, 5, NA, 8, NA))

DF_NEW <- sapply(seq(1, nrow(DF)),
                    function(i) ifelse(is.na(DF[i,3]) ==
                                       TRUE,
                                       0,
                                       DF[i,3]))

DF[,3] <- DF_NEW
DF

0

это очень удобно с {data.table} и {stringr}

library(data.table)
library(stringr)

x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]

К вашему сведению


0

Начиная с data.table y, вы можете просто написать:
y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]
Не забудьте library(data.table)перед созданием yи запуском этой команды.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.