Zamień wszystkie wartości 0 na NA

144

Mam ramkę danych z kilkoma kolumnami numerycznymi. Niektóre wiersze mają wartość 0, które w analizie statystycznej należy uznać za zerowe. Jaki jest najszybszy sposób zamiany wszystkich wartości 0 na NULL w R?

Widziany
źródło
17
Nie sądzę, abyś chciał / mógł zastąpić wartościami NULL, ale NA służy temu celowi w języku R.
Chase,

Odpowiedzi:

243

Zamiana wszystkich zer na NA:

df[df == 0] <- NA



Wyjaśnienie

1. To nie jest to, NULLczym powinieneś chcieć zastępować zera. Jak mówi ?'NULL',

NULL reprezentuje pusty obiekt w języku R

który jest wyjątkowy i, jak sądzę, może być postrzegany jako obiekt najbardziej pozbawiony informacji i pusty. 1 W takim razie nie jest to zaskakujące

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

Oznacza to, że R nie rezerwuje żadnego miejsca dla tego pustego obiektu. 2 Tymczasem, patrząc na ?'NA'to, widzimy

NA jest stałą logiczną o długości 1, która zawiera wskaźnik brakującej wartości. NA można wymusić na dowolnym innym typie wektora oprócz surowego.

Co ważne, NAma długość 1, więc R rezerwuje na nią trochę miejsca. Na przykład,

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

Ponadto struktura ramki danych wymaga, aby wszystkie kolumny miały taką samą liczbę elementów, aby nie było „dziur” (tj. NULLWartości).

Teraz możesz zastąpić zera NULLw ramce danych w sensie całkowitego usunięcia wszystkich wierszy zawierających co najmniej jedno zero. W przypadku korzystania np var, covalbo cor, że jest właściwie równoznaczne z pierwszą wymianą zer NAi ustawienie wartości usejak "complete.obs". Zwykle jest to jednak niezadowalające, ponieważ prowadzi do dodatkowej utraty informacji.

2. Zamiast uruchamiać jakąś pętlę, w rozwiązaniu df == 0stosuję wektoryzację. df == 0zwraca (spróbuj) macierz o takim samym rozmiarze jak df, z wpisami TRUEi FALSE. Ponadto możemy również przekazać tę macierz do podzbioru [...](zobacz ?'['). Wreszcie, chociaż wynik df[df == 0]jest całkowicie intuicyjny, może wydawać się dziwne, że df[df == 0] <- NAdaje pożądany efekt. Operator przypisania <-rzeczywiście nie zawsze jest tak inteligentny i nie działa w ten sposób z niektórymi innymi obiektami, ale robi to z ramkami danych; zobacz ?'<-'.


1 Pusty zbiór w teorii mnogości wydaje się w jakiś sposób powiązany.
2 Kolejne podobieństwo do teorii mnogości: zbiór pusty jest podzbiorem każdego zbioru, ale nie rezerwujemy dla niego miejsca.

Julius Vainora
źródło
3
Jaka byłaby równoważna składnia dla obiektu data.table?
itpetersen,
6
Widzę, że otrzymaliście dużo głosów, ale nie sądzę, aby to odpowiednio obejmowało skrajne przypadki kolumn nienumerycznych z wartościami „0”, które nie miały być ustawione na <NA>.
IRTFM
33

Załóżmy, że plik data.frame jest mieszanką różnych typów danych i nie wszystkie kolumny wymagają modyfikacji.

aby zmodyfikować tylko kolumny od 12 do 18 (z łącznie 21), po prostu zrób to

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
źródło
To działa dla mnie, podczas gdy zaakceptowana odpowiedź nie
Patrick Coulombe
23

Alternatywny sposób bez [<-funkcji:

Przykładowa ramka danych dat(bezwstydnie skopiowana z odpowiedzi @ Chase):

dat

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

Zera może być zastąpiona NAprzez is.na<-funkcję:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Sven Hohenstein
źródło
22

dplyr::na_if() jest opcją:

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
sbha
źródło
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
Pościg
źródło
12

Ponieważ ktoś poprosił o wersję Data.Table tego, a podane rozwiązanie data.frame nie współpracuje z data.table, poniżej przedstawiam rozwiązanie.

Zasadniczo użyj :=operatora ->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
Reilstein
źródło
2
Lub for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Zobacz tutaj, aby uzyskać bardziej szczegółowe omówienie używania data.table do znajdowania i zastępowania wartości.
JWilliman
4

Można wymienić 0ze NAtylko w polach liczbowych (czyli z wyłączeniem rzeczy jak czynników), ale działa na podstawie kolumna po kolumnie:

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

Za pomocą funkcji możesz zastosować to do całej ramki danych:

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

Chociaż możesz zamienić na 1:5liczbę kolumn w ramce danych lub na 1:ncol(df).

Alium Britt
źródło
Nie jestem pewien, czy to poprawne rozwiązanie. A co z kolumnami 6 i więcej. Zostaną pocięte.
userJT
Dlatego zaproponował zastąpienie 1:5ze 1:ncol(df)na końcu. Nie chciałem, aby równanie było zbyt skomplikowane lub trudne do odczytania.
Alium Britt
ale co jeśli w kolumnach 6 i 7 - typ danych to char i nie należy go zastępować. W moim problemie potrzebuję wymiany tylko w kolumnach od 12 do 15, ale cały df ma 21 kolumn (wielu w ogóle nie wolno dotykać).
userJT
Na ramce danych można po prostu zmienić 1:5numerom kolumnę, którą chcesz zmienić, jak 12:15, ale jeśli chciał potwierdzić, że będzie to miało wpływ tylko kolumn numerycznych potem po prostu owinąć drugą linię funkcji w if, tak: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt,
0

W przypadku, gdy ktoś przybywa tutaj przez Google i szuka czegoś przeciwnego (tj. Jak zamienić wszystkie NA w data.frame na 0), odpowiedź brzmi

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

LUB

Używanie dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
stevec
źródło