r - 对具有交叉组的 tibbles 执行类似 `top_n` 的操作

标签 r dplyr grouping greatest-n-per-group tibble

我正在尝试编写一个 R 脚本来执行以下任务。我有两个问题:

library(dplyr); library(magrittr)

(
tibs <- list(
        top = tibble(
                letter = c(rep("A",4),rep("B",4)), 
                number = c(rep(1,2), rep(2,2)) %>% rep(2),
                element = c("x","y","z","w","x","y","z","w"),
                score = 1:8
                ) %>% group_by(letter,number),
        bottom = tibble(
                letter = c(rep("A",2),rep("B",2)),
                element = c("p","q","y","z"),
                score = c(2.5,3.5, 4,5.5)
                ) %>% group_by(letter)
        )
)

# A tibble: 8 x 4
# Groups:   letter, number [4]
  letter number element score
  <chr>   <dbl> <chr>   <int>
1 A           1 x           1
2 A           1 y           2
3 A           2 z           3
4 A           2 w           4
5 B           1 x           5
6 B           1 y           6
7 B           2 z           7
8 B           2 w           8

$bottom
# A tibble: 4 x 3
# Groups:   letter [2]
  letter element score
  <chr>  <chr>   <dbl>
1 A      p         2.5
2 A      q         3.5
3 B      y         4  
4 B      z         5.5

对于每个组 Xn由字母(X =“A”或“B”)和数字(n = 1 或 2)定义的顶级 tibble 的,我想在出现的元素中选择两个得分最低的元素在群里Xn顶级 tibble 或组中的 X较低级别的tibble。如果一个元素同时出现在顶层和低层tibble中,它的分数取自top。小标题。

所以,在这个例子中,我期望得到 x,yA1 , p,zA2 , x,zB1y,zB2 .

我必须对具有多达一百万个不同组(在顶级)并且每个组中有几个条目的(顶级)tibbles 执行这种操作。我想获得一个快速并且可能可读的解决方案,无论是否在 dplyr 内。


到目前为止,我的解决方案返回了预期的输出,但从效率的角度来看尤其不令人满意:

summarizer <- function(letter, element, score, bottom){
        bottom %<>% filter(letter == !!letter[1], !(element %in% !!element))
        order(c(score, bottom$score)) %>%
                c(element, bottom$element)[.] %>%
                head(2) %>%
                paste0(collapse = " ")
}


tibs$top %>% summarise(preds = summarizer(letter, element, score, 
                                          tibs$bottom)
                       )


# A tibble: 4 x 3
# Groups:   letter [2]
  letter number preds
  <chr>   <dbl> <chr>
1 A           1 x y  
2 A           2 p z  
3 B           1 x z  
4 B           2 y z  


特别是对于大量组,最大的瓶颈是管道分配 %<>%在我的函数中 summarizer ,但是我看不出如何避免。


我有以下与上述相关的问题:

  1. dplyr根据构造,'s group_by 组从不相交。有没有一种方法(在 dplyr 内或不在 dplyr 内)以行可以属于多个组的方式对 data.frames 进行分组?
  2. 如果没有,我的任务可以通过创建属于更多组的元素的副本并适本地标记它们来解决。您将如何快速完成此操作?
  3. 您是否看到针对上述问题的任何其他快速(并且可能可读)解决方案?

最佳答案

这是一个使用 data.table 的选项。

library(data.table)
setDT(top)
setDT(bottom)

#get unique groups
g = unique(top[,.(letter, number)])

#creating duplicates for each letter in bottom for each group using a left join on letter
b = bottom[g, on=.(letter)]

#If an element appears both in the top- and lower-level tibble, it's score is taken from the top tibble.
#use an update join to lookup the scores from top tibble
b[top, on=.(letter, number, element), score := i.score]

#bind_rows and remove identical rows
rowsbind = rbindlist(list(top, b), use.names=TRUE)
both = unique(rowsbind, by=c("letter", "number", "element"))

#order and subset
setorder(both, letter, number, score)
both[rowid(letter, number) <= 2L]

数据:

library(data.table)
top = data.table(
    letter = c(rep("A",4),rep("B",4)), 
    number = rep(c(rep(1,2), rep(2,2)), 2),
    element = c("x","y","z","w","x","y","z","w"),
    score = as.double(1:8)
)
bottom = data.table(
    letter = c(rep("A",2),rep("B",2)),
    element = c("p","q","y","z"),
    score = c(2.5,3.5, 4,5.5)
) 

关于r - 对具有交叉组的 tibbles 执行类似 `top_n` 的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62677952/

相关文章:

r - 在单个图例中设置多种文本大小

r - 使用 R 中的 GGplot2 更改 CGPfunctions::Plot2WayANOVA 图中图例和点形状的大小

r - ifelse 函数中的动态变量名称

Javascript:在不记得最后一场比赛的情况下在正则表达式中反向引用

r - 如何使用 R 中不同数据集创建的模型来预测新数据集的结果?

r - 在集群服务器上的 slurm 中提交 R 作业,并将对象保存在与 slurm 工作目录不同的目录中

JavaScript:按一个键对项目进行分组,按另一个键对(!)组内的项目进行排序 - 怎么样?

python - 在 Pandas 中添加多列

r - 如何在列上使用 tidyeval 进行变异?

r - kmeans 对分组数据进行聚类