如何创建一个新变量来标识其他变量更改符号的行?

时间:2020-06-24 16:07:50

标签: r group-by dplyr

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

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。如果一个人在时间上只有负值,那么在新变量上的不应为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还是很陌生,没有成功。任何帮助深表感谢!

3 个答案:

答案 0 :(得分:0)

您可以尝试以下方法:

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

答案 1 :(得分:0)

要创建new.var有2种不同的操作,因此需要分2个步骤进行。为了简单起见,我将其分为两个单独的mutate调用,但您可以将它们都放在同一个mutate

首先,我们按ID分组,然后找到符号更改的行。我们需要使用time >= 0而不是此答案R identifying a row prior to a change in sign中推荐的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 :(得分:0)

以下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