【问题标题】:Find the first incidence (row) of a value that is x amount greater/less than the current value (iterated through each row in a data frame)查找大于/小于当前值 x 数量的值的第一个关联(行)(遍历数据帧中的每一行)
【发布时间】:2021-11-22 23:03:01
【问题描述】:

我一直在努力,但还没有达到目标。 我正在尝试遍历向量 (df$sample) 中的值,并找到比当前值小 20% 的值的第一个处理发生率。我正在尝试为每一行(样本)找到这个并将找到的值的日期打印到一个新列。

这是我的 df:

    date       sample
591 2020-02-14 0.008470
590 2020-02-15 0.008460
589 2020-02-16 0.007681
588 2020-02-17 0.007144
587 2020-02-18 0.007262
586 2020-02-19 0.007300
585 2020-02-20 0.006604
584 2020-02-21 0.006843
583 2020-02-22 0.006687
582 2020-02-23 0.006991
581 2020-02-24 0.007333
580 2020-02-25 0.006738
579 2020-02-26 0.006279
...

我的尝试是使用 Position() 或 which()。我想也许我可以将它们中的任何一个包装在一个 for 循环中,但我的尝试并不完全正确。

for(i in length(df){

df$conc20 <- Position(function(x) x < df$sample[i]*0.80, df$sample)
}

for(i in length(df){

df$conc20 <- min(which(df$sample < df$sample[i]*0.8)

}

我什至找到了一个与我正在寻找的内容接近的dply example

理想情况下:

    date       sample   conc20
591 2020-02-14 0.008470 2020-02-25
590 2020-02-15 0.008460 ...
589 2020-02-16 0.007681
588 2020-02-17 0.007144
587 2020-02-18 0.007262
...

我很乐意提供任何澄清。 非常感谢您的帮助!

【问题讨论】:

  • 你能把数据框分享给dput()吗?这会让事情变得更容易。

标签: r


【解决方案1】:

编辑的答案

df<- read.csv( sep = " ",  text=
                 "row date sample
591 2020-02-14 0.008470
590 2020-02-15 0.008460
589 2020-02-16 0.007681
588 2020-02-17 0.007144
587 2020-02-18 0.007262
586 2020-02-19 0.007300
585 2020-02-20 0.006604
584 2020-02-21 0.006843
583 2020-02-22 0.006687
582 2020-02-23 0.006991
581 2020-02-24 0.007333
580 2020-02-25 0.006738
579 2020-02-26 0.006279",                    
)
df$date=as.Date(as.character(df$date))
df   

#there is no row 20% below, so I am just using 2% below 
# and multiplying 0.98 instead of 0.8

# Finding cross-over before current row    
f_crossover_before<- function(  i  ){
  cutoff= 0.98* df$sample[i]
  res<- max(which( df$sample[1:i]<= cutoff), -1)
  ifelse ( (res>0) , res , NA )  # sapply cannot return dates !
}

# Finding cross-over after  current row   
f_crossover_after<- function(  i  ){
  cutoff<- 0.98* df$sample[i]
  res<- min( i+which( df$sample[(i+1):nrow(df)]<= cutoff), 
        .Machine$integer.max )
  ifelse ( (res<.Machine$integer.max) , res , NA )
}



# A column for  comparison. Only for visual inspection 
df$cutoff<- df$sample*0.98 


df$crossover_before<- sapply( seq_along(df$sample) ,  FUN = f_crossover_before )
df$crossover_before<- df$date[df$crossover_before]

df$crossover_after<- sapply( seq_along(df$sample) ,  FUN = f_crossover_after)
df$crossover_after<- df$date[df$crossover_after]




#View(df)

输出:

#   row       date   sample     cutoff crossover_before crossover_after
#1  591 2020-02-14 0.008470 0.00830060             <NA>      2020-02-16
#2  590 2020-02-15 0.008460 0.00829080             <NA>      2020-02-16
#3  589 2020-02-16 0.007681 0.00752738             <NA>      2020-02-17
#4  588 2020-02-17 0.007144 0.00700112             <NA>      2020-02-20
#5  587 2020-02-18 0.007262 0.00711676             <NA>      2020-02-20
#6  586 2020-02-19 0.007300 0.00715400       2020-02-17      2020-02-20
#7  585 2020-02-20 0.006604 0.00647192             <NA>      2020-02-26
#8  584 2020-02-21 0.006843 0.00670614       2020-02-20      2020-02-22
#9  583 2020-02-22 0.006687 0.00655326             <NA>      2020-02-26
#10 582 2020-02-23 0.006991 0.00685118       2020-02-22      2020-02-25
#11 581 2020-02-24 0.007333 0.00718634       2020-02-23      2020-02-25
#12 580 2020-02-25 0.006738 0.00660324             <NA>      2020-02-26
#13 579 2020-02-26 0.006279 0.00615342             <NA>            <NA>

【讨论】:

  • 多么简洁的小功能!你很擅长解释我想要表达的东西。我很感激。目前,这将在我的交叉列中返回所有“-1”。这很奇怪,因为对于“样本”中的每个值,绝对有一个小于 2% 甚至 20% 的过程值。但任何调整后的值都只返回 -1。我只想报告小于(例如)0.98*df$sample 的值的下一个处理发生率。 (接下来,按日期升序进行)。我一定会玩的。
  • 到目前为止,我尽了最大努力,结果不一。大多数回报仍然是-1,偶尔会从上升或下降位置报告行号。关于调整它以保持沿 df$sample 排序直到找到比当前值小 2% 的下一个继续值并报告该行号的任何想法?
  • @Bo_0 我想我在你添加一些澄清之前已经写了答案编辑问题。无论如何,我不太确定要求是在当前日期之前还是之后找到匹配的行。我重写了代码以包含上述两种情况。
  • 太好了,非常感谢
【解决方案2】:

相当混乱,但这应该可以解决问题

library(dplyr)
df<- read.csv( sep = " ",  text=
                 "row date sample
591 2020-02-14 0.008470
590 2020-02-15 0.008460
589 2020-02-16 0.007681
588 2020-02-17 0.007144
587 2020-02-18 0.007262
586 2020-02-19 0.007300
585 2020-02-20 0.006604
584 2020-02-21 0.006843
583 2020-02-22 0.006687
582 2020-02-23 0.006991
581 2020-02-24 0.007333
580 2020-02-25 0.006738
579 2020-02-26 0.006279", 
               
)

x <- 1.05

df <- df %>%
  mutate(id =  1:n()) %>% 
  rowwise %>% 
  mutate(greater_row = 
           first(which(sample*x <
                         df$sample[id:nrow(df)]) + 
                   id-1))
df$greater_row <- df$date[df$greater_row]

这应该允许您将x 设置为您想要的任何因素

【讨论】:

  • 这很棒。我真的很欣赏这种方法。目前,这是返回升序或降序原点的第一个日期。其中,有没有办法调整它以仅报告第一个诉讼日期?我不是很清楚,那是我的错。我会玩的。
  • 这很奇怪,当我运行代码时,它总是返回“当前”日期之后的第一个有效日期(行)。如果您想更改顺序,您只需重新排序 data.frame 以便日期升序...
  • 复制那个。感谢您的帮助!
【解决方案3】:

如果我理解正确,这可以通过 non-equi self join 使用两个辅助列来解决:

library(data.table)
setDT(df)[, rn := .I][, threshold := 0.8 * sample][
  , conc20 := df[df, on = .(rn > rn, sample < threshold), mult = "first", x.date]][
    , c("rn", "threshold") := NULL][]
          date   sample     conc20
 1: 2020-02-14 0.008470 2020-02-20
 2: 2020-02-15 0.008460 2020-02-20
 3: 2020-02-16 0.007681 2020-02-27
 4: 2020-02-17 0.007144 2020-02-27
 5: 2020-02-18 0.007262 2020-02-27
 6: 2020-02-19 0.007300 2020-02-27
 7: 2020-02-20 0.006604       <NA>
 8: 2020-02-21 0.006843 2020-02-27
 9: 2020-02-22 0.006687 2020-02-27
10: 2020-02-23 0.006991 2020-02-27
11: 2020-02-24 0.007333 2020-02-27
12: 2020-02-25 0.006738 2020-02-27
13: 2020-02-26 0.006279       <NA>
14: 2020-02-27 0.005300       <NA>

说明

on = 子句中的第一个条件确保只考虑后续行,第二个条件查找sample &lt; threshold,其中threshold 已预先定义为sample 的80%。辅助列rn 包含行号(通过 特殊符号.I 创建)。此外,mult = "first" 告诉在多个匹配的情况下选择第一个匹配项。

结果作为附加列添加conc20引用,即不复制整个数据集。最后,通过引用删除了两个辅助列。

请注意,使用了 链接。

为了演示,可以显示包含所有辅助列的非等自连接的结果:

setDT(df)[, rn := .I][, threshold := 0.8 * sample][
  df, on = .(rn > rn, sample < threshold), mult = "first"]
          date    sample rn threshold     i.date i.sample
 1: 2020-02-20 0.0067760  1 0.0052832 2020-02-14 0.008470
 2: 2020-02-20 0.0067680  2 0.0052832 2020-02-15 0.008460
 3: 2020-02-27 0.0061448  3 0.0042400 2020-02-16 0.007681
 4: 2020-02-27 0.0057152  4 0.0042400 2020-02-17 0.007144
 5: 2020-02-27 0.0058096  5 0.0042400 2020-02-18 0.007262
 6: 2020-02-27 0.0058400  6 0.0042400 2020-02-19 0.007300
 7:       <NA> 0.0052832  7        NA 2020-02-20 0.006604
 8: 2020-02-27 0.0054744  8 0.0042400 2020-02-21 0.006843
 9: 2020-02-27 0.0053496  9 0.0042400 2020-02-22 0.006687
10: 2020-02-27 0.0055928 10 0.0042400 2020-02-23 0.006991
11: 2020-02-27 0.0058664 11 0.0042400 2020-02-24 0.007333
12: 2020-02-27 0.0053904 12 0.0042400 2020-02-25 0.006738
13:       <NA> 0.0050232 13        NA 2020-02-26 0.006279
14:       <NA> 0.0042400 14        NA 2020-02-27 0.005300

数据

library(data.table)
df <- fread("
i   date       sample
591 2020-02-14 0.008470
590 2020-02-15 0.008460
589 2020-02-16 0.007681
588 2020-02-17 0.007144
587 2020-02-18 0.007262
586 2020-02-19 0.007300
585 2020-02-20 0.006604
584 2020-02-21 0.006843
583 2020-02-22 0.006687
582 2020-02-23 0.006991
581 2020-02-24 0.007333
580 2020-02-25 0.006738
579 2020-02-26 0.006279
580 2020-02-27 0.005300
", drop = 1L)

【讨论】:

  • 太好了。非常感谢你的帮助! -还有你的崩溃。这为我提供了一种新的玩法。
猜你喜欢
  • 2019-08-24
  • 2013-09-19
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 2017-11-02
  • 2021-12-11
  • 2020-06-11
  • 2019-10-15
相关资源
最近更新 更多