【问题标题】:join in data.table keeping column ids加入 data.table 保留列 ID
【发布时间】:2019-02-01 11:43:06
【问题描述】:

在 data.table 中执行联接后,我想保留列(数据框中的“人”)。我能够得到接近所需输出的东西,但由于我对 data.table 的经验有限,它需要在 data.table 和 dplyr 之间切换:

这里是数据框:

df<-structure(list(person = c("p1", "p1", "p1", "p1", "p1", "p1", 
"p1", "p2", "p2", "p2", "p3", "p3", "p3", "p4", "p4", "p4", "p5", 
"p5", "p5", "p6", "p6", "p6", "p7", "p7", "p7"), hp_char = c("hp1", 
"hp2", "hp3", "hp4", "hp5", "hp6", "hp7", "hp8", "hp9", "hp10", 
"hp1", "hp2", "hp3", "hp5", "hp6", "hp7", "hp8", "hp9", "hp10", 
"hp3", "hp4", "hp5", "hp1", "hp2", "hp3")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -25L), .Names = c("person", 
"hp_char"), spec = structure(list(cols = structure(list(person = structure(list(), class = c("collector_character", 
"collector")), hp_char = structure(list(), class = c("collector_character", 
"collector"))), .Names = c("person", "hp_char")), default = structure(list(), class = c("collector_guess", 
"collector"))), .Names = c("cols", "default"), class = "col_spec"))

我正在做一个自连接来获取任意两个“hp_id”同时出现的实例数,如下所示(类似于this question 中的详细说明)。我将“人”保留在by=.(...) 中,以查看谁参与了共现组合(例如 hp1 和 hp2 在个人 p1、p3 和 p7 中同时出现):

df_by2<- setDT(df)[df, on = "person", allow = TRUE][
    hp_char < i.hp_char, .N, by = .(person ,HP_ID1 = hp_char, HP_ID2 = i.hp_char)]

但由于by =.(person,... 中包含“person”,因此计数(= N)根据“person”、“hp_id”和“hp_id2”的组合进行分隔。所以我切换到 dplyr 以接近我想要的如下。

dfx<- df_by2 %>% group_by(HP_ID1,HP_ID2) %>% mutate (counts=length(person)) %>% spread(person,person) %>% select (-N) %>% unique() %>% filter(counts>1) %>% unite(person,p1:p7, sep="") %>% mutate (involved_id=gsub('?NA', ' ', person)) %>% select (-person)

这是我得到的输出:

# A tibble: 12 x 4
   HP_ID1 HP_ID2 counts   involved_id
    <chr>  <chr>  <int>      <chr>
 1    hp1    hp2      3 p1 p3   p7
 2    hp1    hp3      3 p1 p3   p7
 3   hp10    hp8      2   p2  p5  
 4   hp10    hp9      2   p2  p5  
 5    hp2    hp3      3 p1 p3   p7
 6    hp3    hp4      2  p1    p6 
 7    hp3    hp5      2  p1    p6 
 8    hp4    hp5      2  p1    p6 
 9    hp5    hp6      2  p1  p4   
10    hp5    hp7      2  p1  p4   
11    hp6    hp7      2  p1  p4   
12    hp8    hp9      2   p2  p5 

这很接近,但所需的输出(格式正确但不整洁的“involved_id”列)是:

# A tibble: 12 x 4
   HP_ID1 HP_ID2 counts   involved_id
    <chr>  <chr>  <int>      <chr>
 1    hp1    hp2      3 p1, p3, p7
 2    hp1    hp3      3 p1, p3, p7
 3   hp10    hp8      2     p2, p5
 4   hp10    hp9      2     p2, p5
 5    hp2    hp3      3 p1, p3, p7
 6    hp3    hp4      2     p1, p6
 7    hp3    hp5      2     p1, p6
 8    hp4    hp5      2     p1, p6
 9    hp5    hp6      2     p1, p4
10    hp5    hp7      2     p1, p4
11    hp6    hp7      2     p1, p4
12    hp8    hp9      2     p2, p5

所有这些都非常麻烦,我想知道是否有更简单的方法。我最近刚刚遇到 data.table 并喜欢学习它。非常感谢使用 data.table 的任何帮助。

【问题讨论】:

  • "hp10" &lt; "hp9" == TRUE 的情况下,您比较hp_char &lt; i.hp_char 是否按预期工作?
  • 嗨。请提出独立的问题,包括链接中您需要的任何内容,并附上信用。尤其是不要让我们去问第三个问题。
  • @SymbolixAU 对不起,我错过了你的意思。你能澄清一下吗?就输出而言,我看起来很好,有/没有从 .by(..) 中删除“人”。
  • “hp10”是否小于或大于“hp9”?
  • @SymbolixAU 这些是离散字符。如果我正确地理解了你,那么任何 hp_chars' 之间都没有关系。

标签: r dataframe join data.table


【解决方案1】:

也许您对“全部tidyverse”方法感兴趣(使用combn 进行自我加入加上摘要)?

df %>%
    group_by(person) %>%
    summarise(tmp = list(setNames(
        as_tibble(t(combn(hp_char, 2))),
        c("HP_ID1", "HP_ID2")))) %>%
    unnest() %>%
    group_by(HP_ID1, HP_ID2) %>%
    summarise(
        counts = n(),
        involved_id = toString(person)) %>%
    filter(counts > 1)
## A tibble: 12 x 4
## Groups:   HP_ID1 [8]
#   HP_ID1 HP_ID2 counts involved_id
#   <chr>  <chr>   <int> <chr>
# 1 hp1    hp2         3 p1, p3, p7
# 2 hp1    hp3         3 p1, p3, p7
# 3 hp2    hp3         3 p1, p3, p7
# 4 hp3    hp4         2 p1, p6
# 5 hp3    hp5         2 p1, p6
# 6 hp4    hp5         2 p1, p6
# 7 hp5    hp6         2 p1, p4
# 8 hp5    hp7         2 p1, p4
# 9 hp6    hp7         2 p1, p4
#10 hp8    hp10        2 p2, p5
#11 hp8    hp9         2 p2, p5
#12 hp9    hp10        2 p2, p5

【讨论】:

  • 谢谢!..虽然使用 combn() 我正在处理的大型数据集需要很长时间(如果同时发生 > 2 个事件会更糟)。但这适用于较小的数据框。我将它与 data.table 部分混合。如果我没有得到 data.table 的答案,我会打勾:)。
  • @thisisrg 我明白了;在这种情况下,我会使用来自arrangements 的优化方法来获得所有成对组合。速度增加应该是显着的。如果您可以提供更大的代表性数据集,我会对运行基准比较感兴趣。
  • @ Maurits Evers 所以与我发布的数据集等效的数据集是:110000 行,4000 个唯一的 hp_chars(hp1...hp4000) 和 11000 个唯一的人 (p1,..,p11000)。跨度>
【解决方案2】:

继续之前发布的答案here(为方便起见,也复制到此处),改为使用.(.N, involved_id=paste(x.person, collapse=", ")) 作为最终所需的输出:

library(data.table)
setDT(df)

nset <- 3
cols <- paste0("hp_char", seq_len(nset))

#create combinations of nset number of skills
combi <- do.call(CJ, rep(df[,.(unique(hp_char))], nset))
setnames(combi, cols)

#create for each person the combinations of nset number of skills
nsetSkills <- df[, do.call(CJ, rep(.(hp_char), nset)), by=.(person)]
setnames(nsetSkills, names(nsetSkills)[-1L], cols)

ans <- nsetSkills[combi, on=cols, 
    .(.N, involved_id=paste(x.person, collapse=", ")), by=.EACHI]
ans

输出:

      hp_char1 hp_char2 hp_char3 N involved_id
   1:      hp1      hp1      hp1 3  p1, p3, p7
   2:      hp1      hp1     hp10 0          NA
   3:      hp1      hp1      hp2 3  p1, p3, p7
   4:      hp1      hp1      hp3 3  p1, p3, p7
   5:      hp1      hp1      hp4 1          p1
  ---                                         
 996:      hp9      hp9      hp5 0          NA
 997:      hp9      hp9      hp6 0          NA
 998:      hp9      hp9      hp7 0          NA
 999:      hp9      hp9      hp8 2      p2, p5
1000:      hp9      hp9      hp9 2      p2, p5

【讨论】:

  • 帖子应该是独立的。请将此编辑为对该问题的独立答案。
  • 谢谢@chinsoon12..对于较大的数据框,解决方案相对较快。也明确的答案..帮助我对 data.table 的理解更多。
猜你喜欢
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
相关资源
最近更新 更多