#r #vector #dplyr
#r #вектор #dplyr
Вопрос:
Учитывая фрейм данных:
df <- structure(
list(
record_id = c(1,1,1,1,1,1,1,1,1,1),
day_count = c(1,2,3,4,5,6,7,8,9,10),
change = c(0,2,0,1,0,2,0,1,2,0)),
row.names = c(NA, -10L),
class = c("tbl_df", "tbl", "data.frame"))
с:
change (0)
= без изменений, change (1)
= начать / возобновить и change(2)
= остановить.
Я хочу создать новый столбец, который оценивает, была ли остановка последней остановкой (т. Е. Происходит ли изменение (1) в последовательности, следующей за остановкой)
Ожидаемый результат
df_output <- structure(
list(
record_id = c(1,1,1,1,1,1,1,1,1,1),
day_count = c(1,2,3,4,5,6,7,8,9,10),
change = c(0,2,0,1,0,2,0,1,2,0),
last_stop = c(0,0,0,0,0,0,0,0,1,0)),
row.names = c(NA, -10L),
class = c("tbl_df", "tbl", "data.frame"))
Я считаю, что мне нужно вырезать последующие наблюдения после остановки и создать из них вектор. Затем оцените, произошло ли (1) в векторе. Если да, то это была не последняя остановка, если нет, то это была последняя остановка.
Проблема в том, что я не знаю, как делать это повторно для каждых 2, которые происходят….
Надеюсь, вы сможете помочь
BW
Комментарии:
1. В вашем ожидаемом выводе отсутствует ваша выходная переменная.
2. спасибо, исправлено
Ответ №1:
Решение с базой R. Это работает для каждого record_id
, поскольку я полагаю, что это ваша цель.
Я расширил ваши данные, чтобы иметь:
record_id == 1
это заканчивается1
,record_id == 2
это заканчивается2
,record_id == 3
который состоит только из нулей.
df <- structure(
list(
record_id = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3),
day_count = c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5),
change = c(0,2,0,1,0,2,0,1,2,0,0,0,0,0,0)),
row.names = c(NA, -15L),
class = c("tbl_df", "tbl", "data.frame"))
Вот решение:
df$last_stop <- ave(df$change,
df$record_id,
FUN = function(x){
l <- numeric(length(x))
i <- Position(function(x) x!=0, x, right = TRUE)
if(identical(x[i], 2)) l[i] <- 1
l
})
df
#> record_id day_count change last_stop
#> 1 1 1 0 0
#> 2 1 2 2 0
#> 3 1 3 0 0
#> 4 1 4 1 0
#> 5 1 5 0 0
#> 6 2 1 2 0
#> 7 2 2 0 0
#> 8 2 3 1 0
#> 9 2 4 2 1
#> 10 2 5 0 0
#> 11 3 1 0 0
#> 12 3 2 0 0
#> 13 3 3 0 0
#> 14 3 4 0 0
#> 15 3 5 0 0
Обратите внимание, что у вас есть 1 last_stop
только для record_id == 2
строки 9.
ave
это интересная функция, которая разбивается df$change
на df$record_id
и применяет функцию к каждому компоненту.
Функция:
- создает вектор нулей (который будет вашим
df$last_stop
) - ищет
Position
первое ненулевое значение справа (или снизу) - если это значение равно 2, то оно добавляет 1 в выходной вектор, в противном случае возвращается вектор нулей.
Комментарии:
1. Дорогой Эдо. Спасибо за ваше предложение. Действительно, я хочу, чтобы это работало для нескольких идентификаторов record_id. Однако, как предположил Оньямбу ниже, это не сработает, если 1 произошло после 2, без последующего 2. Есть какие-нибудь предложения? Заранее спасибо
Ответ №2:
Я считаю, что следующий код должен работать.
df$last_stop = sapply(
1:length(df$change),
function(i){
ifelse(df$change[i] != 2, 0,
as.numeric(!any(df$change[i:length(df$change)] == 1)))
})
Функция sapply вызывает у вас вектор изменения df $, выводит 0, если изменение отличается от 2, в противном случае проверяет, есть ли какое-либо значение 1 в оставшихся элементах, если его нет, условие возвращает TRUE, которое затем преобразуется в числовое значение, поскольку as.numeric(TRUE) == 1.
Комментарии:
1. Спасибо, Wawv. Это действительно хорошо работает в примере, который я предоставил. Как предложил edo ниже, я хочу, чтобы этот код работал для каждого record_id . Изображение record_id номер 2, с точными теми же номерами, что и номер 1. Я попробовал следующее в dataframe с record_id 1 и 2, что не работает:
df2 <- df2 %>% group_by(record_id) %>% mutate(last_stop = sapply( 1:length(df2$change), function(i){ ifelse(df2$change[i] != 2, 0, as.numeric(!any(df2$change[i:length(df2$change)] == 1))) } ))
есть предложения?2. Это должно сработать, если вы удалите «df2 $» из функции, чтобы она ссылалась только на изменение переменной внутри группы (а не внутри data.frame).
Ответ №3:
Большинство предоставленных кодов не учитывают, что у вас может быть 1 после 2, не имея 2 впоследствии. Чтобы принять это во внимание, мы могли бы сделать:
a <- max(which(df$change==2))
b <- max(which(df$change==1))
df$change <- numeric(nrow(df))
df$change [if(a>b) a else 0] <- 1
df
Комментарии:
1. Привет, Оньямбу, спасибо за вашу помощь. Это действительно хорошо работает для примера, который я предоставил. Как я забыл упомянуть, у меня есть несколько record_id. Каким будет ваше предложение? BW и заранее спасибо