【问题标题】:Identify Two-Way Combinations of Levels in a Column for Each ID为每个 ID 识别列中级别的双向组合
【发布时间】:2021-01-16 00:31:38
【问题描述】:

我想确定由idDate 变量分组的一列中级别的双向组合。基本上,我想要每个人每天唯一的字母对。

我有一个如下所示的数据框:

in_df <- data.frame(id = c(1,1,1,1,1,2,2,3), 
                    Date = as.Date(c("2019-01-01", "2019-01-01", "2019-01-01", "2019-01-02", "2019-01-02", "2019-01-01", "2019-01-01", "2019-01-01")), 
                    letter = c("A", "B", "C", "A", "B", "A", "D", "B")) 

in_df
  id       Date letter
1  1 2019-01-01      A
2  1 2019-01-01      B
3  1 2019-01-01      C
4  1 2019-01-02      A
5  1 2019-01-02      B
6  2 2019-01-01      A
7  2 2019-01-01      D
8  3 2019-01-01      B

我想要一个看起来像这样的:

out_df
  id       Date letter_1 letter_2
1  1 2019-01-01        A        B
2  1 2019-01-01        A        C
3  1 2019-01-01        B        C
4  1 2019-01-02        A        B
5  2 2019-01-01        A        D
6  3 2019-01-01        B        NA

所以第一个 id 和第一个 Date 有字母 A、B 和 C。我想要这三个中的每一对。顺序无关紧要,所以切换到 letter_1letter_2 将是一回事。

我玩过expand.gridcombn,但似乎都不太适合这项任务。

编辑

我也有每个id/Date 只有一行的情况,所以使用combn 给我Error in combn(letter, m = 2) : n &lt; m。如何添加 if 案例以使 letter_2 获得 NA? (我还更新了上面的 dfs 来解决这个问题)

【问题讨论】:

  • 您能否详细说明输出中的第二行和第三行是如何创建的?我的意思是letter_1letter_2 中的值。
  • @tmfmnk 感谢您的快速回复!我试着澄清一下,这有帮助吗?

标签: r


【解决方案1】:

使用data.table

require(data.table); setDT(in_df)

dt = in_df[, data.table(t(combn(letter, m = 2))), .(id, Date)]

输出:

> dt
   id       Date V1 V2
1:  1 2019-01-01  A  B
2:  1 2019-01-01  A  C
3:  1 2019-01-01  B  C
4:  1 2019-01-02  A  B
5:  2 2019-01-01  A  D

【讨论】:

  • 所有答案都充分回答了我最初的问题,但这是我唯一可以为我稍微复杂的实际数据工作的答案。谢谢!
【解决方案2】:

我们可以使用splitcombn

do.call('rbind', 
        lapply(split(in_df, list(in_df$id, in_df$Date), drop = TRUE), 
               FUN = function(d) 
                 cbind.data.frame(unique(d[c('id', 'Date')]), 
                                  data.frame(t(
                                    if(length(d$letter) > 1){
                                      combn(d$letter, 2)    
                                    }else{
                                      matrix(c(d$letter, NA), nrow = 2)
                                    })))))


#                id       Date X1 X2
# 1.2019-01-01.1  1 2019-01-01  A  B
# 1.2019-01-01.2  1 2019-01-01  A  C
# 1.2019-01-01.3  1 2019-01-01  B  C
# 2.2019-01-01    2 2019-01-01  A  D
# 1.2019-01-02    1 2019-01-02  A  B

逐步完成此操作可能会有所帮助。调查以下输出:

(ss <- split(in_df, list(in_df$id, in_df$Date), drop = TRUE))

然后退房:

lapply(ss, FUN = function(d) data.frame(t(combn(d$letter, 2))))

剩下的部分,我们只是合并数据。您可能需要稍微调整一下列名。

【讨论】:

  • 谢谢!!我也有每个id/Date 只有一行的情况,所以当我使用这个答案时,我得到Error in combn(letter, m = 2) : n &lt; m。如何在 if 情况下添加 letter_2 获得 NA?
  • 查看编辑...它使代码有点复杂,但它应该可以处理您的情况
  • 它已经运行了大约一个小时。也许我的数据对于这种方法来说太大了。不过这真的很有帮助,谢谢!
【解决方案3】:

我认为以下代码有效:

library("dplyr")
in_df %>% 
  group_by(id, Date) %>% 
  mutate(
    letter_1 = combn(letter, 2)[1, ],
    letter_2 = combn(letter, 2)[2, ]
  ) %>% 
  distinct(letter_1, letter_2)


# # A tibble: 5 x 4
# # Groups:   id, Date [3]
#   letter_1 letter_2    id Date      
#   <fct>    <fct>    <dbl> <date>    
# 1 A        B            1 2019-01-01
# 2 A        C            1 2019-01-01
# 3 B        C            1 2019-01-01
# 4 A        B            1 2019-01-02
# 5 A        D            2 2019-01-01

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-03
    • 2020-03-19
    • 2020-03-19
    • 2018-03-10
    • 2021-08-04
    相关资源
    最近更新 更多