2015-05-27 2 views
3

У меня есть кадр данных, как это:Условный группировки и обобщения кадр данных в [R]

df <- data.frame(ID = c("A", "A", "B", "B", "C", "C"), 
       time = c(3.1,3.2,6.5,12.3, 3.2, 3.4), 
       intensity = c(10, 20, 30, 40, 50, 60)) 
 
|ID | time| intensity| 
|:--|----:|---------:| 
|A | 3.1|  10| 
|A | 3.2|  20| 
|B | 6.5|  30| 
|B | 12.3|  40| 
|C | 3.2|  50| 
|C | 3.4|  60| 

Я хотел бы агрегировать значения (интенсивности сумм) с помощью ID только, когда разница во времени меньше, т. е. 0,3. Сначала я вычислил эту разницу во времени:

df.2 <- df %>% 
     group_by(ID) %>% 
     mutate(time.diff = max(time) - min(time)) 

... в результате:

 
|ID | time| intensity| time.diff| 
|:--|----:|---------:|---------:| 
|A | 3.1|  10|  0.1| 
|A | 3.2|  20|  0.1| 
|B | 6.5|  30|  5.8| 
|B | 12.3|  40|  5.8| 
|C | 3.2|  50|  0.2| 
|C | 3.4|  60|  0.2| 

Просто чтобы быть ясно, что я хотел бы получить как результат будет:

 
|ID | time| intensity| time.diff| 
|:--|----:|---------:|---------:| 
|A | 3.15|  30|  0.1| 
|B | 6.5|  30|  5.8| 
|B | 12.3|  40|  5.8| 
|C | 3.3|  110|  0.2| 

, где время теперь представляет собой среднее значение интегрированных наблюдений, а интенсивность - их сумма. Идентификатор «B» сохраняет два наблюдения, так как разница во времени больше 0,3. Я попытался с dplyr, но подводит итог всегда будет отбрасывать одно из наблюдений «B», и я хочу их сохранить, и я не знаю, как сделать условным _group_by_.

Благодарю вас за любую идею!

ответ

3

Возможный вариант с data.table

library(data.table) 
unique(setDT(df)[, time.diff := max(time)-min(time), ID][ 
    time.diff <= 0.3, c('time', 'intensity') := list(mean(time), 
     sum(intensity)), ID]) 
# ID time intensity time.diff 
#1: A 3.15  30  0.1 
#2: B 6.50  30  5.8 
#3: B 12.30  40  5.8 
#4: C 3.30  110  0.2 

Или с помощью dplyr

library(dplyr) 
df %>% 
    group_by(ID) %>% 
    mutate(time.diff=max(time)-min(time), indx=all(time.diff<=0.3), 
     intensity=ifelse(indx, sum(intensity), intensity), 
     time=ifelse(indx, mean(time), time)) %>% 
    filter(!indx|row_number()==1) %>% 
    select(-indx) 
# ID time intensity time.diff 
#1 A 3.15  30  0.1 
#2 B 6.50  30  5.8 
#3 B 12.30  40  5.8 
#4 C 3.30  110  0.2 
+1

@VeerendraGadekar Спасибо, я должен пропустить его. – akrun

+0

@VeerendraGadekar Исправлен вывод. Еще раз спасибо за комментарии. – akrun

+1

@Arun Спасибо, это намного лучше. – akrun

3

Другой вариант data.table решения:

setDT(df)[, time.diff := max(time) - min(time), by = ID 
     ][, if (time.diff <= 0.3) 
       .(time = mean(time), intensity = sum(intensity)) 
      else .SD, by = .(ID, time.diff)] 
# ID time.diff time intensity 
# 1: A  0.1 3.15  30 
# 2: B  5.8 6.50  30 
# 3: B  5.8 12.30  40 
# 4: C  0.2 3.30  110 
+0

'не удалось найти функцию". "' Нужно ли обновлять мои данные.table? –

+1

Oops .. замените его на 'list()' вместо '.()' На данный момент .. Он реализован в 'v1.9.5 +' .. Или установите версию разработки data.table из [здесь] (https: //github.com/Rdatatable/data.table/wiki/Installation). – Arun

+0

ОК спасибо! Я попробую версию разработки –

1
# get time.diff 
df$time.diff <- ave(x = df$time,df$ID,FUN = function(x){max(x)-min(x)}) 

# new split variable to use with ID 
df$cut <- cumsum(df$time.diff > .3) 

# aggregate everything you need and ignore the cut variable 
require(plyr) 
ddply(df,c('cut','ID'),summarize, 
     time = mean(time), 
     intensity = sum(intensity), 
     time.diff = mean(time.diff))[2:5] 
1

USI нг sqldf:

library(sqldf) 
sqldf('SELECT ID, AVG(time) time, SUM(intensity) intensity, (MAX(time)-MIN(time)) dif FROM df 
     GROUP BY ID 
     HAVING (MAX(time)-MIN(time))<0.3 
     UNION 
     SELECT ID, df.time, df.intensity, df2.dif 
     FROM (SELECT ID, AVG(time) time, SUM(intensity) intensity, (MAX(time)-MIN(time)) dif 
     FROM df 
     GROUP BY ID 
     HAVING (MAX(time)-MIN(time))>0.3) as df2 
     LEFT JOIN df USING (ID)') 

Выход:

ID time intensity dif 
1 A 3.15  30 0.1 
2 B 6.50  30 5.8 
3 B 12.30  40 5.8 
4 C 3.30  110 0.2