2016-05-03 3 views
1

Я хотел бы объединить данные data.frame.R: агрегация (медиана) строк данных. Кадров из> 2 столбцов

Ниже приведен пример данных:

data <- structure(list(Charge = c(210133L, 210133L, 210133L, 210152L, 
            210152L, 210152L, 210152L, 210180L, 210180L, 210180L), Seq = c(1L, 
                             2L, 3L, 1L, 2L, 3L, 4L, 1L, 2L, 2L), x = c(NA, 1.5, 2, 
                                         1.5, 1, 0.67, 1.17, 1, 1, 1), y = c(0.5, 0.5, 1, NA, 0.5, 
                                                    0.5, 0.5, 0.5, 0.5, 0.5)), .Names = c("Charge", "Seq", 
                                                              "x", "y"), row.names = c(NA, 10L), class = "data.frame") 

* для объяснения (те же данные, что и выше, другой формат):

Charge Seq x y 
1 210133 1 NA 0.5 
2 210133 2 1.50 0.5 
3 210133 3 2.00 1.0 
4 210152 1 1.50 NA 
5 210152 2 1.00 0.5 
6 210152 3 0.67 0.5 
7 210152 4 1.17 0.5 
8 210180 1 1.00 0.5 
9 210180 2 1.00 0.5 
10 210180 2 1.00 0.5 

Медиана х и у столбцов строк должна быть выполнена для Seq > 1 за каждую уникальную плату.

Так, например, для этой выборки данных, я хотел бы получить дополнительная строка с й и у строк медианы для SEQ> 1:

 Charge Seq x y 
    1 210133 1 NA 0.5 
    2 210133 2 1.50 0.5 
    3 210133 3 2.00 1.0 
    4 210133 >1 1.75 0.75 #here is additional row with median of x and y 
    4 210152 1 1.50 NA 
    5 210152 2 1.00 0.5... 

Спасибо за помощь!

ответ

2

Мы можем использовать data.table. Преобразуйте «data.frame» в «data.frame» в «data.table» (setDT(data)), сгруппированный по «Charge», переверните столбец (lapply(.SD,...), получите median столбцов, указанных в .SDcols, на основании условия в 'i' (Seq >1), создайте столбец «Seq» со значением «> 1». Поместите исходные данные вместе с новым в list, используйте rbind для объединения наборов данных и, если необходимо, order.

library(data.table) 
setDT(data) 
res <- data[Seq > 1L, lapply(.SD, median, na.rm=TRUE), 
      by = Charge, .SDcols = x:y][, Seq := ">1"][] 
ans <- setorder(rbind(data, res), Charge, Seq) 
# Charge Seq x y 
# 1: 210133 1 NA 0.50 
# 2: 210133 2 1.50 0.50 
# 3: 210133 3 2.00 1.00 
# 4: 210133 >1 1.75 0.75 
# 5: 210152 1 1.50 NA 
# 6: 210152 2 1.00 0.50 
# 7: 210152 3 0.67 0.50 
# 8: 210152 4 1.17 0.50 
# 9: 210152 >1 1.00 0.50 
#10: 210180 1 1.00 0.50 
#11: 210180 2 1.00 0.50 
#12: 210180 2 1.00 0.50 
#13: 210180 >1 1.00 0.50 

Аналогичный вариант с использованием dplyr, где мы конвертировать class из «послед», чтобы character в исходном наборе данных. Затем filter для «Seq», не равный 1, сгруппированный по «Charge», мы получаем median столбцов с summarise_each, создаем новый столбец на выходе «Seq», затем привязываем исходные данные к новому с помощью bind_rows , и order при необходимости.

library(magrittr) 
library(dplyr) 
data %<>% 
    mutate(Seq = as.character(Seq)) 

data %>% 
    filter(Seq!="1") %>% 
    group_by(Charge) %>% 
    summarise_each(funs(median=median(., na.rm=TRUE)), x:y) %>% 
    mutate(Seq = ">1") %>% 
    bind_rows(data, .) %>% 
    mutate(Seq = factor(Seq, levels = c(unique(data$Seq), ">1"))) %>% 
    arrange(Charge, Seq) 
+1

Спасибо, это работает как шарм! –

2

Другой способ сделать то же самое с помощью data.table:

library(data.table) 

setDT(data) 

test <- function(x){ 
    seq.gt.1 <- which(x$Seq > 1) 

    median.1 <- median(x$x[seq.gt.1],na.rm=T) 
    median.2 <- median(x$y[seq.gt.1],na.rm=T) 

    return (rbind(x,data.table(Seq='>1',x=median.1,y=median.2))) 
} 

data[,test(.SD),by=Charge] 

## Charge Seq x y 
##1: 210133 1 NA 0.50 
##2: 210133 2 1.50 0.50 
##3: 210133 3 2.00 1.00 
##4: 210133 >1 1.75 0.75 
##5: 210152 1 1.50 NA 
##6: 210152 2 1.00 0.50 
##7: 210152 3 0.67 0.50 
##8: 210152 4 1.17 0.50 
##9: 210152 >1 1.00 0.50 
##10: 210180 1 1.00 0.50 
##11: 210180 2 1.00 0.50 
##12: 210180 2 1.00 0.50 
##13: 210180 >1 1.00 0.50 
+1

Спасибо за ответ! Ваш код работает отлично –

Смежные вопросы