2015-11-19 22 views
11

có cách nào thanh lịch để xử lý NA là 0 (na.rm = TRUE) trong dplyr không?bỏ qua NA trong tổng hàng dplyr

data <- data.frame(a=c(1,2,3,4), b=c(4,NA,5,6), c=c(7,8,9,NA)) 

data %>% mutate(sum = a + b + c) 

a b c sum 
1 4 7 12 
2 NA 8 NA 
3 5 9 17 
4 6 NA NA 

but I like to get 

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

ngay cả khi tôi biết rằng đây không phải là kết quả mong muốn trong nhiều trường hợp khác

Trả lời

22

Bạn có thể sử dụng này:

library(dplyr) 
data %>% 
    #rowwise will make sure the sum operation will occur on each row 
    rowwise() %>% 
    #then a simple sum(..., na.rm=TRUE) is enough to result in what you need 
    mutate(sum = sum(a,b,c, na.rm=TRUE)) 

Output:

Source: local data frame [4 x 4] 
Groups: <by row> 

     a  b  c sum 
    (dbl) (dbl) (dbl) (dbl) 
1  1  4  7 12 
2  2 NA  8 10 
3  3  5  9 17 
4  4  6 NA 10 
+0

thật tuyệt vời! Cảm ơn bạn rất nhiều – ckluss

+0

Bạn đang rất chào đón @ckluss. Tôi đã cung cấp cách "dplyr -ic" nhất (nếu tôi có thể nói điều này, theo nghĩa là nó đang sử dụng dplyr theo cách truyền thống theo hướng dẫn) khi thực hiện nó. Tuy nhiên, việc sử dụng các hàm cơ sở khác (một mình hoặc kết hợp với dplyr) chắc chắn hiệu quả hơn tôi. Câu trả lời của StevenBeaupre và Akrun là hiệu quả hơn vì vậy bạn có lẽ sẽ tốt hơn với những người đó nếu tốc độ là quan trọng với bạn. – LyzandeR

+0

@LyzandeR Tôi đoán OP muốn 'cách dplyr'ish. Vì vậy, đừng lo lắng về hiệu quả. – akrun

0

Hãy thử điều này

data$sum <- apply(data, 1, sum, na.rm = T) 

Kết quả data

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

Một tùy chọn khác:

data %>% 
    mutate(sum = rowSums(., na.rm = TRUE)) 

Benchmark

library(microbenchmark) 
mbm <- microbenchmark(
steven = data %>% mutate(sum = rowSums(., na.rm = TRUE)), 
lyz = data %>% rowwise() %>% mutate(sum = sum(a, b, c, na.rm=TRUE)), 
nar = apply(data, 1, sum, na.rm = TRUE), 
akrun = data %>% mutate_each(funs(replace(., which(is.na(.)), 0))) %>% mutate(sum=a+b+c), 
frank = data %>% mutate(sum = Reduce(function(x,y) x + replace(y, is.na(y), 0), ., 
            init=rep(0, n()))), 
times = 10) 

enter image description here

#Unit: milliseconds 
# expr   min   lq  mean  median   uq  max neval cld 
# steven 9.493812 9.558736 18.31476 10.10280 22.55230 65.15325 10 a 
# lyz 6791.690570 6836.243782 6978.29684 6915.16098 7138.67733 7321.61117 10 c 
# nar 702.537055 723.256808 799.79996 805.71028 849.43815 909.36413 10 b 
# akrun 11.372550 11.388473 28.49560 11.44698 20.21214 155.23165 10 a 
# frank 20.206747 20.695986 32.69899 21.12998 25.11939 118.14779 10 a 
+1

Có lẽ bạn có thể thêm akrun's? Tôi thấy nó ở 1,33 so với 1,00 của bạn trong đơn vị = "tương đối" (sử dụng biến thể này: 'data%>% mutate (sum = Reduce (hàm (x, y) x + thay thế (y, is.na (y), 0),., init = rep (0, n()))) ') – Frank

+1

@Frank Chắc chắn, tôi sẽ cập nhật điểm chuẩn. –

5

Hoặc chúng ta có thể replaceNA với 0 và sau đó sử dụng mã của OP

data %>% 
    mutate_each(funs(replace(., which(is.na(.)), 0))) %>% 
    mutate(Sum= a+b+c) 
    #or as @Frank mentioned 
    #mutate(Sum = Reduce(`+`, .)) 

Dựa trên các tiêu chuẩn sử dụng dữ liệu @Steven Beaupré, nó có vẻ là hiệu quả là tốt.

Các vấn đề liên quan