【问题标题】:Selecting specific rows and following ones which meet certain criteria in R选择特定行并遵循 R 中满足特定条件的行
【发布时间】:2020-04-16 11:35:26
【问题描述】:

我有一个大型数据集 [df],例如:

id   device   date                pressure    warning
1    B3       2020-04-15 08:00    112         0
2    B3       2020-04-15 09:00    67          1
3    B3       2020-04-15 10:00    13          0
4    B3       2020-04-15 11:00    0           0
5    B3       2020-04-15 12:00    12          0
6    B3       2020-04-15 13:00    28          0
7    B3       2020-04-16 09:00    120         0
8    B3       2020-04-16 10:00    80          1
9    B3       2020-04-16 11:00    0           0
10   B3       2020-04-16 12:00    19          0
11   B3       2020-04-16 13:00    30          0

我需要选择有警告 [1] 的那些,并且我还需要选择压力值高于 20 [压力 >= 20] 的警告后的第一行。

预期结果如下所示:

id   device   date                pressure    warning
2    B3       2020-04-15 09:00    67          1
6    B3       2020-04-15 13:00    28          0
8    B3       2020-04-16 10:00    80          1
11   B3       2020-04-16 13:00    30          0

在 R 或 SQL 中有什么方法可以做到这一点吗?

感谢您的任何建议。

【问题讨论】:

  • 为什么您的预期结果显示 2 其中压力 >= 20 并且问题询问“选择压力值高于 20 的第一行”?
  • 很抱歉。我更正了问题

标签: r dataframe


【解决方案1】:

试试这个。基本思想是首先按“警告组”对 df 进行分组。在这些组中,我们可以选择触发警告的第一个 obs 以及压力高于 20 的第一个后续 obs。感谢 @Ben 大大简化了我的原始代码:

编辑:

library(dplyr)

df %>% 
  group_by(grp = cumsum(warning)) %>% 
  filter(any(warning == 1), warning == 1 | pressure >= 20) %>% 
  slice(1:2) %>% 
  # Drop helpers
  select(-grp)
#> # A tibble: 4 x 6
#> # Groups:   warning1 [2]
#>   warning1 id    device     date  pressure warning
#>      <int> <chr> <chr>      <chr>    <int>   <int>
#> 1        1 B3    2020-04-15 09:00       67       1
#> 2        1 B3    2020-04-15 13:00       28       0
#> 3        2 B3    2020-04-16 10:00       80       1
#> 4        2 B3    2020-04-16 13:00       30       0

由reprex package (v0.3.0) 于 2020 年 4 月 16 日创建

原始代码:

df %>% 
  # Warnings group
  mutate(warning1 = cumsum(warning)) %>%
  # Group by warnings group
  group_by(warning1) %>%
  # Pressure counter by warnings group
  mutate(pressure1 = cumsum(pressure >= 20 & warning == 0)) %>% 
  # Filter: 
  # 1. Keep obs where warning is initiated (warning == 1)
  # 2. Keep first following obs with pressure >= 20 
  filter(warning == 1 | (warning1 > 0 & pressure >= 20 & warning == 0 & pressure1 == 1)) %>% 
  # Drop helpers
  select(-warning1, -pressure1)

【讨论】:

  • stefan,如何简化为:df %&gt;% group_by(grp = cumsum(warning)) %&gt;% filter(any(warning == 1), warning == 1 | pressure &gt;= 20) %&gt;% slice(1:2)?似乎给出了类似的答案
  • 嗨@Ben。绝对地。这是对代码的相当大的简化。谢谢。随意发布它作为答案。
  • 没问题 - 如果您愿意,您可以编辑您的答案并包括在内作为替代。一切都好。
  • 嗨,这很好用,我得到了预期行数的结果,但是,我所有的行和列都只包含 NA,而行索引包含诸如 (NA, NA.1 , NA.2...)。你知道这可能意味着什么吗?非常感谢。
  • 您的真实数据集中很可能有缺失,例如如果是NA 在warning 中,则通过cumsum() 进行分组。我建议您检查数据集中的缺失。接下来的问题是如何处理它们,例如删除这样的 obs?,替换缺失,...
【解决方案2】:

data.table 解决方案

逻辑与@stefan 的答案相同。

library(data.table)

dt <- fread('id device  date                pressure    warning
1   B3      2020/4/15 8:00  112 0
2   B3      2020/4/15 9:00  67  1
3   B3      2020/4/15 10:00 13  0
4   B3      2020/4/15 11:00 0   0
5   B3      2020/4/15 12:00 12  0
6   B3      2020/4/15 13:00 28  0
7   B3      2020/4/16 9:00  120 0
8   B3      2020/4/16 10:00 80  1
9   B3      2020/4/16 11:00 0   0
10  B3      2020/4/16 12:00 19  0
11  B3      2020/4/16 13:00 30  0
')


dt[,grp:=cumsum(warning)]

dt[warning==1|pressure>20&grp>0,head(.SD,2),by=.(grp)]
#>    grp id device            date pressure warning
#> 1:   1  2     B3  2020/4/15 9:00       67       1
#> 2:   1  6     B3 2020/4/15 13:00       28       0
#> 3:   2  8     B3 2020/4/16 10:00       80       1
#> 4:   2 11     B3 2020/4/16 13:00       30       0

由reprex package (v0.3.0) 于 2020-04-17 创建

【讨论】:

    【解决方案3】:

    这是一个基本的 R 解决方案

    ind1 <- which(df$warning==1)
    ind2 <- which(df$pressure >= 20)
    dfout <- df[sort(c(ind1,sapply(ind1, function(x) min(ind2[ind2 > x])))),]
    

    这样

    > dfout
       id     device  date pressure warning
    2  B3 2020-04-15 09:00       67       1
    6  B3 2020-04-15 13:00       28       0
    8  B3 2020-04-16 10:00       80       1
    11 B3 2020-04-16 13:00       30       0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-15
      • 2011-12-28
      • 2014-02-18
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      • 2018-09-19
      • 1970-01-01
      相关资源
      最近更新 更多