2017-01-10 1 views
2

У меня есть dataframe, который выглядит как:Совокупность R на основе нескольких столбцов, а затем слияние в dataframe?

id<-c(1,1,1,3,3) 
date1<-c("23-01-08","01-11-07","30-11-07","17-12-07","12-12-08") 
type<-c("A","B","A","B","B") 
df<-data.frame(id,date,type) 
df$date<-as.Date(as.character(df$date), format = "%d-%m-%y") 

То, что я хочу, чтобы добавить новый столбец, который содержит самую раннюю дату для каждого идентификатора для каждого типа. Эта первая попытка работает нормально и выполняет агрегацию и объединение на основе только идентификатора.

d = aggregate(df$date, by=list(df$id), min) 
df2 = merge(df, d, by.x="id", by.y="Group.1") 

То, что я хочу, хотя это также фильтровать по типу и получить этот результат:

data.frame(df2, desired=c("2007-11-30","2007-11-01", "2007-11-30","2007-12-17","2007-12-17")) 

Я пробовал много возможностей. Я действительно думаю, что это может быть сделано со списками, но я в убыток, как ...

d = aggregate(df$date, by=list(df$id, df$type), min) 

# And merge the result of aggregate with the original data frame 
df2 = merge(df,d,by.x=list("id","type"),by.y=list("Group.1","Group.2")) 

Для этого простого примера я просто не мог отделить типы в их собственный Д.Ф., построить новый столбец, а затем объединить в результате 2 dfs, но на самом деле существует много типов и 3-й столбец, который также необходимо фильтровать аналогично, что было бы нецелесообразно ...

Спасибо!

+0

У вас есть несоответствие между опечатка '' date1' и date' при создании 'df' – thelatemail

+0

@thelatemail Вы правы. Я пошел по кругу, чтобы сделать эту колонку с датой ... – Soran

ответ

2

Мы можем использовать data.table. Преобразуйте 'data.frame' в 'data.table' (setDT(df)), сгруппированные по 'id', 'type' (или с 'id'), order 'date' и присвойте (:=) первый элемент 'date 'как столбец «самая ранняя».

library(data.table) 
setDT(df)[order(date), earliestdateid := date[1], by = id 
    ][order(date), earliestdateidtype := date[1], by = .(id, type)] 
df 
# id  date type earliestdateid earliestdateidtype 
#1: 1 2008-01-23 A  2007-11-01   2007-11-30 
#2: 1 2007-11-01 B  2007-11-01   2007-11-01 
#3: 1 2007-11-30 A  2007-11-01   2007-11-30 
#4: 3 2007-12-17 B  2007-12-17   2007-12-17 
#5: 3 2008-12-12 B  2007-12-17   2007-12-17 

Аналогичный подход с dplyr является

library(dplyr) 
df %>% 
    group_by(id) %>% 
    arrange(date) %>% 
    mutate(earliestdateid = first(date)) %>% 
    group_by(type, add = TRUE) %>% 
    mutate(earliestdateidtype = first(date)) 

ПРИМЕЧАНИЕ: Это не делать это в два этапа, т.е. получить обобщенную выход, а затем присоединиться к

+1

Ничего себе, поэтому мне нравится R. Сложная куча операций, которые выполняются в 1 строке. И я подумал, что 2 линии были великолепны. Если я столкнулся с чем-то похожим, но вместо числового столбца вместо цифры, я просто изменил бы порядок (дату) на значение (числа) или что-то подобное для метода data.table? – Soran

+1

@Soran Если вы просто хотите «mean (numbers)», тогда «order» не требуется, т. Е. 'SetDT (df) [, Mean: = mean (numbers),. (Id, type)]' – akrun

2

Вы можете получить два минимума различными группами с использованием ave вместо:

df$minid <- with(df, ave(date, id, FUN=min, drop=TRUE)) 
df$minidtype <- with(df, ave(date, list(id,type), FUN=min, drop=TRUE)) 
df 

# id  date type  minid minidtype 
#1 1 2008-01-23 A 2007-11-01 2007-11-30 
#2 1 2007-11-01 B 2007-11-01 2007-11-01 
#3 1 2007-11-30 A 2007-11-01 2007-11-30 
#4 3 2007-12-17 B 2007-12-17 2007-12-17 
#5 3 2008-12-12 B 2007-12-17 2007-12-17 

Если бы вы были хитрыми вы могли бы сделать все это в одном вызове тоже:

df[c("minid", "minidtype")] <- lapply(list("id", c("id","type")), 
            FUN=function(x) ave(df$date, df[x], FUN=min, drop=TRUE))