【问题标题】:How can I create a new variable which identifies rows where another variable changes sign?如何创建一个新变量来标识另一个变量更改符号的行?
【发布时间】:2020-06-24 16:07:50
【问题描述】:

我有一个关于数据准备的问题。我有以下数据集(长格式;每个测量点一行,因此每人几行):

dd <- read.table(text=
"ID    time
1      -4
1      -3
1      -2
1      -1
1       0
1       1
2      -3
2      -1
2       2
2       3
2       4
3      -3
3      -2
3      -1
4      -1
4       1   
4       2
4       3
5       0
5       1
5       2
5       3
5       4", header=TRUE) 

现在我想创建一个新变量,该变量的行中为 1,其中此人的时间变量第一次发生符号更改,所有其他行中为 0。如果一个人在 time 上只有负值,则新变量上的 不应该是任何 1。对于在 time 上只有正值的人,第一行在新变量上应该有 1,所有其他行应该用 0 编码。对于我上面的示例,新数据框应该看起来像这个:

dd <- read.table(text=
"ID    time   new.var
1      -4     0
1      -3     0
1      -2     0
1      -1     0
1       0     1
1       1     0
2      -3     0
2      -1     0
2       2     1
2       3     0
2       4     0
3      -3     0  
3      -2     0
3      -1     0
4      -1     0
4       1     1  
4       2     0
4       3     0
5       0     1
5       1     0
5       2     0
5       3     0
5       4     0", header=TRUE) 

有人知道怎么做吗?我考虑过使用 dplyr 和 group_by,但是我对 R 很陌生并且没有成功。非常感谢任何帮助!

【问题讨论】:

标签: r group-by dplyr


【解决方案1】:

要创建new.var,您需要完成 2 种不同的操作,因此您需要分 2 步完成它们。为简单起见,我将把它分成 2 个单独的 mutate 调用,但您可以将它们都放入同一个 mutate

首先,我们按 ID 分组,然后找到符号发生变化的行。我们需要使用time &gt;= 0 而不是sign,正如此答案中所推荐的那样:R identifying a row prior to a change in sign 因为您希望仅在从 -1 0 开始而不是从 0 1:

library(tidyverse)
dd2 <- dd %>%
    group_by(ID) %>%
    mutate(new.var = as.numeric((time >= 0) != (lag(time) >= 0)))

dd2
# A tibble: 23 x 3
# Groups:   ID [5]
      ID  time new.var
   <int> <int>   <dbl>
 1     1    -4      NA
 2     1    -3       0
 3     1    -2       0
 4     1    -1       0
 5     1     0       1
 6     1     1       0
 7     2    -3      NA
 8     2    -1       0
 9     2     2       1
10     2     3       0
# … with 13 more rows

然后我们使用case_when 根据您想要的规则修改第一行。由于lag 的工作方式,第一行将始终具有NA(因为没有前一行可供查看),这使其成为根据time 选择第一行以更改它的好方法该组中的值:

dd3 <- dd2 %>%
    mutate(new.var = case_when(
               !is.na(new.var) ~ new.var,
               all(time >= 0) ~ 1,
               TRUE ~ 0)
    )

print(dd3, n = 100) #n=100 because tibbles are truncated to 10 rows by print

# A tibble: 23 x 3
# Groups:   ID [5]
      ID  time new.var
   <int> <int>   <dbl>
 1     1    -4       0
 2     1    -3       0
 3     1    -2       0
 4     1    -1       0
 5     1     0       1
 6     1     1       0
 7     2    -3       0
 8     2    -1       0
 9     2     2       1
10     2     3       0
11     2     4       0
12     3    -3       0
13     3    -2       0
14     3    -1       0
15     4    -1       0
16     4     1       1
17     4     2       0
18     4     3       0
19     5     0       1
20     5     1       0
21     5     2       0
22     5     3       0
23     5     4       0

【讨论】:

    【解决方案2】:

    你可以试试这个:

    library(dplyr)
    dd %>% left_join(dd %>% group_by(ID) %>% summarise(index=min(which(time>=0)))) %>%
      group_by(ID) %>% mutate(new.var=ifelse(row_number(ID)==index,1,0)) %>% select(-index)-> DF
    
    # A tibble: 23 x 3
    # Groups:   ID [5]
          ID  time new.var
       <int> <int>   <dbl>
     1     1    -4       0
     2     1    -3       0
     3     1    -2       0
     4     1    -1       0
     5     1     0       1
     6     1     1       0
     7     2    -3       0
     8     2    -1       0
     9     2     2       1
    10     2     3       0
    

    【讨论】:

    • 希望对您有所帮助!
    【解决方案3】:

    以下ave 指令执行问题要求的操作。

    dd$new.var <- with(dd, ave(time, ID, FUN = function(x){
      y <- integer(length(x))
      if(any(x >= 0)) y[which.max(x[1]*x <= 0)] <- 1L
      y
    }))
    
    dd
    #   ID time new.var
    #1   1   -4       0
    #2   1   -3       0
    #3   1   -2       0
    #4   1   -1       0
    #5   1    0       1
    #6   1    1       0
    #7   2   -3       0
    #8   2   -1       0
    #9   2    2       1
    #10  2    3       0
    #11  2    4       0
    #12  3   -3       0
    #13  3   -2       0
    #14  3   -1       0
    #15  4   -1       0
    #16  4    1       1
    #17  4    2       0
    #18  4    3       0
    #19  5    0       1
    #20  5    1       0
    #21  5    2       0
    #22  5    3       0
    #23  5    4       0
    

    如果预期的输出被重命名为dd2 那么

    identical(dd, dd2)
    #[1] TRUE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 2012-09-08
      • 2015-01-01
      • 1970-01-01
      • 2019-07-31
      相关资源
      最近更新 更多