簡體   English   中英

按組刪除過去的觀察到最接近給定日期的觀察

[英]Remove past observations up to nearest observation to given date by group

雖然我已經實現了我想要的(見下面的結果),但我發現我的方法有點復雜。 我想按組刪除所有觀察結果,直到截止日期(此處為cut-off日期)之前最近的觀察結果。 我不能簡單地使用min(abs(x - date))計算最近的觀察值,因為在正面和負面中可能存在距離相等的觀察關系(例如mydf中的“b”組)。

我通過查找date - cut_off <=0的最后一次觀察的索引,然后在dplyr::slice()中使用該索引來解決它。 不過,我對其他方法很好奇。

對於非 dplyr 解決方案非常開放。

每組至少包含一行observation date - cutoff date <= 0

library(tidyverse)

set.seed(8)

mydf <- data.frame(group = rep(letters[1:3], each = 5), date1 = as.Date(sample(15), origin = '1970-01-01'), cut_off = as.Date(rep(sample(10, 3), each = 5), origin = '1970-01-01'))

mydf %>% arrange(group, date1) %>% group_by(group) %>%
  mutate(diff = date1 - cut_off, 
         min_abs = min(abs(date1 - cut_off)))

#> # A tibble: 15 x 5
#> # Groups:   group [3]
#>    group date1      cut_off    diff    min_abs
#>    <fct> <date>     <date>     <drtn>  <drtn> 
#>  1 a     1970-01-03 1970-01-05 -2 days 0 days 
#>  2 a     1970-01-05 1970-01-05  0 days 0 days 
#>  3 a     1970-01-08 1970-01-05  3 days 0 days 
#>  4 a     1970-01-13 1970-01-05  8 days 0 days 
#>  5 a     1970-01-15 1970-01-05 10 days 0 days 
#>  6 b     1970-01-02 1970-01-09 -7 days 2 days 
#>  7 b     1970-01-06 1970-01-09 -3 days 2 days 
#>  8 b     1970-01-07 1970-01-09 -2 days 2 days 
#>  9 b     1970-01-11 1970-01-09  2 days 2 days 
#> 10 b     1970-01-12 1970-01-09  3 days 2 days 
#> 11 c     1970-01-04 1970-01-11 -7 days 1 days 
#> 12 c     1970-01-09 1970-01-11 -2 days 1 days 
#> 13 c     1970-01-10 1970-01-11 -1 days 1 days 
#> 14 c     1970-01-14 1970-01-11  3 days 1 days 
#> 15 c     1970-01-16 1970-01-11  5 days 1 days

# min(abs(x)) does not help when the distance from neg and pos values is tied, see group b

期望的結果(解決方案已經很好了)

mydf %>% 
  arrange(group, date1) %>% 
  group_by(group) %>% 
  mutate(diff = date1 - cut_off) %>% 
  slice(max(which(diff <= 0)):n()) 
# finds index of last element in "diff" which fullfills condition 

#> # A tibble: 10 x 4
#> # Groups:   group [3]
#>    group date1      cut_off    diff   
#>    <fct> <date>     <date>     <drtn> 
#>  1 a     1970-01-05 1970-01-05  0 days
#>  2 a     1970-01-08 1970-01-05  3 days
#>  3 a     1970-01-13 1970-01-05  8 days
#>  4 a     1970-01-15 1970-01-05 10 days
#>  5 b     1970-01-07 1970-01-09 -2 days
#>  6 b     1970-01-11 1970-01-09  2 days
#>  7 b     1970-01-12 1970-01-09  3 days
#>  8 c     1970-01-10 1970-01-11 -1 days
#>  9 c     1970-01-14 1970-01-11  3 days
#> 10 c     1970-01-16 1970-01-11  5 days

代表 package (v0.3.0) 於 2019 年 12 月 16 日創建

您可以檢測日期高於閾值的行,然后在它們上使用鉛以保持另一個值:

library(dplyr)
mydf %>%
  arrange(group,date1) %>%
  group_by(group) %>%
  filter(lead(date1 > cut_off, default = TRUE)) %>%
  ungroup()
#> # A tibble: 10 x 3
#>    group date1      cut_off   
#>    <fct> <date>     <date>    
#>  1 a     1970-01-05 1970-01-05
#>  2 a     1970-01-08 1970-01-05
#>  3 a     1970-01-13 1970-01-05
#>  4 a     1970-01-15 1970-01-05
#>  5 b     1970-01-07 1970-01-09
#>  6 b     1970-01-11 1970-01-09
#>  7 b     1970-01-12 1970-01-09
#>  8 c     1970-01-10 1970-01-11
#>  9 c     1970-01-14 1970-01-11
#> 10 c     1970-01-16 1970-01-11

以下是dplyr的幾種方法:

我們可以使用top_n到 select 每個組的前 n 個日期,其中根據大於cut_off的值的數量為每個組計算不同的n

library(dplyr)
mydf %>% group_by(group) %>% top_n(sum(date1 > cut_off) + 1, date1) 

#   group date1      cut_off   
#   <fct> <date>     <date>    
# 1 a     1970-01-05 1970-01-05
# 2 a     1970-01-08 1970-01-05
# 3 a     1970-01-13 1970-01-05
# 4 a     1970-01-15 1970-01-05
# 5 b     1970-01-11 1970-01-09
# 6 b     1970-01-12 1970-01-09
# 7 b     1970-01-07 1970-01-09
# 8 c     1970-01-14 1970-01-11
# 9 c     1970-01-16 1970-01-11
#10 c     1970-01-10 1970-01-11

盡管這會正確選擇行,但請注意top_n不會對數據進行排序,因此您可能希望在鏈的末尾添加arrange(group, date1)


另一種方法類似於在 OP 中使用slice發布的方法

mydf %>% 
  arrange(group, date1) %>%
  group_by(group) %>% 
  slice((which.max(date1 > cut_off) - 1):n())

#  group date1      cut_off   
#  <fct> <date>     <date>    
# 1 a     1970-01-05 1970-01-05
# 2 a     1970-01-08 1970-01-05
# 3 a     1970-01-13 1970-01-05
# 4 a     1970-01-15 1970-01-05
# 5 b     1970-01-07 1970-01-09
# 6 b     1970-01-11 1970-01-09
# 7 b     1970-01-12 1970-01-09
# 8 c     1970-01-10 1970-01-11
# 9 c     1970-01-14 1970-01-11
#10 c     1970-01-16 1970-01-11 

我們也可以調整它以在filter中使用。

mydf %>% 
  arrange(group, date1) %>%
  group_by(group) %>% 
  filter(row_number() >= which.max(date1 > cut_off) - 1)

可以在基礎 R 中翻譯為:

new_df <- mydf[with(mydf, order(group, date1)), ]
subset(new_df, ave(date1 > cut_off, group, FUN = function(x) 
                seq_along(x) >= (which.max(x) - 1)))

我想按組刪除所有觀察到給定日期最近的觀察。 我不能簡單地使用 min(abs(x - date)) 計算最近的觀察值,因為在正面和負面中可能存在距離相等的觀察關系(例如,mydf 中的“b”組)。

你的標准是固定的,你需要有意識地選擇一種打破關系的方式——你可以選擇先出現的條目:(或最后一個,檢查?top_n)

mydf %>% 
  mutate(diff =  abs(date1- cut_off)) %>% 
  arrange(group, diff) %>% 
  group_by(group) %>%
  top_n(n = 1, wt = -diff )

# A tibble: 3 x 4
# Groups:   group [3]
  group date1      cut_off    diff  
  <fct> <date>     <date>     <drtn>
1 a     1970-01-12 1970-01-11 1 days
2 b     1970-01-07 1970-01-02 5 days
3 c     1970-01-03 1970-01-04 1 days

*出於某種原因,即使在使用您的種子時,我也得到了不同的值 (8)

如果您只需要過濾 diff <= 0 的情況,只需將其添加到 pipe 鏈中。

排序和差異是明智之舉。 因此,對於最后一部分,由於您的日期已經排序,因此對於每個組,您使用 which.min 來調出最近的行,並保留 >= 此值的行:

mydf %>% 
arrange(group, date1) %>% 
group_by(group) %>%
mutate(delta = abs(date1- cut_off)) %>%
filter(1:n() >= max(which(delta == max(delta[delta<=0]))))

# A tibble: 10 x 4
# Groups:   group [3]
   group date1      cut_off    delta  
   <fct> <date>     <date>     <drtn> 
 1 a     1970-01-05 1970-01-05  0 days
 2 a     1970-01-08 1970-01-05  3 days
 3 a     1970-01-13 1970-01-05  8 days
 4 a     1970-01-15 1970-01-05 10 days
 5 b     1970-01-07 1970-01-09  2 days
 6 b     1970-01-11 1970-01-09  2 days
 7 b     1970-01-12 1970-01-09  3 days
 8 c     1970-01-10 1970-01-11  1 days
 9 c     1970-01-14 1970-01-11  3 days
10 c     1970-01-16 1970-01-11  5 days

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM