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, 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.
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 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
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ć 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).
1:5ze 1:ncol(df)na końcu. Nie chciałem, aby równanie było zbyt skomplikowane lub trudne do odczytania.
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 }.