【问题标题】:Coding dichotomous variable based on changes in the relative highest score between a set of variables根据一组变量之间相对最高分的变化对二分变量进行编码
【发布时间】:2026-02-13 07:20:05
【问题描述】:

我想根据一组规则在数据框中编写一个新变量。我有一个带有主题变量、时间变量和变量 A、B 和 C 的数据框 df1,如下所示:

subject <- c(1,1,1,1,1,1,2,2,2,2,2,2)
time <- c(1,2,3,4,5,6,1,2,3,4,5,6)
A <- c(1,7,7,6,6,5,1,2,3,NA,NA,NA)
B <- c(2,1,1,1,1,1,6,5,4,NA,NA,NA)
C <-c(7,1,6,1,6,1,6,2,4,NA,NA,NA)

df1 <- data.frame(subject,time,A,B,C)

A、B 和 C 中的值范围从 1(最低)到 7(最高),也有一些 NA。现在我想编写一个新的二分变量newvar。每个主题的第一行应始终编码为 0。每当一行中得分最高的变量(A、B 或 C)更改为下一行中的一个或多个不同变量时,应编码为 1 .一个变量内的值是否从一行变化到下一行无关紧要,只要三个变量中的哪一个在一行内的得分与前一行相比有所变化。

df1 中的示例应该更清楚地说明这一点:

  • 第 1 行编码为 0,因为它是主题 1 的第一行。C 具有 A、B、C三个变量中得分最高。

  • 在第 2 行中,A 得分最高。因此,newvar = 1。

  • 在第 3 行中,A 仍然得分最高,因此 newvar = 0。

  • 在第 4 行,A 仍然得分最高 --> newvar = 0。

  • 在第 5 行,现在 A 和 C 的得分最高,因此, 新变量 = 1。

  • 在第 6 行中,只有 A 再次获得最高分,因此,newvar = 1。

  • 第 7 行是主题 2 的第一行,因此 newvar 编码为 0。

  • 在第 8 行中,newvar 应编码为 1,因为在前一行中,B 和C同样得分最高,现在只有B。

  • 在第 9 行,newvar 应该再次编码为 1,因为现在 B 和 C 有 再次获得该行的最高分。

  • 第 10 到 12 行应编码为 NA。

它应该是这样的:

newvar <-c(0,1,0,0,1,1,0,1,1,NA,NA,NA)
df2 <- data.frame(subject,time,A,B,C,newvar)

我将不胜感激任何关于如何解决此问题的意见!

【问题讨论】:

    标签: r


    【解决方案1】:

    这是使用tidyverse 的一种方法。首先,将您的数据转换为长格式。然后,对于每个 subject time 组合,收集等于该组合最大值的列名。这存储为highest_values

    然后,将组更改为subject。对于每个subject,检查time 是否是time 的最小值-如果是,则编码为0(如果您只想将第一行编码为0,而与时间值无关,则可以使用其他选项)。如果highest_values 没有任何列名,则编码为NA。如果highest_values与上一行有差异(变化),编码为1。否则,假定highest_values没有变化,编码为0。

    library(tidyverse)
    
    df1 %>%
      pivot_longer(cols = -c(subject, time)) %>%
      group_by(subject, time) %>%
      summarise(highest_values = toString(name[which(value == max(value))])) %>%
      group_by(subject) %>%
      mutate(newvar = case_when(
        time == min(time) ~ 0,
        highest_values == "" ~ NA_real_,
        highest_values != lag(highest_values) ~ 1,
        TRUE ~ 0
      )) %>%
      right_join(df1)
    

    输出

       subject  time highest_values newvar     A     B     C
         <dbl> <dbl> <chr>           <dbl> <dbl> <dbl> <dbl>
     1       1     1 "C"                 0     1     2     7
     2       1     2 "A"                 1     7     1     1
     3       1     3 "A"                 0     7     1     6
     4       1     4 "A"                 0     6     1     1
     5       1     5 "A, C"              1     6     1     6
     6       1     6 "A"                 1     5     1     1
     7       2     1 "B, C"              0     1     6     6
     8       2     2 "B"                 1     2     5     2
     9       2     3 "B, C"              1     3     4     4
    10       2     4 ""                 NA    NA    NA    NA
    11       2     5 ""                 NA    NA    NA    NA
    12       2     6 ""                 NA    NA    NA    NA
    

    编辑(2/11/21):根据下面的评论,有时有些行缺少数据。在这些情况下,newvar 应反映不包括这些行的最后或最近的“highest_values”。

    为此,filter 会剔除在group_by 之前没有“highest_values”值的那些行。然后,最新的“highest_values”将是没有丢失的值。此外,您无需将newvar 设置为NA - 这将在right_join 自动发生。

    这是修改后的代码:

    df1 %>%
      pivot_longer(cols = -c(subject, time)) %>%
      group_by(subject, time) %>%
      summarise(highest_values = toString(name[which(value == max(value))])) %>%
      filter(highest_values != "") %>%
      group_by(subject) %>%
      mutate(newvar = case_when(
        time == min(time) ~ 0,
        highest_values != lag(highest_values) ~ 1,
        TRUE ~ 0
      )) %>%
      right_join(df1) %>%
      arrange(subject, time)
    

    我添加了一行数据,用一个例子来演示。

    输出

       subject  time highest_values newvar     A     B     C
         <dbl> <dbl> <chr>           <dbl> <dbl> <dbl> <dbl>
     1       1     1 C                   0     1     2     7
     2       1     2 A                   1     7     1     1
     3       1     3 A                   0     7     1     6
     4       1     4 A                   0     6     1     1
     5       1     5 A, C                1     6     1     6
     6       1     6 A                   1     5     1     1
     7       2     1 B, C                0     1     6     6
     8       2     2 B                   1     2     5     2
     9       2     3 B, C                1     3     4     4
    10       2     4 NA                 NA    NA    NA    NA
    11       2     5 NA                 NA    NA    NA    NA
    12       2     6 B, C                0     2     3     3
    

    【讨论】:

    • 效果很好,谢谢!但是,将其调整为我的真实数据时,我遇到了另一个使事情变得更加复杂的编码问题:对于某些主题,在时间序列的中间存在缺失值的行,而不仅仅是在它的末尾。在这些情况下,最好不要将“highes_values”中的值与前一行中的值进行比较,而是与前一行中包含值的值进行比较。这有可能吗?
    • @jwin 查看已编辑的答案 - 这对您的描述有效吗?