Cách thay thế các giá trị NA trong bảng cho các cột đã chọn


82

Có rất nhiều bài viết về việc thay thế các giá trị NA. Tôi biết rằng người ta có thể thay thế NAs trong bảng / khung sau bằng những thứ sau:

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

Nhưng, điều gì sẽ xảy ra nếu tôi muốn giới hạn nó ở một số cột nhất định? Hãy để tôi chỉ cho bạn một ví dụ.

Đầu tiên, hãy bắt đầu với một tập dữ liệu.

set.seed(1234)
x <- data.frame(a=sample(c(1,2,NA), 10, replace=T),
                b=sample(c(1,2,NA), 10, replace=T), 
                c=sample(c(1:5,NA), 10, replace=T))

Cái nào mang lại:

    a  b  c
1   1 NA  2
2   2  2  2
3   2  1  1
4   2 NA  1
5  NA  1  2
6   2 NA  5
7   1  1  4
8   1  1 NA
9   2  1  5
10  2  1  1

Ok, vì vậy tôi chỉ muốn giới hạn sự thay thế cho cột 'a' và 'b'. Cố gắng của tôi là:

x[is.na(x), 1:2]<-0

và:

x[is.na(x[1:2])]<-0

Cái nào không hoạt động.

Nỗ lực data.table của tôi, trong đó y<-data.table(x), rõ ràng là không bao giờ hoạt động:

y[is.na(y[,list(a,b)]), ]

Tôi muốn chuyển các cột bên trong đối số is.na nhưng điều đó rõ ràng sẽ không hoạt động.

Tôi muốn thực hiện việc này trong data.frame và data.table. Mục tiêu cuối cùng của tôi là mã hóa lại 1: 2 thành 0: 1 trong 'a' và 'b' trong khi giữ nguyên 'c' vì nó không phải là một biến logic. Tôi có một loạt các cột nên tôi không muốn làm từng cột một. Và, tôi chỉ muốn biết cách làm điều này.

Bạn có đề nghị nào không?

Câu trả lời:


115

Bạn có thể làm:

x[, 1:2][is.na(x[, 1:2])] <- 0

hoặc tốt hơn (IMHO), hãy sử dụng các tên biến:

x[c("a", "b")][is.na(x[c("a", "b")])] <- 0

Trong cả hai trường hợp, 1:2hoặc c("a", "b")có thể được thay thế bằng một vectơ được xác định trước.


Đó là công việc. Còn nếu tôi muốn tìm kiếm '1'? Tôi đã cố gắng thay đổi nó nhưng tôi không thể làm cho nó hoạt động.
jnam27

5
Có lẽ như thế này:x[, 1:2][x[, 1:2] == 1] <- 0
flodel

@flodel tại sao dữ liệu chỉ xchấp nhận một ma trận là thành viên đầu tiên của nó khi thực hiện phép gán? Tính năng này có được ghi ở đâu đó không? Ngoài ra, tôi nghĩ rằng bạn đã quên đặt dấu phẩy trước các vectơ có tên cột trong ví dụ thứ hai của bạn.
ChiseledAbs

@ChiseledAbs, tôi nghĩ bạn đang đề cập đến việc lập chỉ mục ma trận (xem điều này ví dụ: stackoverflow.com/a/13999583/1201032 ), nhưng nó không giới hạn ở các bài tập, nó cũng có thể được sử dụng để trích xuất dữ liệu. Về dấu phẩy còn thiếu: không. Data.frames là danh sách các cột nên nếu bạn sử dụng một đối số duy nhất [, nó sẽ trích xuất các cột được chỉ định (xem stackoverflow.com/a/21137524/1201032 ). Tôi hy vọng điều này trả lời câu hỏi của bạn nhưng trong tương lai, vui lòng tránh bình luận về những câu trả lời rất cũ như câu này; thay vào đó hãy đăng một câu hỏi mới.
flodel

In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.Khi tôi sử dụng một vector được xác định trước như thế này x[Vpredefined][is.na(x[Vpredefined])] <- 0nó mang lại cho tôi lỗi
Rohit Saluja

30

Chỉnh sửa 2020-06-15

Kể từ ngày data.table1.12.4 (tháng 10 năm 2019), data.tablecó hai chức năng để hỗ trợ điều này: nafillsetnafill.

nafill hoạt động trên các cột:

cols = c('a', 'b')
y[ , (cols) := lapply(.SD, nafill, fill=0), .SDcols = cols]

setnafill hoạt động trên các bảng (thay thế xảy ra theo tham chiếu / tại chỗ)

setnafill(y, cols=cols, fill=0)
# print y to show the effect
y[]

Điều này cũng sẽ hiệu quả hơn các tùy chọn khác; thấy ?nafillđể biết thêm, cuối cùng theo dõi bằng-thực-forward (LOCF) và (NOCB) phiên bản của lạc hậu tiếp theo quan sát-thực- NAsự đổ tội cho chuỗi thời gian.


Điều này sẽ hoạt động cho data.tablephiên bản của bạn :

for (col in c("a", "b")) y[is.na(get(col)), (col) := 0]

Ngoài ra, như David Arenburg chỉ ra bên dưới, bạn có thể sử dụng set(lợi ích phụ - bạn có thể sử dụng trên data.framehoặc data.table):

for (col in 1:2) set(x, which(is.na(x[[col]])), col, 0)

cám ơn vì cái này. Chỉ muốn biết, 3 năm sau, nếu có những cách nào để thực hiện điều trên mà không có vòng lặp for? Tôi tưởng tượng điều này sẽ được làm ngắn gọn hơn bởi nhóm data.table? Cảm ơn.
info_seekeR

1
@info_seekeR Tôi không biết cách nào ngắn gọn hơn
eddi

đây là một giải pháp tốt hơn so với câu trả lời đã chọn bởi flodel. Cách tiếp cận của Flodel sử dụng toán tử gán <- và do đó liên quan đến việc sao chép dữ liệu không cần thiết.
Michael

@MichaelChirico Trong phần đầu tiên của nhận xét, bạn đã thêm bước out <- xđể tránh hiểu nhầm với x data.frame từ câu hỏi chưa? Nếu không, đây là một lệnh thậm chí còn ngắn hơn: y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]bỏ qua tên biến 'out' và sử dụng 'x'.
Yoann Pageaud

@MichaelChirico Đúng! Tôi hoàn toàn quên mất nafill ()
Yoann Pageaud

21

Dựa trên tidyr::replace_na()câu trả lời của @Robert McDonald , đây là một số dplyrtùy chọn để kiểm soát cột NAnào được thay thế:

library(tidyverse)

# by column type:
x %>%
  mutate_if(is.numeric, ~replace_na(., 0))

# select columns defined in vars(col1, col2, ...):
x %>%
  mutate_at(vars(a, b, c), ~replace_na(., 0))

# all columns:
x %>%
  mutate_all(~replace_na(., 0))

1
Với chức năng này tôi nhận được báo lỗi: Error in replace_na(., 0) : argument "value" is missing, with no default. Bất kỳ đề xuất những gì để thay đổi?
Tim M. Schendzielorz

17

Điều này bây giờ là tầm thường trong ngăn nắp với Replace_na (). Hàm dường như hoạt động đối với data.tables cũng như data.frames:

tidyr::replace_na(x, list(a=0, b=0))

2

Không chắc liệu điều này có ngắn gọn hơn không, nhưng hàm này cũng sẽ tìm và cho phép thay thế các NA (hoặc bất kỳ giá trị nào bạn thích) trong các cột đã chọn của data.table:

update.mat <- function(dt, cols, criteria) {
  require(data.table)
  x <- as.data.frame(which(criteria==TRUE, arr.ind = TRUE))
  y <- as.matrix(subset(x, x$col %in% which((names(dt) %in% cols), arr.ind = TRUE)))
  y
}

Để áp dụng nó:

y[update.mat(y, c("a", "b"), is.na(y))] <- 0

Hàm tạo một ma trận gồm các cột và hàng đã chọn (tọa độ ô) đáp ứng tiêu chí đầu vào (trong trường hợp này là .na == TRUE).


1

Chúng tôi có thể giải quyết nó theo data.tablecách với tidyr::repalce_nachức năng vàlapply

library(data.table)
library(tidyr)
setDT(df)
df[,c("a","b","c"):=lapply(.SD,function(x) replace_na(x,0)),.SDcols=c("a","b","c")]

Bằng cách này, chúng ta cũng có thể giải quyết các cột dán với NAchuỗi. Đầu tiên, chúng tôi replace_na(x,""), sau đó chúng tôi có thể sử dụng stringr::str_cđể kết hợp các cột!


1
Cảm ơn bạn về đoạn mã này, đoạn mã này có thể cung cấp một số trợ giúp hạn chế, tức thì. Một lời giải thích thích hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ hữu ích hơn cho những người đọc trong tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số giải thích, bao gồm cả những giả định bạn đã đưa ra.
MostPerformance

0

Đối với một cột cụ thể, có một giải pháp thay thế bằng sapply

DF <- data.frame(A = letters[1:5],
             B = letters[6:10],
             C = c(2, 5, NA, 8, NA))

DF_NEW <- sapply(seq(1, nrow(DF)),
                    function(i) ifelse(is.na(DF[i,3]) ==
                                       TRUE,
                                       0,
                                       DF[i,3]))

DF[,3] <- DF_NEW
DF

0

nó khá tiện dụng với {data.table} và {stringr}

library(data.table)
library(stringr)

x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]

FYI


0

Bắt đầu từ data.table y, bạn có thể viết:
y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]
Đừng quên library(data.table)trước khi tạo yvà chạy lệnh này.


-4

Cái này làm việc tốt cho tôi

DataTable DT = new DataTable();

DT = DT.AsEnumerable().Select(R =>
{
      R["Campo1"] = valor;
      return (R);
}).ToArray().CopyToDataTable();

1
đây là R? trông giống như C #
Chris McKelt
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.