在不循环的情况下复制数据框中具有条件的行

Duplicate rows with conditions in dataframe without looping

我正在处理一个大型数据集(超过 100 万行),例如两列日期和延迟编号。

   ID    col1    Date         Delay
1:  A     100    2021-05-01    1
2:  B     200    2018-04-03    3
3:  C     300    2020-02-17    2

我想根据延迟量复制 table 中的行,同时增加新列中每一行的日期:

   ID    col1    Date         Delay   New_Date
1:  A     100    2021-05-01    1      2021-05-02
2:  B     200    2018-04-03    3      2018-04-04
3:  B     200    2018-04-03    3      2018-04-05
4:  B     200    2018-04-03    3      2018-04-06
5:  C     300    2020-02-17    2      2020-02-18
6:  C     300    2020-02-17    2      2020-02-19

我目前正在使用 for each 循环来做这件事,这非常低效并且需要很多时间。

for(row in 1:nrow(df)) {
  delay <- as.numeric(df[row, "Delay"])
  tempdf <- df[0,]
    
  for(numberDelay in 1:delay) {
    tempdf[numberDelay, ] <- df[row, ]
    tempdf[numberDelay, "New_Date"] <- as.Date.character(tempdf[numberDelay, "Date"] + as.numeric(numberDelay), 
    tryFormats = "%Y-%m-%d")
  }
  result <- rbind(result, tempdf)
}

上下文:这将允许我通过进一步比较新日期与黑名单日期列表来确定周末或国定假日的延误。 在 R 中有没有一种有效的方法来做到这一点?

浣熊

您可以尝试 dplyrtidyr:

library(dplyr)
library(tidyr)

df %>% 
  rowwise() %>% 
  mutate(New_Date = list(seq.Date(Date + 1, Date + Delay, by = "day"))) %>% 
  unnest(New_Date)
#> # A tibble: 6 x 5
#>   ID     col1 Date       Delay New_Date  
#>   <chr> <int> <date>     <int> <date>    
#> 1 A       100 2021-05-01     1 2021-05-02
#> 2 B       200 2018-04-03     3 2018-04-04
#> 3 B       200 2018-04-03     3 2018-04-05
#> 4 B       200 2018-04-03     3 2018-04-06
#> 5 C       300 2020-02-17     2 2020-02-18
#> 6 C       300 2020-02-17     2 2020-02-19

但是,考虑到你解释的上下文,我认为这样的事情对你来说可能更有效:

# example of vector of blacklisted days
blacklist_days <- as.Date(c("2020-02-18", "2018-04-04", "2018-04-05"))
df %>% 
  rowwise() %>% 
  mutate(Dates = list(seq.Date(Date + 1, Date + Delay, by = "day"))) %>% 
  mutate(n_bl = sum(Dates %in% blacklist_days)) %>% 
  ungroup()
#> # A tibble: 3 x 6
#>   ID     col1 Date       Delay Dates       n_bl
#>   <chr> <int> <date>     <int> <list>     <int>
#> 1 A       100 2021-05-01     1 <date [1]>     0
#> 2 B       200 2018-04-03     3 <date [3]>     2
#> 3 C       300 2020-02-17     2 <date [2]>     1

通过这种方式,您可以避免行重复,这可能会影响您的性能。

您可以单独创建副本的数据框,然后将它们与原始数据框合并。这使用循环遍历 Delay.

的不同值
> dat <- data.frame(ID = LETTERS[1:3], col1 = 1:3 * 100,
+                   date = as.Date(c('2021-05-01', '2018-04-03', '2020-02-17')),

+                   delay = c(1, 3, 2))
> dat
  ID col1       date delay
1  A  100 2021-05-01     1
2  B  200 2018-04-03     3
3  C  300 2020-02-17     2
> dat$sk <- 1:nrow(dat)
> ddup <- data.frame()
> for (i in 2:3) {
+
  dd <- dat[dat$delay >= i, ]
+   dd <- dat[dat$delay >= i, ]
+   dd$date <- dd$date + 1

+   ddup <- rbind(ddup, dd)
}
+
+ }
> dat <- rbind(dat, ddup)
> dat <- dat[order(dat$sk, dat$date), ]
> dat
   ID col1       date delay sk
1   A  100 2021-05-01     1  1
2   B  200 2018-04-03     3  2
22  B  200 2018-04-04     3  2
21  B  200 2018-04-04     3  2
3   C  300 2020-02-17     2  3
31  C  300 2020-02-18     2  3
>