#r #dataframe #collapse
#r #фрейм данных #агрегировать
Вопрос:
У меня есть data.frame
, который выглядит как этот пример data.frame
:
df = data.frame(id = c("a","b","c","d","e","f","g"), start = c(10,20,30,40,50,60,70), end = c(15,25,35,45,55,65,75), flag = c(0,1,1,0,1,0,1))
> df
id start end flag
1 a 10 15 0
2 b 20 25 1
3 c 30 35 1
4 d 40 45 0
5 e 50 55 1
6 f 60 65 0
7 g 70 75 1
Он сортируется в порядке возрастания по df$start
и затем df$end
.
Я ищу функцию, которая объединит все строки, в df$flag == 1
которые не вмешиваются строки df$flag == 0
. Объединенные строки должны быть df$id
объединены с разделителем комы, они df$start
должны быть из строки с min
df$start
, и они df$end
должны быть из строки с max
df$end
. И, наконец, df$flag
для них должно быть 1.
Итак, для этого примера возврат data.frame
должен быть:
res.df = data.frame(id = c("a","b,c","d","e","f","g"), start = c(10,20,40,50,60,70), end = c(15,35,45,55,65,75), flag = c(0,1,0,1,0,1))
> res.df
id start end flag
1 a 10 15 0
2 b,c 20 35 1
3 d 40 45 0
4 e 50 55 1
5 f 60 65 0
6 g 70 75 1
Комментарии:
1. Не могли бы вы уточнить
end
значение? Из вашего объяснения кажется, что оно должно быть 35, но вашеres.df
показывает 25.2. Извините за это. Теперь это исправлено.
3. Еще один вопрос: будет ли когда-либо объединяться более двух строк?
Ответ №1:
Это сложно сделать, aggregate
поскольку одна и та же функция применяется к каждому столбцу по очереди. Несколько вызовов aggregate
могут выполнить это по частям, которые затем объединяются. Однако data.table
позволяет использовать разные функции агрегирования в одном вызове:
library(data.table)
d <- data.table(df)
d[,list(id=paste(id, collapse=','), start=min(start), end=max(end)),
by=list(flag, cumsum(flag==0))
]
flag cumsum id start end
1: 0 1 a 10 15
2: 1 1 b,c 20 35
3: 0 2 d 40 45
4: 1 2 e 50 55
5: 0 3 f 60 65
6: 1 3 g 70 75
В итоге вы получаете новый столбец, который при желании можно удалить. Условие on cumsum(flag==0)
предотвращает flag==0
объединение любых строк с в агрегате и сохраняет непоследовательные flag==1
значения отдельными в результате.
Ответ №2:
Вот решение в base
использовании aggregate
и merge
:
merge(merge(aggregate(start ~ flag cumsum(flag==0), data=df, FUN=min),
aggregate(end ~ flag cumsum(flag==0), data=df, FUN=max)
),
aggregate(id ~ flag cumsum(flag==0), data=df, FUN=paste, sep=',')
)
flag cumsum(flag == 0) start end id
1 0 1 10 15 a
2 0 2 40 45 d
3 0 3 60 65 f
4 1 1 20 35 b, c
5 1 2 50 55 e
6 1 3 70 75 g
Код становится немного более читаемым, если вы используете Reduce
и список фреймов данных для выполнения слияния:
Reduce(merge, list(aggregate(start ~ flag cumsum(flag==0), data=df, FUN=min),
aggregate(end ~ flag cumsum(flag==0), data=df, FUN=max),
aggregate(id ~ flag cumsum(flag==0), data=df, FUN=paste, sep=',')
)
)