是否有一种有效的方法可以根据预聚合数据 (R) 计算百分位数?
Is there an efficient way to calculate percentiles from pre-aggregated data (R)?
首先:这是我的第一个问题,我也是 R 的新手。所以,如果这是一个愚蠢的问题或错误的提问方式,我很抱歉。
我有这样一个数据框:
df <- data.frame(Website = c("A", "A", "A", "B", "B", "B"),
seconds = c(1,12,40,3,5,14),
visitors = c(200000,100000,12000,250000,180000,90000))
> df
Website seconds visitors
A 1 200000
A 12 100000
A 40 12000
B 3 250000
B 5 180000
B 14 90000
如何解读数据:网站A有200000人访问该网站仅1秒,100000人访问该网站12秒等。
实际上,数据有大约一百个不同的网站,每个网站的秒数从 0 到大约 900(分别有大量访问者)。
现在,我想计算访问持续时间的百分位数或至少四分位数(对于每个网站)。
我已经在这里找到并尝试了这个解决方案:
但是,此解决方案效率非常低,因为它会导致数据帧具有数百万行(并且处理时间非常长)。
我现在的问题是:是否有更快(更有效的方法)从此类预聚合数据计算百分位数?
我相信这样会更快。首先创建一个函数来计算您指定的分位数。然后将数据拆分成一个列表并使用 sapply
:
quant <- function(x, p=c(.25, .50, .75)) {
v <- c(0, cumsum(x$visitors)/sum(x$visitors))
s <- c(0, x$seconds)
approx(v, s, p)$y
}
df.split <- split(df, df$Website)
p <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9)
stats <- t(sapply(df.split, quant, p=p))
colnames(stats) <- as.character(p)
round(stats, 1)
# 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
# A 0.2 0.3 0.5 0.6 0.8 0.9 3.0 6.5 9.9
# B 0.6 1.2 1.9 2.5 3.1 3.7 4.3 4.8 8.8
为了更好地了解发生了什么,这里有一张图表显示了网站 A 的数据:
test1 <- df[1:3, ]
test1$cumvis <- cumsum(test1$visitors)
barplot(test1$seconds, test1$visitors, space=0, xlim=c(0, 325000))
axis(1, seq(0, 300000, 50000), c("0", "50K", "100K", "150K", "200K",
"250K", "300K"), xpd=NA)
axis(3, seq(0, sum(test1$visitors), by=31200), seq(0, 1, by=.1), lty=1)
lines(c(0, test1$cumvis), c(0, test1$seconds), col="red", lwd=2)
lines(c(0, test1$cumvis-.5*test1$visitors, tail(test1$cumvis, 1)),
c(0, test1$seconds, tail(test1$seconds, 1)), col="blue", lwd=2)
该图将数据显示为灰色矩形。底部的 x 轴显示累计访问次数,顶部的 x 轴显示累计比例。我们可以将矩形视为分布,或者我们可以假设矩形是近似于基础分布的样本。我建议的解决方案采用红线并使用 approx
函数在数据点之间使用线性插值来估计沿该曲线的秒数。
相同的方法可以用于不同的曲线定义,其中数据点位于每个矩形的中间,即蓝色曲线。我还将提供该方法的代码。也可以在不复制原始数据的情况下估计分位数。
首先是估计沿蓝线的分位数的函数:
quant2 <- function(x, p=c(.25, .50, .75)) {
v <- c(0, cumsum(x$visitors)-(.5*x$visitors)/sum(x$visitors), 1)
s <- c(0, x$seconds, tail(x$seconds, 1))
approx(v, s, p)$y
}
p <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9)
stats <- t(sapply(df.split, quant2, p=p))
colnames(stats) <- as.character(p)
round(stats, 1)
# 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
# A 4.0 8.0 12.0 16.0 20 24.0 28.0 32.0 36.0
# B 1.4 2.8 4.2 5.6 7 8.4 9.8 11.2 12.6
估计值较高,因为蓝线在红线上方。
最后,我们可以简单地使用矩形而不进行任何插值。基本上我们在数据点的边界设置中断,并使用它们来确定哪些比例属于哪些观察组(秒)。
quant3 <- function(x, p=c(.25, .50, .75)){
v <- c(0, cumsum(x$visitors)/sum(x$visitors))
limits <- cut(p, breaks=v, include.lowest=TRUE, labels=x$seconds)
limits <- as.numeric(as.character(limits))
}
p <- 0:10/10
stats <- t(sapply(df.split, quant3, p=p))
colnames(stats) <- as.character(p)
stats
# 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
# A 1 1 1 1 1 1 1 12 12 12 40
# B 3 3 3 3 3 5 5 5 5 14 14
所以对于网站 A,1 秒是分位数 0 - .6 的值。
首先:这是我的第一个问题,我也是 R 的新手。所以,如果这是一个愚蠢的问题或错误的提问方式,我很抱歉。
我有这样一个数据框:
df <- data.frame(Website = c("A", "A", "A", "B", "B", "B"),
seconds = c(1,12,40,3,5,14),
visitors = c(200000,100000,12000,250000,180000,90000))
> df
Website seconds visitors
A 1 200000
A 12 100000
A 40 12000
B 3 250000
B 5 180000
B 14 90000
如何解读数据:网站A有200000人访问该网站仅1秒,100000人访问该网站12秒等。 实际上,数据有大约一百个不同的网站,每个网站的秒数从 0 到大约 900(分别有大量访问者)。
现在,我想计算访问持续时间的百分位数或至少四分位数(对于每个网站)。
我已经在这里找到并尝试了这个解决方案: 但是,此解决方案效率非常低,因为它会导致数据帧具有数百万行(并且处理时间非常长)。
我现在的问题是:是否有更快(更有效的方法)从此类预聚合数据计算百分位数?
我相信这样会更快。首先创建一个函数来计算您指定的分位数。然后将数据拆分成一个列表并使用 sapply
:
quant <- function(x, p=c(.25, .50, .75)) {
v <- c(0, cumsum(x$visitors)/sum(x$visitors))
s <- c(0, x$seconds)
approx(v, s, p)$y
}
df.split <- split(df, df$Website)
p <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9)
stats <- t(sapply(df.split, quant, p=p))
colnames(stats) <- as.character(p)
round(stats, 1)
# 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
# A 0.2 0.3 0.5 0.6 0.8 0.9 3.0 6.5 9.9
# B 0.6 1.2 1.9 2.5 3.1 3.7 4.3 4.8 8.8
为了更好地了解发生了什么,这里有一张图表显示了网站 A 的数据:
test1 <- df[1:3, ]
test1$cumvis <- cumsum(test1$visitors)
barplot(test1$seconds, test1$visitors, space=0, xlim=c(0, 325000))
axis(1, seq(0, 300000, 50000), c("0", "50K", "100K", "150K", "200K",
"250K", "300K"), xpd=NA)
axis(3, seq(0, sum(test1$visitors), by=31200), seq(0, 1, by=.1), lty=1)
lines(c(0, test1$cumvis), c(0, test1$seconds), col="red", lwd=2)
lines(c(0, test1$cumvis-.5*test1$visitors, tail(test1$cumvis, 1)),
c(0, test1$seconds, tail(test1$seconds, 1)), col="blue", lwd=2)
该图将数据显示为灰色矩形。底部的 x 轴显示累计访问次数,顶部的 x 轴显示累计比例。我们可以将矩形视为分布,或者我们可以假设矩形是近似于基础分布的样本。我建议的解决方案采用红线并使用 approx
函数在数据点之间使用线性插值来估计沿该曲线的秒数。
相同的方法可以用于不同的曲线定义,其中数据点位于每个矩形的中间,即蓝色曲线。我还将提供该方法的代码。也可以在不复制原始数据的情况下估计分位数。
首先是估计沿蓝线的分位数的函数:
quant2 <- function(x, p=c(.25, .50, .75)) {
v <- c(0, cumsum(x$visitors)-(.5*x$visitors)/sum(x$visitors), 1)
s <- c(0, x$seconds, tail(x$seconds, 1))
approx(v, s, p)$y
}
p <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9)
stats <- t(sapply(df.split, quant2, p=p))
colnames(stats) <- as.character(p)
round(stats, 1)
# 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
# A 4.0 8.0 12.0 16.0 20 24.0 28.0 32.0 36.0
# B 1.4 2.8 4.2 5.6 7 8.4 9.8 11.2 12.6
估计值较高,因为蓝线在红线上方。
最后,我们可以简单地使用矩形而不进行任何插值。基本上我们在数据点的边界设置中断,并使用它们来确定哪些比例属于哪些观察组(秒)。
quant3 <- function(x, p=c(.25, .50, .75)){
v <- c(0, cumsum(x$visitors)/sum(x$visitors))
limits <- cut(p, breaks=v, include.lowest=TRUE, labels=x$seconds)
limits <- as.numeric(as.character(limits))
}
p <- 0:10/10
stats <- t(sapply(df.split, quant3, p=p))
colnames(stats) <- as.character(p)
stats
# 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
# A 1 1 1 1 1 1 1 12 12 12 40
# B 3 3 3 3 3 5 5 5 5 14 14
所以对于网站 A,1 秒是分位数 0 - .6 的值。