Thay thế tất cả 0 giá trị thành NA


144

Tôi có một khung dữ liệu với một số cột số. Một số hàng có giá trị 0 nên được coi là null trong phân tích thống kê. Cách nhanh nhất để thay thế tất cả giá trị 0 thành NULL trong R là gì?


17
Tôi không nghĩ rằng bạn muốn / có thể thay thế bằng các giá trị NULL, nhưng NA phục vụ mục đích đó trong biệt ngữ R.
Đuổi theo

Câu trả lời:


243

Thay thế tất cả các số 0 thành NA:

df[df == 0] <- NA



Giải trình

1. Nó không phải là NULLnhững gì bạn nên thay thế số không bằng. Như đã nói ?'NULL',

NULL đại diện cho đối tượng null trong R

đó là duy nhất và, tôi đoán, có thể được coi là đối tượng không chính xác và trống rỗng nhất. 1 Sau đó, nó trở nên không quá ngạc nhiên

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

Đó là, R không dành bất kỳ khoảng trống nào cho đối tượng null này. 2 Trong khi đó, nhìn vào ?'NA'chúng ta thấy rằng

NA là hằng số logic có độ dài 1 chứa chỉ số giá trị bị thiếu. NA có thể được ép buộc với bất kỳ loại vectơ nào khác ngoại trừ nguyên.

Điều quan trọng, NAcó độ dài 1 để R dành một khoảng trống cho nó. Ví dụ,

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

Ngoài ra, cấu trúc khung dữ liệu yêu cầu tất cả các cột phải có cùng số lượng phần tử để không có "lỗ" (nghĩa là NULL các giá trị).

Bây giờ bạn có thể thay thế số không bằng NULLmột khung dữ liệu theo nghĩa loại bỏ hoàn toàn tất cả các hàng chứa ít nhất một số không. Khi sử dụng, ví dụ như, var, cov, hoặc cor, đó là thực sự tương đương với đầu thay thế zero với NAvà thiết lập giá trị của use"complete.obs". Thông thường, tuy nhiên, điều này là không thỏa đáng vì nó dẫn đến mất thêm thông tin.

2. Thay vì chạy một số loại vòng lặp, trong giải pháp tôi sử dụng df == 0vector hóa. df == 0trả về (thử nó) một ma trận có cùng kích thước dfvới các mục TRUEFALSE. Hơn nữa, chúng tôi cũng được phép truyền ma trận này cho tập hợp con [...](xem ?'['). Cuối cùng, trong khi kết quả df[df == 0]là hoàn toàn trực quan, nó có vẻ lạ df[df == 0] <- NAmang lại hiệu quả mong muốn. Toán tử gán <-thực sự không phải lúc nào cũng thông minh và không hoạt động theo cách này với một số đối tượng khác, nhưng nó làm như vậy với các khung dữ liệu; thấy ?'<-'.


1 Tập hợp trống trong lý thuyết tập hợp cảm thấy bằng cách nào đó liên quan.
2 Một điểm tương đồng khác với lý thuyết tập hợp: tập hợp trống là tập hợp con của mọi tập hợp, nhưng chúng tôi không dành bất kỳ khoảng trống nào cho nó.


3
Cú pháp tương đương sẽ là gì cho một đối tượng data.table?
itpeteren

6
Tôi thấy bạn đã nhận được rất nhiều phiếu bầu nhưng không nghĩ rằng điều này bao gồm một cách thích hợp các trường hợp cạnh của các cột không phải là số có giá trị "0" không được yêu cầu đặt thành <NA>.
IRTFM

33

Hãy để tôi giả sử rằng data.frame của bạn là sự pha trộn của các kiểu dữ liệu khác nhau và không phải tất cả các cột cần phải được sửa đổi.

để sửa đổi chỉ các cột 12 thành 18 (trong tổng số 21), chỉ cần làm điều này

df[, 12:18][df[, 12:18] == 0] <- NA

Điều này làm việc cho tôi, trong khi câu trả lời được chấp nhận thì không
Patrick Coulombe

23

Một cách khác mà không cần [<- chức năng:

Khung dữ liệu mẫu dat(được sao chép một cách đáng xấu hổ từ câu trả lời của @ Chase):

dat

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

Số không có thể được thay thế NAbằng is.na<-chức năng:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

22

dplyr::na_if() là một lựa chọn:

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

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

12

Vì ai đó đã yêu cầu phiên bản Data.Table của điều này và vì giải pháp data.frame đã cho không hoạt động với data.table, tôi sẽ cung cấp giải pháp bên dưới.

Về cơ bản, sử dụng :=toán tử ->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

2
Hoặc for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Xem ở đây để thảo luận chi tiết hơn về việc sử dụng data.table để tìm và thay thế các giá trị.
JWilliman

4

Bạn chỉ có thể thay thế 0bằng NAcác trường số (nghĩa là loại trừ những thứ như các yếu tố), nhưng nó hoạt động trên cơ sở từng cột:

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

Với một chức năng, bạn có thể áp dụng điều này cho toàn bộ khung dữ liệu của mình:

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

Mặc dù bạn có thể thay thế 1:5bằng số lượng cột trong khung dữ liệu của mình hoặc bằng 1:ncol(df).


Tôi không chắc đây là giải pháp chính xác. Những gì về cột 6 trở lên. Họ sẽ bị cắt.
userJT

Đó là lý do tại sao tôi đề nghị thay thế 1:5với 1:ncol(df)lúc kết thúc. Tôi không muốn làm cho phương trình quá phức tạp hoặc khó đọc.
Alium Britt

nhưng nếu trong cột 6 và 7 - kiểu dữ liệu là char và không nên thay thế. Trong vấn đề của tôi, tôi chỉ cần thay thế trong các cột 12 đến 15 nhưng toàn bộ df có 21 cột (nhiều cột không được chạm vào).
userJT

Đối với khung dữ liệu của bạn, bạn chỉ có thể thay đổi 1:5số cột bạn muốn thay đổi, 12:15nhưng nếu bạn muốn xác nhận rằng nó sẽ chỉ ảnh hưởng đến các cột số thì chỉ cần bọc dòng thứ hai của hàm trong câu lệnh if, như sau : if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt

0

Trong trường hợp bất kỳ ai đến đây thông qua google để tìm kiếm điều ngược lại (tức là làm thế nào để thay thế tất cả các NA trong một data.frame bằng 0), câu trả lời là

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

HOẶC LÀ

Sử dụng dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.