Jak zamienić wartości NA w tabeli dla wybranych kolumn


82

Jest wiele postów dotyczących zastępowania wartości NA. Zdaję sobie sprawę, że w poniższej tabeli / ramce można zastąpić NA:

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

Ale co, jeśli chcę ograniczyć to tylko do niektórych kolumn? Pokażę ci przykład.

Najpierw zacznijmy od zbioru danych.

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

Co daje:

    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

Ok, więc chcę ograniczyć zamianę tylko do kolumn „a” i „b”. Moja próba była:

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

i:

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

Co nie działa.

Moja próba z danymi.table, gdzie y<-data.table(x)oczywiście nigdy nie zadziałała:

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

Chcę przekazać kolumny wewnątrz argumentu is.na, ale to oczywiście nie zadziała.

Chciałbym to zrobić w data.frame i data.table. Moim końcowym celem jest przekodowanie 1: 2 do 0: 1 w „a” i „b”, zachowując „c” taką, jaka jest, ponieważ nie jest to zmienna logiczna. Mam kilka kolumn, więc nie chcę tego robić po kolei. Chciałbym tylko wiedzieć, jak to zrobić.

Masz jakieś sugestie?

Odpowiedzi:


115

Możesz to zrobić:

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

lub lepiej (IMHO), użyj nazw zmiennych:

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

W obu przypadkach 1:2lub c("a", "b")można go zastąpić predefiniowanym wektorem.


To wystarcza. A co jeśli chcę wyszukać „1”? Próbowałem to zmienić, ale nie mogłem zmusić go do pracy.
jnam27

5
Prawdopodobnie tak:x[, 1:2][x[, 1:2] == 1] <- 0
flodel

@flodel dlaczego datatable xprzyjmuje macierz jako swojego pierwszego członka tylko podczas przypisywania? Czy ta funkcja jest gdzieś udokumentowana? Myślę też, że w drugim przykładzie zapomniałeś wstawić przecinek przed wektorami z nazwami kolumn.
ChiseledAbs

@ChiseledAbs, myślę, że odnosisz się do indeksowania macierzy (zobacz to na przykład stackoverflow.com/a/13999583/1201032 ), ale nie ogranicza się to do przypisań, można go również użyć do wyodrębnienia danych. Odnośnie brakującego przecinka: nie. Data.frames to listy kolumn, więc jeśli użyjesz jednego argumentu [, wyodrębni określone kolumny (patrz stackoverflow.com/a/21137524/1201032 ). Mam nadzieję, że to odpowiada na twoje pytanie, ale w przyszłości unikaj komentowania bardzo starych odpowiedzi, takich jak ta; zamiast tego zadaj nowe pytanie.
flodela

In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.Kiedy użyłem predefiniowanego wektora takiego jak ten x[Vpredefined][is.na(x[Vpredefined])] <- 0, daje mi to błąd
Rohit Saluja

30

Edytuj 2020-06-15

Od data.table1.12.4 (październik 2019 r.) data.tableZyskuje dwie funkcje, które to ułatwiają: nafilli setnafill.

nafill działa na kolumnach:

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

setnafill działa na tabelach (wymiany odbywają się według referencji / na miejscu)

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

Będzie to również bardziej wydajne niż inne opcje; zobacz ?nafillwięcej, wersje NAimputacji z ostatniej obserwacji przeniesionej do przodu (LOCF) i następnej obserwacji przeniesionej do tyłu (NOCB) dla szeregów czasowych.


To zadziała dla twojej data.tablewersji:

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

Alternatywnie, jak wskazuje David Arenburg poniżej, możesz użyć set(korzyść dodatkowa - możesz jej użyć na data.framelub data.table):

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

dzięki za to. Chciałem tylko wiedzieć, po trzech latach, czy są sposoby na zrobienie tego bez pętli for? Wyobrażam sobie, że zostałoby to bardziej zwięzłe przez zespół data.table? Dzięki.
info_seekeR

1
@info_seekeR Nie znam bardziej zwięzłego sposobu
eddi

jest to lepsze rozwiązanie niż wybrana przez flodel odpowiedź. Podejście Flodel używa operatora przypisania <- i dlatego obejmuje niepotrzebne kopiowanie danych.
Michael,

@MichaelChirico Czy w pierwszej części komentarza dodałeś krok, out <- xaby uniknąć niezrozumienia z x data.frame z pytania? W przeciwnym razie jest to jeszcze krótsze polecenie: y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]pomijanie nazwy zmiennej „out” i użycie „x”.
Yoann Pageaud

@MichaelChirico True! Zupełnie zapomniałem o nafill ()
Yoann Pageaud

22

Opierając się na odpowiedzi @Robert McDonald's tidyr::replace_na(), oto kilka dplyropcji kontrolowania, które kolumny NAsą zastępowane:

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
Dzięki tej funkcji pojawia się błąd: Error in replace_na(., 0) : argument "value" is missing, with no default. Jakieś sugestie co zmienić?
Tim M. Schendzielorz

17

Jest to teraz trywialne w tidyr dzięki replace_na (). Wygląda na to, że funkcja działa w przypadku data.tables oraz data.frames:

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

2

Nie jestem pewien, czy jest to bardziej zwięzłe, ale ta funkcja również znajdzie i umożliwi zamianę NA (lub dowolnej wartości) w wybranych kolumnach tabeli danych:

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
}

Aby go zastosować:

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

Funkcja tworzy macierz wybranych kolumn i wierszy (współrzędnych komórek), które spełniają kryteria wejściowe (w tym przypadku jest to.na == TRUE).


1

Możemy to rozwiązać za data.tablepomocą tidyr::repalce_nafunkcji ilapply

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

W ten sposób możemy również rozwiązać wklejanie kolumn NAciągiem. Najpierw my replace_na(x,""), a następnie możemy użyć stringr::str_cdo łączenia kolumn!


1
Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie byłoby znacznie poprawić swoją długoterminową wartość pokazując dlaczego jest to dobre rozwiązanie problemu i byłoby bardziej użyteczne dla czytelników przyszłości z innymi, podobnymi pytaniami. Proszę edytować swoją odpowiedź dodać kilka wyjaśnień, w tym założeń już wykonanych.
CertainPerformance

0

W przypadku określonej kolumny istnieje alternatywa z 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

jest całkiem przydatne z {data.table} i {stringr}

library(data.table)
library(stringr)

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

FYI


0

Zaczynając od data.table y, możesz po prostu napisać:
y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]
Nie zapomnij library(data.table)przed utworzeniem yi uruchomieniem tego polecenia.


-4

to działa dobrze dla mnie

DataTable DT = new DataTable();

DT = DT.AsEnumerable().Select(R =>
{
      R["Campo1"] = valor;
      return (R);
}).ToArray().CopyToDataTable();

1
czy to jest R? wygląda jak C #
Chris McKelt
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.