(Легко?) Рассчитать изменение за несколько лет как -1, +1 или 0 в R - PullRequest
1 голос
/ 26 апреля 2020

Я хотел бы измерить для каждой рабочей задачи, является ли она (1) новой, (2) смещенной, (3) всегда присутствовала. Присутствие задачи в определенном году является двоичным (1 или 0). Вывод, который мне нужен, представляет собой простую меру расстояния и должен выглядеть так:

  • задача всегда присутствовала (0)
  • задача была удалена в любой момент времени (-1 )
  • задача добавлена ​​недавно (+1)
task_id <- c('X001','X002','X003', 'X004')
year2016 <- c(1, 1, 0, 1)
year2017 <- c(1, 0, 0, 1)
year2018 <- c(1, 0, 1, 1)
year2019 <- c(0, 0, 1, 1)
output <- c(-1, -1, 1, 0)

df <- data.frame(task_id, year2016, year2017, year2018, year2019, output)

Выходной столбец должен выглядеть следующим образом:

  task_id year2016 year2017 year2018 year2019 output
1    X001        1        1        1        0     -1
2    X002        1        0        0        0     -1
3    X003        0        0        1        1      1
4    X004        1        1        1        1      0

Любые предложения для меня, чтобы код это? Незначительное добавление: столбцы фактического года представлены в стандартном формате даты (если это может повлиять на решение). Спасибо большое !!

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

A dplyr решение с использованием case_when будет:

library(dplyr)
library(tidyr)

df %>% pivot_longer(cols = starts_with("year"),names_to = "year","value") %>%
  group_by(task_id) %>%
  mutate(output2 = case_when(last(value) == 0  ~ -1,
                            last(value) == 1 & sum(value == 0) != 0 ~ 1,
                            sum(value == 0) == 0 ~ 0)) %>%
  pivot_wider(names_from = year, values_from = value)

# A tibble: 4 x 7
# Groups:   task_id [4]
  task_id output output2 year2016 year2017 year2018 year2019
  <fct>    <dbl>   <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
1 X001        -1      -1        1        1        1        0
2 X002        -1      -1        1        0        0        0
3 X003         1       1        0        0        1        1
4 X004         0       0        1        1        1        1

РЕДАКТИРОВАТЬ: с более сложным примером

Просто чтобы завершить ответ с более сложным примером, описанным в очень хорошем ответе @AaronMontgomery, здесь решение, использующее dplyr и case_when:

library(dplyr)
library(tidyr)

df %>% pivot_longer(cols = starts_with("year"),names_to = "year","value") %>%
  group_by(task_id) %>%
  mutate(output2 = case_when(last(value) == 0 & length(unlist(rle(value)$length)) >2 ~ -2,
                             last(value) == 0 & length(unlist(rle(value)$length)) <= 2 ~ -1,
                             last(value) == 1 & sum(value == 0) != 0 ~ 1,
                             sum(value == 0) == 0 ~ 0)) %>%
  pivot_wider(names_from = year, values_from = value)

# A tibble: 5 x 6
# Groups:   task_id [5]
  task_id output2 year2016 year2017 year2018 year2019
  <fct>     <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
1 X001         -1        1        1        1        0
2 X002         -1        1        0        0        0
3 X003          1        0        0        1        1
4 X004          0        1        1        1        1
5 X005         -2        1        0        1        0
2 голосов
/ 26 апреля 2020

В очень простой версии мы игнорируем случаи, когда строки могут выглядеть как 1, 0, 1, 0 или 0, 0, 0, 0. В этом случае мы можем использовать:

df <- data.frame(task_id, year2016, year2017, year2018, year2019)
df$output <- 0  
df[df$year2016 == 0, ]$output <- 1  
df[df$year2019 == 0, ]$output <- -1

Лог c для третьей строки состоит в том, что те, которых нет в начале, должны быть добавлены в какой-то момент; затем мы проверяем те, которые присутствовали в начале, но не в конце, и помечаем их как удаленные.


Логика c для более сложного случая:

  • создает новый столбец (num_switches), который подсчитывает количество сальто в данной строке от 0 до 1 или наоборот - это то, что rle() делает
  • , автоматически помечая что-либо num_switches > 2 как output = -2
  • для случаев, когда num_switches <= 2, пометить как выше

Полный код с расширенным набором игрушечных данных ниже. Обратите внимание, что ссылка 2:5 в подмножестве df должна соответствовать столбцам года; более ответственная вещь здесь - вероятно, создать внешнюю переменную, которая будет отслеживать эти столбцы и ссылаться на них здесь (например, если вы добавите больше лет спустя).

task_id <- c('X001','X002','X003', 'X004', 'X005')
year2016 <- c(1, 1, 0, 1, 1)
year2017 <- c(1, 0, 0, 1, 0)
year2018 <- c(1, 0, 1, 1, 1)
year2019 <- c(0, 0, 1, 1, 0)
# output <- c(-1, -1, 1, 0)

df <- data.frame(task_id, year2016, year2017, year2018, year2019)
df$output <- 0
df$num_switches <- sapply(apply(df[,2:5], 1, function(x) rle(x)$lengths), length)
df[df$num_switches > 2, ]$output <- -2
df[df$year2016 == 0 & df$num_switches <= 2, ]$output <- 1
df[df$year2019 == 0 & df$num_switches <= 2, ]$output <- -1
...