Ganti semua 0 nilai ke NA

144

Saya memiliki kerangka data dengan beberapa kolom numerik. Beberapa baris memiliki nilai 0 yang harus dianggap nol dalam analisis statistik. Apa cara tercepat untuk mengganti semua nilai 0 ke NULL dalam R?

Terlihat
sumber
17
Saya tidak berpikir Anda ingin / bisa mengganti dengan nilai NULL, tetapi NA melayani tujuan itu dalam bahasa R.
Mengejar

Jawaban:

243

Mengganti semua nol ke NA:

df[df == 0] <- NA



Penjelasan

1. Bukan NULLapa yang Anda ingin ganti dengan nol. Seperti yang tertulis di ?'NULL',

NULL mewakili objek nol di R

yang unik dan, saya kira, dapat dilihat sebagai objek yang paling tidak informatif dan kosong. 1 Maka tidak begitu mengejutkan

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

Artinya, R tidak menyediakan ruang untuk objek nol ini. 2 Sementara itu, melihat ?'NA'kita melihat itu

NA adalah konstanta logis dengan panjang 1 yang berisi indikator nilai yang hilang. NA dapat dipaksakan untuk jenis vektor lainnya kecuali mentah.

Yang penting, NAadalah panjang 1 sehingga R menyediakan ruang untuk itu. Misalnya,

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

Selain itu, struktur bingkai data mengharuskan semua kolom memiliki jumlah elemen yang sama sehingga tidak ada "lubang" (yaitu, NULLnilai).

Sekarang Anda bisa mengganti nol dengan NULLdalam bingkai data dalam arti sepenuhnya menghapus semua baris yang mengandung setidaknya satu nol. Bila menggunakan, misalnya, var, cov, atau cor, yang benar-benar setara dengan pertama menggantikan nol dengan NAdan menetapkan nilai usesebagai "complete.obs". Namun, biasanya, ini tidak memuaskan karena menyebabkan hilangnya informasi tambahan.

2. Alih-alih menjalankan semacam loop, dalam solusi saya menggunakan df == 0vektorisasi. df == 0mengembalikan (coba) matriks dengan ukuran yang sama dengan df, dengan entri TRUEdan FALSE. Lebih lanjut, kami juga diizinkan untuk meneruskan matriks ini ke subset [...](lihat ?'['). Terakhir, sementara hasil dari df[df == 0]intuisi sempurna, mungkin tampak aneh yang df[df == 0] <- NAmemberikan efek yang diinginkan. Operator penugasan <-memang tidak selalu begitu pintar dan tidak bekerja dengan cara ini dengan beberapa objek lain, tetapi ia melakukannya dengan bingkai data; lihat ?'<-'.


1 Himpunan kosong dalam teori himpunan terasa entah bagaimana terkait.
2 Kesamaan lain dengan teori himpunan: himpunan kosong adalah himpunan bagian dari setiap himpunan, tetapi kami tidak menyediakan ruang untuk itu.

Julius Vainora
sumber
3
Apa yang akan menjadi sintaks yang setara untuk objek data.table?
itpetersen
6
Saya melihat Anda mendapatkan banyak suara tetapi tidak berpikir ini dengan tepat mencakup kasus tepi kolom non-numerik dengan nilai "0" yang tidak diminta untuk disetel ke <NA>.
IRTFM
33

Biarkan saya berasumsi bahwa data.frame Anda adalah campuran dari tipe data yang berbeda dan tidak semua kolom perlu dimodifikasi.

untuk memodifikasi hanya kolom 12 hingga 18 (dari total 21), lakukan saja ini

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
sumber
Ini berfungsi untuk saya, sementara jawaban yang diterima tidak
Patrick Coulombe
23

Cara alternatif tanpa [<-fungsi:

Kerangka data sampel dat(disalin tanpa malu-malu dari jawaban @ Chase):

dat

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

Nol bisa diganti dengan NAdengan is.na<-fungsi:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Sven Hohenstein
sumber
22

dplyr::na_if() adalah sebuah opsi:

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
sumber
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
Mengejar
sumber
12

Karena seseorang meminta versi Data.Table ini, dan karena solusi data.frame yang diberikan tidak bekerja dengan data.table, saya memberikan solusi di bawah ini.

Pada dasarnya, gunakan :=operator ->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
sumber
2
Atau for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Lihat di sini untuk diskusi lebih rinci tentang penggunaan data.
JWilliman
4

Anda dapat mengganti 0dengan NAhanya dalam bidang numerik (yaitu mengecualikan hal-hal seperti faktor), tetapi berfungsi berdasarkan kolom-demi-kolom:

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

Dengan suatu fungsi, Anda dapat menerapkan ini ke seluruh kerangka data Anda:

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

Meskipun Anda bisa mengganti 1:5dengan jumlah kolom di bingkai data Anda, atau dengan 1:ncol(df).

Alium Britt
sumber
Saya tidak yakin ini solusi yang tepat. Bagaimana dengan kolom 6 dan lebih banyak. Mereka akan dipotong.
userJT
Itu sebabnya saya menyarankan untuk mengganti 1:5dengan 1:ncol(df)di akhir. Saya tidak ingin membuat persamaan terlalu rumit atau sulit dibaca.
Alium Britt
tetapi bagaimana jika di kolom 6 dan 7 - tipe data adalah char dan tidak ada penggantian yang harus dilakukan. Dalam masalah saya, saya perlu penggantian hanya di kolom 12 hingga 15 tetapi seluruh df memiliki 21 kolom (banyak yang tidak boleh disentuh sama sekali).
userJT
Untuk frame data Anda Anda hanya bisa mengubah 1:5ke nomor kolom yang ingin diubah, seperti 12:15, tetapi jika Anda ingin mengkonfirmasi bahwa hal itu hanya akan mempengaruhi kolom numerik kemudian hanya membungkus baris kedua fungsi dalam sebuah pernyataan jika, seperti ini: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt
0

Jika ada yang datang ke sini melalui google untuk mencari yang sebaliknya (yaitu cara mengganti semua NAS dalam data.frame dengan 0), jawabannya adalah

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

ATAU

Menggunakan dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
stevec
sumber