我想衡量每项工作任务是否是(1)新的,(2)被取代的,(3)一直存在的。一个任务是否在某一年存在是二进制的(1或0)。我需要的输出是一个简单的距离测量,必须是这样的。
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
有什么建议可以让我写出来吗?小的补充:实际的年份列是标准的日期格式(如果这可能会影响解决方案)。
非常简单的版本是,我们可以忽略一些情况,其中行可以看起来像 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
第三行的逻辑是,那些在开始时不存在的内容一定是在某个时候被添加的;然后我们检查那些在开始时存在但没有在结束时存在的内容,并将其标记为已被删除。
更复杂的情况的逻辑是
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
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
EDIT: With more elaborated example
为了完成这个答案,在@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