我有这个data.frame

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))


每行是来自某个主题(由id指定)的100个测量值,该主题与父ID(由parent.id指定)相关联。 parent.idid之间的关系是一对多的。

我正在寻找一种快速方法,以从其df$id的测量值中减去每个parent.id的分数(对于其100个测量值)。这意味着对于id中的每个df$id,我要将其100个测量值中的每一个除以其所有df$id对应于其df$parent.id的测量值之和。

我正在尝试的是:

sum.df <- dplyr::select(df,-id) %>% dplyr::group_by(parent.id) %>% dplyr::summarise_all(sum)

fraction.df <- do.call(rbind,lapply(df$id,function(i){
  pid <- dplyr::filter(df,id == i)$parent.id
  (dplyr::filter(df,id == i) %>% dplyr::select(-id,-parent.id))/
    (dplyr::filter(sum.df,parent.id == pid) %>% dplyr::select(-parent.id))
}))


但是对于我的数据的真实维度:length(df$id) = 10,000个,具有1,024个测量值,这还不够快。

知道如何改进此方法,最好使用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 

08-04 10:14