2016-01-18 22 views
8

Tôi có một data.frame với nhiều cột (~ 50). Một số trong số đó là ký tự, một số là số và 3 trong số chúng tôi sử dụng để nhóm.R: tóm tắt nhiều cột (số, ký tự) và loại bỏ NA

tôi cần phải:

  • loại bỏ NA từ cột số
  • tính toán giá trị trung bình của mỗi cột số
  • trích xuất các phần tử đầu tiên của các cột nhân vật

Giả sử, chúng tôi đang sử dụng dữ liệu iris đã sửa đổi như sau:

data(iris) 
iris$year <- rep(c(2000,3000),each=25) ## for grouping 
iris$color <- rep(c("red","green","blue"),each=50) ## character column 
iris[1,] <- NA ## introducing NAs 

Tôi có tổng cộng ~ 50 cột, số và ký tự được trộn lẫn với nhau. Tôi đã thử một cái gì đó như:

giris <- group_by(iris, Species, year) 
cls <- unlist(sapply(giris, class)) ## find out classes 
action <- ifelse(cls == "numeric", "mean", "first") 
action <- paste(action) 
summarise_each(giris, action) 

Điều tôi nhận được có nghĩa là cho tất cả các cột trong một nhóm theo sau với các cột có giá trị đầu tiên trong nhóm tương ứng. Và NA không được xử lý ... Mà không phải là chính xác những gì tôi tìm kiếm ...

Giúp đỡ bất cứ ai?

Trả lời

9

Bạn có thể thử điều này với một if/else trong funs của summarise_each:

iris %>% 
    group_by(Species, year) %>% 
    summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.))) 

Kể từ khi bạn có một số của NA cũng trong cột nhóm, bạn có thể thêm một tuyên bố filter:

iris %>% 
    filter(!is.na(Species) & !is.na(year)) %>% 
    group_by(Species, year) %>% 
    summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.))) 
#Source: local data frame [6 x 7] 
#Groups: Species [?] 
# 
#  Species year Sepal.Length Sepal.Width Petal.Length Petal.Width color 
#  (fctr) (dbl)  (dbl)  (dbl)  (dbl)  (dbl) (chr) 
#1  setosa 2000  5.025 3.479167  1.4625  0.250 red 
#2  setosa 3000  4.984 3.376000  1.4640  0.244 red 
#3 versicolor 2000  6.012 2.776000  4.3120  1.344 green 
#4 versicolor 3000  5.860 2.764000  4.2080  1.308 green 
#5 virginica 2000  6.576 2.928000  5.6400  2.044 blue 
#6 virginica 3000  6.600 3.020000  5.4640  2.008 blue 

Để tránh NA tiềm ẩn trong cột màu (hoặc bất kỳ cột nào không phải số), bạn có thể sửa đổi nó thành first(na.omit(.)).


Bạn cũng có thể thử data.table:

library(data.table) 
setDT(iris) 
iris[!is.na(Species) & !is.na(year), lapply(.SD, function(x) { 
    if(is.numeric(x)) mean(x, na.rm = TRUE) else x[!is.na(x)][1L]}), 
    by = list(Species, year)] 
#  Species year Sepal.Length Sepal.Width Petal.Length Petal.Width color 
#1:  setosa 2000  5.025 3.479167  1.4625  0.250 red 
#2:  setosa 3000  4.984 3.376000  1.4640  0.244 red 
#3: versicolor 2000  6.012 2.776000  4.3120  1.344 green 
#4: versicolor 3000  5.860 2.764000  4.2080  1.308 green 
#5: virginica 2000  6.576 2.928000  5.6400  2.044 blue 
#6: virginica 3000  6.600 3.020000  5.4640  2.008 blue 
+0

Tôi nghĩ bạn có thể muốn thêm 'na.omit()' ở trên 'group_by', nhưng đây là ý chính của câu hỏi. – JasonAizkalns

+0

@ JasonAizkalns, tôi không nghĩ vậy - điều này có khả năng sẽ xóa nhiều hàng cần lưu giữ. Nhưng tôi đồng ý rằng một 'bộ lọc (! Is.na (Loài) &! Is.na (năm))' sẽ có ý nghĩa –

+0

Đây là một giải pháp làm việc thực sự tốt đẹp và (quan trọng nhất) cũng cho phép để có được một cái nhìn thoáng qua về những gì đang đi theo mui xe của summaryise_each. Tôi thực sự, REALLY biết ơn vì điều đó, Doncendo :-). Đồng thời, bạn có nghĩ rằng có thể có một cách để tăng tốc nó? – rpl

0

tôi cung cấp cho nó một thử:

1. Đối với điểm đầu tiên bạn đề cập đến, tôi sẽ làm một cái gì đó như sau (mà isn 't cần thiết cho điểm thứ hai):

na.omit(iris[ , which(sapply(iris, class) == "numeric")]) 

Để tách cột bei hoặc numeric hoặc character, tôi sử dụng như sau:

iris[ , which(sapply(iris, class) == "numeric")] 
iris[ , which(sapply(iris, class) == "character")] 

2. Nhiệm vụ thứ hai tôi kết hợp các dòng trên với colMeans:

colMeans(iris[ , which(sapply(iris, class) == "numeric")], na.rm = TRUE) 

3. Để trích xuất các phần tử đầu tiên của các cột nhân vật, bạn chỉ có thể làm:

iris[1, which(sapply(iris, class) == "character")] 

Trong trường hợp đề cập đến cho các dữ liệu iris, dòng đầu tiên là hoàn toàn NA, thậm chí các cột nhân vật, vì vậy tôi sẽ lặp để tìm là người đầu tiên-phi-NA-hàng

k <- 1 
while(any(is.na(FirstCharacterElement <- iris[k, which(sapply(iris, class) == "character")]))){ 
    k <- k + 1 
} 

Hãy cẩn thận về các yếu tố lớp (mà phá vỡ các mã trong trường hợp của các dữ liệu iris nơi cột loài là các yếu tố đẳng cấp và bạn có thể mong đợi nó để trở thành một nhân vật Bạn có thể kiểm tra điều này với sapply(iris, class) và thay đổi nó với ví dụ:

iris$Species <- as.character(iris$Species) #or with similar column names 

Khi bạn đọc dữ liệu, bạn có thể đề cập đến tham số stringsAsFactors = FALSE của hàm read.table, read.csv hoặc tương tự.

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