Заменить значение на основе номера строки в r - PullRequest
4 голосов
/ 29 апреля 2020

У меня фрейм данных выглядит примерно так:

id <- c(1, 1, 1, 2, 2, 2, 3, 3, 3)
x <- c(1, 1, 0, 0, 1, 1, 1, 1, 1)
df <- data.frame(id, x)

Я хочу сохранить только первое значение = 1 для каждого идентификатора, в противном случае я хочу, чтобы оно = 0, и выглядело так:

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

Я пробовал этот код, но безуспешно:

df %>% 
  group_by(id) %>%
  mutate(x = if (any(x == 1)) replace(x,
                                      row_number() != 1, 0) else x)
```

Ответы [ 5 ]

3 голосов
/ 29 апреля 2020

В base вы можете использовать ave для группировки по id и использовать ifelse с cumsum для замены после первого 1 на 0.

df$x <- ave(df$x, df$id, FUN=function(x) ifelse(cumsum(x)>1,0,x))
#df$x <- ifelse(ave(df$x, df$id, FUN=cumsum)>1, 0, df$x) #Alternativ
#df$x <- with(df, ifelse(ave(x, id, FUN=cumsum)>1, 0, x)) #Alternativ
df
#  id x
#1  1 1
#2  1 0
#3  1 0
#4  2 0
#5  2 1
#6  2 0
#7  3 1
#8  3 0
#9  3 0
2 голосов
/ 29 апреля 2020

Если x является двоичным, вы можете сделать:

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(x = +(which.max(x) == row_number()))

# A tibble: 9 x 2
# Groups:   id [3]
     id     x
  <dbl> <int>
1     1     1
2     1     0
3     1     0
4     2     0
5     2     1
6     2     0
7     3     1
8     3     0
9     3     0

Если есть группы x, которые не содержат 1, вам понадобится дополнительное условие:

df %>%
  group_by(id) %>%
  mutate(x = +(x == 1 & which.max(x) == row_number()))
2 голосов
/ 29 апреля 2020

Используя replace вы можете сделать:

library(dplyr)
df %>% group_by(id) %>% mutate(y = replace(x, -match(1L, x), 0L))
#OR
#mutate(y = replace(x, which.max(x), 0L))

#     id     x     y
#  <dbl> <dbl> <dbl>
#1     1     1     1
#2     1     1     0
#3     1     0     0
#4     2     0     0
#5     2     1     1
#6     2     1     0
#7     3     1     1
#8     3     1     0
#9     3     1     0
1 голос
/ 29 апреля 2020

Опция, использующая data.table:

library(data.table)
setDT(df)[, x := replace(rep(0L, .N), match(1L, x), 1L), id]
0 голосов
/ 29 апреля 2020

Одно dplyr решение может быть:

df %>%
 group_by(id) %>%
 mutate(x = +(x == 1 & !duplicated(x)))

     id     x
  <dbl> <int>
1     1     1
2     1     0
3     1     0
4     2     0
5     2     1
6     2     0
7     3     1
8     3     0
9     3     0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...