我如何使用一个函数来分析所有 tibbles 中的所有行,将我的数据放在一个 tibbles 列表中?

How can I use a function to analyse all the rows in all the tibbles, having my data in a list of tibbles?

我有一个包含 106 个小标题的列表,每个小标题包含两列(日期、温度)和数千个值。

我尝试创建一个函数,允许我通过 tibble 获取温度低于 8.0 的行的索引四次。

我遇到的问题是我的代码只执行每个小标题的第一行。

这里可以看到代码:

pos_r = 0;
temp =0; 
posx = vector();
for (i in seq_along(data_sensor)){
  if (temp < 4){
    pos_r = pos_r + 1;
  if (data_sensor[[i]]$Temperature < 8.0){
       temp=temp+1;
} else if (temp == 4){
   posx[i] = pos_r;
   i = i+1;
}
}
}



> [1] NA NA NA NA NA NA  5  6 NA  7  8 NA NA  9 NA NA NA 10 11 NA 12 13 14 NA 15 16 17 18 19 NA
 [31] 20 21 22 NA 23 24 25 26 27 NA 28 NA 29 30 NA 31 32 33 34 NA 35 36 37 38 NA 39 40 41 42 43
 [61] 44 NA 45 NA 46 47 48 49 50 51 52 53 54 55 56 57 58 NA NA NA 59 60 61 NA 62 63 NA 64 65 66
 [91] NA 67 NA NA 68 69 70 71 72 73 74 75 76 77 78 79

如何处理列表中每个小标题的所有行?

这里有一个选项:在下面的代码中,我们使用逻辑测试来查找温度在四天内低于 8 的行的索引。然后我们使用map在列表中的每个数据框上实现这个方法。

library(tidyverse)

# Generate a list of 5 data frames to work with
set.seed(33)
dl = replicate(5, tibble(date=seq(as.Date("2021-01-01"), as.Date("2021-02-01"), by="1 day"),
                         temperature = 10 + cumsum(rnorm(length(date), 0, 3))),
               simplify=FALSE)

# Index of row of fourth day with temperataure lower than 8
# Run this on the first data frame in the list
min(which(cumsum(dl[[1]][["temperature"]] < 8) == 4))
#> [1] 8

# Run the method on each data frame in the list
# Note that infinity is returned if no data row meets the condition
idx8 = dl %>% 
  map_dbl(~ min(which(cumsum(.x[["temperature"]] < 8) == 4)))

idx8
#> [1]   8  29 Inf   7   6

以下是列表中第一个数据框所示的各个步骤:

# Logical vector returning TRUE when temperature is less than 8
dl[[1]][["temperature"]] < 8
#>  [1] FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
#> [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

# Cumulative number of days where temperature was less than 8
cumsum(dl[[1]][["temperature"]] < 8) 
#>  [1] 0 0 0 0 1 2 3 4 4 5 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7

# Index of rows for which the cumulative number of days where 
#  temperature was less than 8 is equal to 4
which(cumsum(dl[[1]][["temperature"]] < 8) == 4)
#> [1] 8 9

# We want the index of the first row that meets the condition
min(which(cumsum(dl[[1]][["temperature"]] < 8) == 4))
#> [1] 8

从每个数据框中获取指定的行,如果没有满足条件的行,则获取缺失值。 Return 作为数据框的结果:

list(dl, idx8) %>% 
  pmap_dfr(~ { 
    if(is.infinite(.y)) {
      tibble(date=NA, temperature=NA)
    } else {
      .x %>% 
        slice(.y) %>% 
        mutate(row.index=.y) %>% 
        relocate(row.index)
    }
  },
  .id="data.frame")
#> # A tibble: 5 × 4
#>   data.frame row.index date       temperature
#>   <chr>          <dbl> <date>           <dbl>
#> 1 1                  8 2021-01-08       7.12 
#> 2 2                 29 2021-01-29      -0.731
#> 3 3                 NA NA              NA    
#> 4 4                  7 2021-01-07       6.29 
#> 5 5                  6 2021-01-06       4.58

eipi10的回答回答了我的问题。 后来我需要用完全相同的数据找出第一个温度连续3次低于8.0的时间。

下一个代码是这种情况的可能解决方案:

idx84 = data_sensor %>% 
  map_dbl(~min(which(cumsum(.x[["Temperature"]] < 8.0) == 4)))
idx87 = data_sensor %>% 
  map_dbl(~min(which(cumsum(.x[["Temperature"]] < 8.0) == 7)))
idx8=idx87-idx84

在此示例中,我们 select 索引范围从 7 到 4。

沿着 idx8 我们使用 n 来计算多重条件为真的次数。

掩码用于我们想要分析另一个范围但它已经在之前的范围中找到的情况,因此我们将保留我们找到的索引优先于第一个计时器。

即:在 idx87 和 idx84 之间找到了 70 个值,mask 将用 0 指向这些值。如果我们想获得 idx88 和 idx 85 之间的值,我们不会用 a 更改 mask 指向的值0.

最后,我们在idx_pos8[i]

中知道多重条件为True,保存idx87的索引值
for (i in seq_along(idx8)){
      #If the difference is 3, there are no na's 
      if ((idx8[i] == 3)&(!is.na(idx8[i]))){
        n=n+1 
        mask_idx8[i]=0
        idx_pos8[i]=idx87[i]
        #If there are na's or differ from 3
      } else if ((is.na(idx8[i]))||(idx8[i] != 3)){
          idx_pos8[i]=0
          mask_idx8[i]= idx8[i]
    }}