拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 根据过去48小时内发生的情况更改值?

根据过去48小时内发生的情况更改值?

白鹭 - 2022-02-22 1948 0 0

我有一个资料集,我需要将任何值为 0 但在过去 48 小时内具有非零值的值更改为特定字符串。我猜我可能需要在执行此操作之前将除第一列之外的所有列从 dbl 转换为 chr?

   Time                 colA             colB             colC  colD
   <dttm>              <dbl>            <dbl>            <dbl> <dbl>
 1 2021-11-21 10:00:00     8                0                9   176
 2 2021-11-11 11:00:00    21                0               22   416
 3 2021-11-21 11:00:00    19                0               20   373
 4 2021-11-11 12:00:00    40               13               28   566
 5 2021-11-21 12:00:00    26                0               27   527
 6 2021-11-11 13:00:00    50               20               32   651
 7 2021-11-11 10:00:00    11                0               12   216
 8 2021-11-21 13:00:00    30                0               31   617
 9 2021-11-11 14:00:00    51                0               32   675
10 2021-11-21 14:00:00    31                0               32   644

很抱歉资料尚未按时间排序,正在努力解决这个问题。例如,这里的输出,我会喜欢去:

   Time                 colA             colB             colC  colD
   <dttm>              <dbl>            <dbl>            <dbl> <dbl>
 1 2021-11-21 10:00:00     8                0                9   176
 2 2021-11-11 11:00:00    21                0               22   416
 3 2021-11-21 11:00:00    19                0               20   373
 4 2021-11-11 12:00:00    40               13               28   566
 5 2021-11-21 12:00:00    26                0               27   527
 6 2021-11-11 13:00:00    50               20               32   651
 7 2021-11-11 10:00:00    11                0               12   216
 8 2021-11-21 13:00:00    30                0               31   617
 9 2021-11-11 14:00:00    51          STRING1               32   675
10 2021-11-21 14:00:00    31                0               32   644

由于 colB 在 2021-11-11 14:00:00 的值为 0,但在此之前的 48 小时内至少有 1 个先前值!= 0,因此它会更改为“STRING1”

抱歉,如果这令人困惑,我正在尝试自动化我通常在 Excel 中手动执行的操作。提前致谢

uj5u.com热心网友回复:

这是一个tidyverse解决方案。我将首先创建一些示例资料(请注意,我确实将其他列设定为字符):

data = tribble(
  ~ time, ~ colA, ~ colB,
  "2021-11-21 12:00:00", 1, 0,
  "2021-11-22 00:00:00", 0, 1,
  "2021-11-24 12:00:00", 0, 0,
  "2021-11-25 12:00:00", 1, 1,
  "2021-11-26 12:00:00", 0, 0,
) %>%
  mutate(
    time = ymd_hms(time), 
    across(-time, as.character)
  )

# A tibble: 5 x 3
  time                colA  colB 
  <dttm>              <chr> <chr>
1 2021-11-21 12:00:00 1     0    
2 2021-11-22 00:00:00 0     1    
3 2021-11-24 12:00:00 0     0    
4 2021-11-25 12:00:00 1     1    
5 2021-11-26 12:00:00 0     0    

这个问题的挑战在于,每次我们都需要知道要查找哪些其他行来确定每列的新值。要做到这一点,我将使用purrr:pmap().data可用的物件dplyr我将首先演示如何“回顾”过去 48 小时内的行:

data %>%
  mutate(
    across(
      .cols = -time, 
      function(col) {
        pmap_chr(list(time), function(t) {
          eligible = .data$time >= t - hours(48) & .data$time < t
          paste(col[eligible], collapse = ",")
        })
      },
      .names = "{.col}_previous"
    )
  )

输出:

# A tibble: 5 x 5
  time                colA  colB  colA_previous colB_previous
  <dttm>              <chr> <chr> <chr>         <chr>        
1 2021-11-21 12:00:00 1     0     ""            ""           
2 2021-11-22 00:00:00 0     1     "1"           "0"          
3 2021-11-24 12:00:00 0     0     ""            ""           
4 2021-11-25 12:00:00 1     1     "0"           "0"          
5 2021-11-26 12:00:00 0     0     "0,1"         "0,1"    

如您所见,这看起来很有希望。我们已准备好以此为核心思想来开发解决方案。

data %>%
  mutate(
    across(
      .cols = -time, 
      function(col) {
        modify_ind = pmap_lgl(list(time), function(t) {
          eligible = .data$time >= t - hours(48) & .data$time < t
          any(col[eligible] != "0")
        })
        ifelse(modify_ind & col == "0", "STRING1", col)
      }
    )
  )

输出:

# A tibble: 5 x 3
  time                colA    colB   
  <dttm>              <chr>   <chr>  
1 2021-11-21 12:00:00 1       0      
2 2021-11-22 00:00:00 STRING1 1      
3 2021-11-24 12:00:00 0       0      
4 2021-11-25 12:00:00 1       1      
5 2021-11-26 12:00:00 STRING1 STRING1

一些注意事项:

  • 在我的解决方案中,我创建了一个modify_ind建立在前面所示想法的基础上:访问在过去 48 小时内按时间过滤的列,然后检查是否有任何非零值。然后我修改列,只要它modify_indTRUE与列的值"0"
  • 如果您想创建新列而不是完全替换原始列,请添加一个.names自变量 toacross()如前所示。
  • 如果您只想修改资料集中的几列,而不是使用across(.cols = -time),请使用类似across(.cols = c("colA", "colB")).
标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *