(容易吗?)在R中把多年的变化计算为-1、+1或0。

问题描述 投票:0回答:1

我想衡量每项工作任务是否是(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

有什么建议可以让我写出来吗?小的补充:实际的年份列是标准的日期格式(如果这可能会影响解决方案)。

r dataframe binary distance
1个回答
2
投票

非常简单的版本是,我们可以忽略一些情况,其中行可以看起来像 1, 0, 1, 00, 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

2
投票

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的非常好的答案中描述了一个更详细的例子,这里有一个使用了 dplyrcase_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
© www.soinside.com 2019 - 2024. All rights reserved.