计算每个唯一变量的更改次数?

时间:2018-11-04 16:30:42

标签: r dplyr mutate

我有一个长数据框,其中包含多个主题(id),试验编号和回复。我想知道每个主题的回复变化了多少次。可能的响应是1和0。 因此,对于同一主题的每一行,新的“更改”列应具有相同的编号。

现在,我能够获得整个数据帧在响应中的更改数量,而不是特定于每个主题(id)。

我如何获得此号码,以便特定于ID?我以为group_by()会这样做,但是不会。

HNPS_df2的标头:id Trial_Num响应 每个试用版的每个ID都有一行

HNPS_df2 <- HNPS_df2 %>% group_by(id) %>% mutate(change = cumsum(ifelse(Response != lag(Response) | is.na(lag(Response)), 1, 0)))

有什么想法吗? 对于这个问题,我是陌生的,如果再重复一遍,详细的解释将非常棒,对不起!

编辑 我没有得到一个错误,我只是没有得到我想要的哈。 这是我的数据框的简化版本

df <- data_frame(
        id = c(500, 500, 500, 501, 501, 501, 502, 502, 502), 
        trial_num = c(1, 2, 3, 1, 2, 3, 1, 2, 3), 
        Response = c(0, 0, 0, 1, 0, 0, 1, 1, 0))

我希望它看起来像是添加一列具有更改次数的列

change <- data_frame(change = c(0, 0, 0, 1, 1, 1, 1, 1, 1))

但是当我使用此代码时:

df <- df %>% 
         group_by(id) %>% 
         mutate(changeD = cumsum(ifelse(Response!= lag(Response) | is.na(lag(Response)), 1, 0)))

计数器不会在每个新的ID号上“重新启动”

2 个答案:

答案 0 :(得分:1)

首先,我创建一个临时变量R2,用一个我知道NA不需要的值替换Response中的Response。然后,由于R2没有NA的值,所以我只看diff(R2)。如果diff不是0,说明存在更改,因此sum(diff(R2) != 0)等于更改次数。

library(dplyr)

df <- data_frame(
        id = c(500, 500, 500, 501, 501, 501, 502, 502, 502), 
        trial_num = c(1, 2, 3, 1, 2, 3, 1, 2, 3), 
        Response = c(0, 0, 0, 1, 0, 0, 1, 1, 0))


df %>% 
  mutate(R2 = replace(Response, is.na(Response), max(Response, na.rm = T) + 1)) %>% 
  group_by(id) %>% 
  mutate(change = sum(diff(R2) != 0)) %>% 
  select(-R2)
# # A tibble: 9 x 4
# # Groups:   id [3]
#      id trial_num Response change
#   <dbl>     <dbl>    <dbl>  <int>
# 1   500         1        0      0
# 2   500         2        0      0
# 3   500         3        0      0
# 4   501         1        1      1
# 5   501         2        0      1
# 6   501         3        0      1
# 7   502         1        1      1
# 8   502         2        1      1
# 9   502         3        0      1

diff函数计算每个元素与下一个元素之间的差。例如

diff(c(1, 2, 4, 5, 10))
# [1] 1 2 1 5

基本R版本

df$change <- 
  with(df, rep(tapply({r <- Response
                      replace(r, is.na(r), max(r, na.rm = T) + 1)}
                      , id
                      , function(x) sum(diff(x) != 0))
              , lengths(split(id, id))))

答案 1 :(得分:1)

如果您有兴趣,可以直接使用data.table

library(data.table)

setDT(df)[, Change := max(rleid(Response) - 1), by = id][, .(Change)]

   Change
1:      0
2:      0
3:      0
4:      1
5:      1
6:      1
7:      1
8:      1
9:      1

您也可以将其合并到dplyr中:

library(data.table)
library(dplyr)

df %>% group_by(id) %>% 
   mutate(Change = max(rleid(Response) - 1)) %>% 
   ungroup() %>% select(Change)

  Change
   <dbl>
1      0
2      0
3      0
4      1
5      1
6      1
7      1
8      1
9      1

如果没有data.table,类似的事情也将起作用:

library(dplyr)

df %>% group_by(id) %>% mutate(Change = Response != lag(Response),
                               Change = ifelse(is.na(Change), FALSE, Change),
                               Change = max(cumsum(Change))) %>% ungroup() %>% select(Change)

  Change
   <int>
1      0
2      0
3      0
4      1
5      1
6      1
7      1
8      1
9      1