R 有效地计算一个数据帧与另一个数据帧的比例
我有这个R 有效地计算一个数据帧与另一个数据帧的比例,r,performance,dataframe,dplyr,R,Performance,Dataframe,Dplyr,我有这个数据框: set.seed(1) df <- cbind(matrix(rnorm(26,100),26,100),data.frame(id=LETTERS,parent.id=sample(letters[1:5],26,replace = T),stringsAsFactors = F)) 但是对于我的数据的真实维度:length(df$id)=10000,有1024个测量值,这还不够快 如果理想情况下使用dplyr函数,您知道如何改进这一点吗?您的数据存在的问题是所有行都
数据框
:
set.seed(1)
df <- cbind(matrix(rnorm(26,100),26,100),data.frame(id=LETTERS,parent.id=sample(letters[1:5],26,replace = T),stringsAsFactors = F))
但是对于我的数据的真实维度:length(df$id)
=10000,有1024个测量值,这还不够快
如果理想情况下使用
dplyr
函数,您知道如何改进这一点吗?您的数据存在的问题是所有行都是相互重复的,因此我稍微更改了它以反映数据集中的不同值
数据:
set.seed(1L)
df <- cbind(matrix(rnorm(2600), nrow = 26, ncol = 100),data.frame(id=LETTERS,parent.id=sample(letters[1:5],26,replace = T),stringsAsFactors = F))
library('data.table')
setDT(df) # assign data.table class by reference
# compute sum for each `parent.id` for each column (100 columns)
sum_df <- df[, .SD, .SDcols = which(colnames(df) != 'id' )][, lapply(.SD, sum ), by = .(parent.id ) ]
# get column names for sum_df and df which are sorted for consistency
no_pid_id_df <- gtools::mixedsort( colnames(df)[ ! ( colnames(df) %in% c( 'id', 'parent.id' ) ) ] )
no_pid_sum_df <- gtools::mixedsort( colnames(sum_df)[ colnames(sum_df) != 'parent.id' ] )
# match the `parent.id` for each `id` and then divide its value by the value of `sum_df`.
df[, .( props = {
pid <- parent.id
unlist( .SD[, .SD, .SDcols = no_pid_id_df ] ) /
unlist( sum_df[ parent.id == pid, ][, .SD, .SDcols = no_pid_sum_df ] )
}, parent.id ), by = .(id)]
# id props parent.id
# 1: A -0.95157186 e
# 2: A 0.06105359 e
# 3: A -0.42267771 e
# 4: A -0.03376174 e
# 5: A -0.16639600 e
# ---
# 2596: Z 2.34696158 e
# 2597: Z 0.23762369 e
# 2598: Z 0.60068440 e
# 2599: Z 0.14192337 e
# 2600: Z 0.01292592 e
library('microbenchmark')
microbenchmark( sathish(), frank(), dan())
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# sathish() 404.450219 413.456675 433.656279 420.46044 429.876085 593.44202 100 c
# frank() 2.035302 2.304547 2.707019 2.47257 2.622025 18.31409 100 a
# dan() 17.396981 18.230982 19.316653 18.59737 19.700394 27.13146 100 b
基准测试:
set.seed(1L)
df <- cbind(matrix(rnorm(2600), nrow = 26, ncol = 100),data.frame(id=LETTERS,parent.id=sample(letters[1:5],26,replace = T),stringsAsFactors = F))
library('data.table')
setDT(df) # assign data.table class by reference
# compute sum for each `parent.id` for each column (100 columns)
sum_df <- df[, .SD, .SDcols = which(colnames(df) != 'id' )][, lapply(.SD, sum ), by = .(parent.id ) ]
# get column names for sum_df and df which are sorted for consistency
no_pid_id_df <- gtools::mixedsort( colnames(df)[ ! ( colnames(df) %in% c( 'id', 'parent.id' ) ) ] )
no_pid_sum_df <- gtools::mixedsort( colnames(sum_df)[ colnames(sum_df) != 'parent.id' ] )
# match the `parent.id` for each `id` and then divide its value by the value of `sum_df`.
df[, .( props = {
pid <- parent.id
unlist( .SD[, .SD, .SDcols = no_pid_id_df ] ) /
unlist( sum_df[ parent.id == pid, ][, .SD, .SDcols = no_pid_sum_df ] )
}, parent.id ), by = .(id)]
# id props parent.id
# 1: A -0.95157186 e
# 2: A 0.06105359 e
# 3: A -0.42267771 e
# 4: A -0.03376174 e
# 5: A -0.16639600 e
# ---
# 2596: Z 2.34696158 e
# 2597: Z 0.23762369 e
# 2598: Z 0.60068440 e
# 2599: Z 0.14192337 e
# 2600: Z 0.01292592 e
library('microbenchmark')
microbenchmark( sathish(), frank(), dan())
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# sathish() 404.450219 413.456675 433.656279 420.46044 429.876085 593.44202 100 c
# frank() 2.035302 2.304547 2.707019 2.47257 2.622025 18.31409 100 a
# dan() 17.396981 18.230982 19.316653 18.59737 19.700394 27.13146 100 b
让我们将这些选项与
microbenchmark
进行比较,所有选项都使用@Sathish答案中数据集的新定义:
OP方法:
Units: seconds
min lq mean median uq max neval
1.423583 1.48449 1.602001 1.581978 1.670041 2.275105 100
@Sathish方法将其速度提高约5倍。当然,这是很有价值的
Units: milliseconds
min lq mean median uq max neval
299.3581 334.787 388.5283 363.0363 398.6714 951.4654 100
下面一个可能的base R实现使用了高效R代码的原理,将性能提高了约65倍(24毫秒,而不是1582毫秒):
下面是基本的R实现。与OP的实现一样,parent.id
和id
列不包括在结果结构中(此处为分数
)<代码>分数是一个矩阵,其行按照排序(交互(df$id,df$parent.id,drop=TRUE))排序
values“我正在寻找一种快速的方法来获取它的parent.id
的测量值中每个df$id
(每100个测量值)的分数。”我不理解这句话。你能提供一个例子来详细说明你想要计算什么吗?编辑我的帖子以使其更清晰。你的数据框的尺寸是多少?10000 x 1024-参见编辑的帖子如果你关心速度,转换为长格式可能会有所帮助。对于看起来像res=melt(DT,id=c(“id”,“parent.id”))[,v:=value/sum(value),by=(variable,parent.id)][]
的data.table,返回到wide,dcast(res,id+parent.id~ variable,value.var=“v”)
这不是特别快。与OPs相比,这是一个因数5的改进。向上投票:)我不知道我是否认为它会更快。如果你想加快速度,你可以转换成一个矩阵,在这种情况下,行与列或宽与长是不相关的。你是如何实现Frank的方法的?很好!如果你想比较的话,请随意添加我的。