2016-04-28 4 views
5

у меня есть данные, что выглядит следующим образом:Dplyr или data.table консолидации последовательных строк в сгруппированных данных на основе значения в другом столбце

ID CLASS START END 
100 GA 3-Jan-15 1-Feb-15 
100 G 1-Feb-15 22-Feb-15 
100 GA 28-Feb-15 17-Mar-15 
100 G 1-Apr-15 8-Apr-15 
100 G 10-Apr-15 18-Apr-15 
200 FA 3-Jan-14 1-Feb-14 
200 FA 1-Feb-14 22-Feb-14 
200 G 28-Feb-14 15-Mar-14 
200 F 1-Apr-14 20-Apr-14 

Вот данные:

df <- structure(list(ID = c(100L, 100L, 100L, 100L, 100L, 200L, 200L, 
200L, 200L), CLASS = structure(c(4L, 3L, 4L, 3L, 3L, 2L, 2L, 
3L, 1L), .Label = c("F", "FA", "G", "GA"), class = "factor"), 
START = structure(c(9L, 4L, 7L, 2L, 5L, 8L, 3L, 6L, 1L), .Label = c("1-Apr-14", 
"1-Apr-15", "1-Feb-14", "1-Feb-15", "10-Apr-15", "28-Feb-14", 
"28-Feb-15", "3-Jan-14", "3-Jan-15"), class = "factor"), 
END = structure(c(2L, 8L, 4L, 9L, 5L, 1L, 7L, 3L, 6L), .Label = c("1-Feb-14", 
"1-Feb-15", "15-Mar-14", "17-Mar-15", "18-Apr-15", "20-Apr-14", 
"22-Feb-14", "22-Feb-15", "8-Apr-15"), class = "factor")), .Names = c("ID", 
"CLASS", "START", "END"), class = "data.frame", row.names = c(NA, 
-9L)) 

Я хотел бы для группировки данных по столбцу ID, а затем консолидировать любые последовательные вхождения одного и того же значения в столбце CLASS (отсортированные по дате START) при выборе минимальной даты начала и максимальной даты окончания. Поэтому для идентификатора номер 100 существует только один экземпляр, где класс «G» является последовательным, поэтому я хотел бы объединить эти две строки в одну строку с датами min (START) и max (END). Это простой пример, но в реальных данных иногда есть несколько последовательных строк, которые необходимо консолидировать.

Я пробовал group_by, а затем использовал какой-то рейтинг, но это, похоже, не делает трюк. Любые предложения о том, как это решить? Также это первый раз, когда я публикую SO, поэтому я надеюсь, что этот вопрос имеет смысл.

Результат должен выглядеть следующим образом:

ID CLASS START END 
100 GA 3-Jan-15 1-Feb-15 
100 G 1-Feb-15 22-Feb-15 
100 GA 28-Feb-15 17-Mar-15 
100 G 1-Apr-15 18-Apr-15 
200 FA 3-Jan-14 22-Feb-14 
200 G 28-Feb-14 15-Mar-14 
200 F 1-Apr-14 20-Apr-14 
+1

Не следует ли объединять два 'FA' в ID 200 в виде w ELL? –

+0

@CactusWoman это правильно! Я отредактирую таблицу. – Kartik

ответ

5

Вот вариант, используя data.table::rleid сделать идентификатор для прогонов же ID и CLASS:

# make START and END Date class for easier manipulation 
df <- df %>% mutate(START = as.Date(START, '%d-%b-%y'), 
        END = as.Date(END, '%d-%b-%y')) 
# More concise alternative: 
# df <- df %>% mutate_each(funs(as.Date(., '%d-%b-%y')), START, END) 

# group and make rleid as mentioned above 
df %>% group_by(ID, CLASS, rleid = data.table::rleid(ID, CLASS)) %>% 
    # collapse with summarise, replacing START and END with their min and max for each group 
    summarise(START = min(START), END = max(END)) %>% 
    # clean up arrangement and get rid of added rleid column 
    ungroup() %>% arrange(rleid) %>% select(-rleid) 

# Source: local data frame [7 x 4] 
# 
#  ID CLASS  START  END 
# (int) (fctr)  (date)  (date) 
# 1 100  GA 2015-01-03 2015-02-01 
# 2 100  G 2015-02-01 2015-02-22 
# 3 100  GA 2015-02-28 2015-03-17 
# 4 100  G 2015-04-01 2015-04-18 
# 5 200  FA 2014-01-03 2014-02-22 
# 6 200  G 2014-02-28 2014-03-15 
# 7 200  F 2014-04-01 2014-04-20 

Вот чистый data.table аналог :

library(data.table) 
setDT(df) 
datecols = c("START","END") 
df[, (datecols) := lapply(.SD, as.IDate, format = '%d-%b-%y'), .SDcols = datecols] 

df[, .(START = START[1L], END = END[.N]), by=.(ID, CLASS, r = rleid(ID, CLASS))][, r := NULL][] 
+1

Приятно, хотя я бы перезаписал плохо отформатированные столбцы даты вместо того, чтобы делать только конверсию в части цепочки. Я имею в виду 'df = df%>% mutate_each (funs (.%>% As.Date (format = '% d-% b-% y')), START, END)' перед другим. – Frank

+1

@Frank Да, я пошел на удобочитаемость по поводу переписки. Я думаю, что наиболее кратким было бы заменить «mutate» на 'mutate_each (funs (as.Date (., '% D-% b-% y')), START, END)'. (И редактирование data.table приветствуется, конечно!) – alistaire

+2

@Alistair Nice 'data.table' решение. Но будьте осторожны, преобразование даты работает только для английского языка. Мне пришлось использовать 'Sys.setlocale (« LC_ALL »,« English »)' в моей системе. Спецификация конверсии '% b' ожидает имя месяца в текущей локали. – Uwe