У меня есть таблица со страницами веб-сайта и их посещениями. В некоторых случаях встречаются повторяющиеся строки. Я хочу дедуплицировать строки на основе столбцов YearMonth и Page, суммируя столбцы пользователей и сеансов.
| yearMonth | page | users | sessions | bounceRate |
| --------- | ------ | ----- | -------- | ---------- |
| 202405 | a.html | 20 | 22 | 0.48 |
| 202406 | b.html | 14 | 16 | 0.52 |
| 202405 | a.html | 2 | 3 | 0.90 |
Для столбцаounceRate я хочу либо использовать средневзвешенное значение этих строк (если возможно), либо использовать значение из строки с наибольшим количеством сеансов.
| yearMonth | page | users | sessions | bounceRate |
| --------- | ------ | ----- | -------- | ------------------ |
| 202405 | a.html | 22 | 25 | 0.48 (value of max)|
| 202406 | b.html | 14 | 16 | 0.52 |
Я попробовал приведенный ниже сценарий, но он всегда суммирует столбецounceRate вместо использования значения из строки с наибольшим количеством сеансов:
data <- data.frame(
yearMonth = c(202405, 202406, 202405),
page = c("a.html", "b.html", "a.html"),
users = c(20, 14, 2),
sessions = c(22, 16, 3),
bounceRate = c(0.48, 0.52, 0.90)
)
result <- aggregate(. ~ yearMonth + page, data, function(x) {
if (any(names(x) == "bounceRate")) {
x[which.max(data$Sessions)]
} else {
sum(x)
}
})
print(result)
Для параметраounceRate, связанного с максимальным значением сеанса, вы можете использовать slice_max
из dplyr:
library(dplyr)
summarise(data, users=sum(users), sessions=sum(sessions), .by=c(yearMonth, page)) |>
inner_join(
slice_max(data, sessions, by=c(yearMonth, page)) |>
select(yearMonth, page, bounceRate),
by=c("yearMonth", "page"))
yearMonth page users sessions bounceRate
1 202405 a.html 22 25 0.48
2 202406 b.html 14 16 0.52
Для среднего значенияounceRate:
summarise(data,
users=sum(users),
sessions=sum(sessions),
bounceRate=mean(bounceRate), .by=c(yearMonth, page))
yearMonth page users sessions bounceRate
1 202405 a.html 22 25 0.69
2 202406 b.html 14 16 0.52
Используя base
функции, мы можем split()
фрейм данных перед lapply()
использованием пользовательской функции.
data.s <- split(data, ~ yearMonth + page)
# removing empty elements
data.s <- data.s[sapply(data.s, NROW) > 0]
fun <- function(x) {
users <- sum(x$users)
sessions <- sum(x$sessions)
bounceRate <- weighted.mean(x$bounceRate, x$sessions)
data.frame(x[1,1:2], users, sessions, bounceRate)
}
do.call("rbind", lapply(data.s, fun))
# yearMonth page users sessions bounceRate
# 202405.a.html 202405 a.html 22 25 0.5304
# 202406.b.html 202406 b.html 14 16 0.5200
Используя by
, max
минимальные сеансы,
> by(data, ~interaction(yearMonth, page), \(x) {
+ bounceRate <- with(x, bounceRate[which.max(sessions)])
+ data.frame(x[1, 1:2], t(colSums(x[c('users', 'sessions')])), bounceRate)
+ }) |> do.call(what='rbind')
yearMonth page users sessions bounceRate
202405.a.html 202405 a.html 22 25 0.48
202406.b.html 202406 b.html 14 16 0.52
или weighted.mean
сеансов.
> by(data, ~interaction(yearMonth, page), \(x) {
+ bounceRate <- with(x, weighted.mean(x=bounceRate, w=sessions))
+ data.frame(x[1, 1:2], t(colSums(x[c('users', 'sessions')])), bounceRate)
+ }) |> do.call(what='rbind')
yearMonth page users sessions bounceRate
202405.a.html 202405 a.html 22 25 0.5304
202406.b.html 202406 b.html 14 16 0.5200
Вот еще одно решение с основанием R by
.
Напишите вспомогательную функцию, вычисляющую всю совокупную статистику. И позвоните by
. Затем свяжите все do.call
.
data <- data.frame(
yearMonth = c(202405, 202406, 202405),
page = c("a.html", "b.html", "a.html"),
users = c(20, 14, 2),
sessions = c(22, 16, 3),
bounceRate = c(0.48, 0.52, 0.90)
)
fun <- function(x, na.rm = FALSE) {
yearMonth <- x[["yearMonth"]][1L]
page <- x[["page"]][1L]
users <- sum(x[["users"]], na.rm = na.rm)
sessions <- sum(x[["sessions"]], na.rm = na.rm)
bounceRate <- min(x[["bounceRate"]], na.rm = na.rm)
data.frame(yearMonth, page, users, sessions, bounceRate)
}
by(data, data[1:2], fun) |> do.call(rbind, args = _)
#> yearMonth page users sessions bounceRate
#> 1 202405 a.html 22 25 0.48
#> 2 202406 b.html 14 16 0.52
Created on 2024-06-22 with reprex v2.1.0