【问题标题】:Generate series of columns whose values equal the values of column in another row生成一系列列,其值等于另一行中列的值
【发布时间】:2026-02-22 19:00:01
【问题描述】:

假设我有以下数据集:

data = read.table(text = "teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution
          1 2 2 4 4
          1 3 2 1 4", header = T)

> data
  teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.3.solution
1      1             2               2             4               4
2      1             3               2             1               4

我想为团队中的每个人(具有相同唯一 teamID 的个人)创建一个列,该列对应于他们团队中其他人的价值观。所以,例如:

data_final = read.table(text = "teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution partner_quiz.1.answer partner_quiz.1.solution partner_quiz.2.answer partner_quiz.2.solution
          1 2 2 4 4 3 2 1 4
          1 3 2 1 4 2 2 4 4", header = T)

有了这个输出:

> data_final
  teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution partner_quiz.1.answer partner_quiz.1.solution
1      1             2               2             4               4                     3                       2
2      1             3               2             1               4                     2                       2
  partner_quiz.2.answer partner_quiz.2.solution
1                     1                       4
2                     4                       4

所有相关列都将以“答案”或“解决方案”作为后缀。永远只有两个人的团队。

我可以使用以下代码在每个变量的基础上模拟这种行为。但是,在实际数据集中,我有超过 100 个测验问题和解决方案,因此需要找到一种方法来对匹配特定正则表达式查询的变量执行此操作。即,quiz.[a number 1-100].answer or solution

data <- transform(data,partner_quiz.1.answer=ave(quiz.1.answer,teamID,FUN=rev))

【问题讨论】:

    标签: r


    【解决方案1】:

    如果您知道每个组中只有 2 个人,请切换行,然后覆盖新的变量块:

    nms <- names(data)[-1]
    data <- data[order(data$teamID),]
    data[paste0("partner_",nms)] <- data[seq_len(nrow(data)) + c(1,-1), nms]
    data
    #  teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution
    #1      1             2               2             4               4
    #2      1             3               2             1               4
    #  partner_quiz.1.answer partner_quiz.1.solution partner_quiz.2.answer
    #1                     3                       2                     1
    #2                     2                       2                     4
    #  partner_quiz.2.solution
    #1                       4
    #2                       4
    

    【讨论】:

    • 这是最简单的解决方案。谢谢!
    【解决方案2】:

    data.table 解决方案:

    dt <- data.table(df)
    
    newcols <- paste0("partner_", names(dt)[2:5])
    
    dt[, c(newcols) := .SD[order(-.I)], by = teamID]
    

    c(newcols) := 分配给在newcols 中命名的列。它分配.SD 的内容,这恰好是数据的一个子集(因此是SD),在这种情况下是为每个teamID 过滤的数据。 [order(-.I)] 颠倒子集的顺序(.IteamID-组中的第 i 个元素),所以order(-.I) 将把学生#2 放在第一位,然后将#1 放在后面。 by 部分很容易解释。

    使用的数据:

    df = read.table(text = "teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution
    1 2 2 4 4
    1 3 2 1 4", header = T)
    

    请注意我避免使用data,因为它是utils 包中的函数名称。

    【讨论】:

    • 我不熟悉 data.table,但我得到了Type of RHS ('double') must match LHS ('character'). To check and coerce would impact performance too much for the fastest cases. Either change the type of the target column, or coerce the RHS of := yourself (e.g. by using 1L instead of 1) 我需要将 RHS 强制转换为字符串吗?这些类是我实际数据集中的字符
    • 你能把str(df)的结果贴在这里吗?
    【解决方案3】:

    使用dplyr,我们可以按组反转行号,重命名列并将此数据框绑定到原始数​​据框。

    library(dplyr)
    
    bind_cols(data, data %>%
                     group_by(teamID) %>%
                     slice(n() : 1) %>%
                     ungroup() %>%
                     select(-teamID) %>%
                     rename_all(~paste0("partner_", .)))
    
    #  teamID quiz.1.answer quiz.1.solution quiz.2.answer quiz.2.solution partner_quiz.1.answer
    #1      1             2               2             4               4                     3
    #2      1             3               2             1               4                     2
    
    #  partner_quiz.1.solution partner_quiz.2.answer partner_quiz.2.solution
    #1                       2                     1                       4
    #2                       2                     4                       4
    

    如果还有其他列并且我们只想选择以"solution""answer" 结尾的列,我们可以在select 中使用matches

    bind_cols(data, data %>%
         select(teamID, matches("answer$|solution$")) %>%
         group_by(teamID) %>%
         slice(n() : 1) %>%
         ungroup() %>%
         select(-teamID) %>%
        rename_all(~paste0("partner_", .)))
    

    【讨论】:

      最近更新 更多