Як замінити значення NA у таблиці для вибраних стовпців


82

Є багато публікацій про заміну значень 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

Гаразд, тому я хочу обмежити заміну лише стовпцями "а" та "б". Моєю спробою було:

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, чому таблиця даних xприймає матрицю як свого першого члена лише при призначенні? Ця особливість десь задокументована? Також я думаю, ви забули поставити кому перед векторами з іменами стовпців у вашому другому прикладі.
ChiseledAbs

@ChiseledAbs, я думаю, ви маєте на увазі індексацію матриці (див. Це, наприклад, stackoverflow.com/a/13999583/1201032 ), але це не обмежується призначеннями, воно також може використовуватися для отримання даних. Щодо відсутньої коми: ні. Data.frames - це списки стовпців, тому, якщо ви використовуєте один аргумент [, він витягне вказані стовпці (див. Stackoverflow.com/a/21137524/1201032 ). Сподіваюся, це відповідає на ваше запитання, але в майбутньому, будь ласка, уникайте коментування дуже старих відповідей, таких як ця; замість цього опублікуйте нове запитання.
флодель

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докладніше, останнє спостереження - перенесене вперед (LOCF) та наступне - спостереження - перенесене назад (NOCB) версія обчислення NAдля часових рядів.


Це буде працювати для вашої 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 Я не знаю більш стислого слова
Едді

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

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

@MichaelChirico Правда! Я зовсім забув про nafill ()
Йоанн Пейдж

22

Спираючись на відповідь @Robert McDonald's 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

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)})]

FYI


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.