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?
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?
Odpowiedzi:
Zamiana wszystkich zer na NA:
df[df == 0] <- NA
Wyjaśnienie
1. To nie jest to, NULL
czym 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, NA
ma 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. NULL
Wartości).
Teraz możesz zastąpić zera NULL
w ramce danych w sensie całkowitego usunięcia wszystkich wierszy zawierających co najmniej jedno zero. W przypadku korzystania np var
, cov
albo cor
, że jest właściwie równoznaczne z pierwszą wymianą zer NA
i ustawienie wartości use
jak "complete.obs"
. Zwykle jest to jednak niezadowalające, ponieważ prowadzi do dodatkowej utraty informacji.
2. Zamiast uruchamiać jakąś pętlę, w rozwiązaniu df == 0
stosuję wektoryzację. df == 0
zwraca (spróbuj) macierz o takim samym rozmiarze jak df
, z wpisami TRUE
i 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] <- NA
daje 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.
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
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 NA
przez 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
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
Można wymienić 0
ze NA
tylko 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:5
liczbę kolumn w ramce danych lub na 1:ncol(df)
.
1:5
ze 1:ncol(df)
na końcu. Nie chciałem, aby równanie było zbyt skomplikowane lub trudne do odczytania.
1:5
numerom 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 }
.