簡體   English   中英

如何在 dataframe 中使用來自另一個 dataframe 的開始和結束值對 windows 進行子集化

[英]How to subset windows in a dataframe using start- and end-values from another dataframe in R?

我有一個時間序列數據df1的 dataframe ,我需要從 R 中提取多個“窗口”。 我需要的 windows 的起點和終點位於單獨的 dataframe, df2的兩列中。 起點和終點的值對應於所需的 windows 的行號。

在下面的示例中,我是解決方案的一部分,但目前只提取了第一個 window。 如何修改此示例以提取所有四個 windows? 這可能是purrr的情況嗎?

library(tidyverse)

# dataframe of data to subset
df1 <- tibble(my_values = rnorm(100))

# dataframe of windows (i.e. row number IDs) to extract from data
df2 <-tibble::tribble(
        ~window_start, ~window_end,
                   3L,         10L,
                  21L,         25L,
                  52L,         63L,
                  78L,         90L
        )

# extracted data
df3 <- df1 %>% 
  slice(df2$window_start : df2$window_end)

(注意。我知道這里有一個類似的問題 - 使用來自另一個 dataframe 的起點和終點對 dataframe 進行子集? - 但我的實際數據非常大,我很好奇非基於合並的解決方案是否會更快。)

也許用purrr::map2試試這種方法

# dataframe of data to subset
df1 <- tibble(my_values = rnorm(100, mean = 45, sd = 30) %>% abs())

# dataframe of windows (i.e. row number IDs) to extract from data
df2 <-tibble::tribble(
  ~window_start, ~window_end,
  3L,         10L,
  21L,         25L,
  52L,         63L,
  78L,         90L
)

subset_thats_in <- function(mini, maxi){
  df1 %>% 
    filter(between(my_values, mini, maxi))
}

purrr::map2(df2$window_start, 
            df2$window_end, 
            subset_thats_in)
[[1]]
# A tibble: 4 × 1
  my_values
      <dbl>
1      6.47
2      8.69
3      7.73
4      7.35

[[2]]
# A tibble: 12 × 1
   my_values
       <dbl>
 1      24.2
 2      22.9
 3      22.4
 4      24.4
 5      22.6
 6      21.7
 7      23.2
 8      21.3
 9      23.3
10      21.1
11      23.5
12      22.6

[[3]]
# A tibble: 10 × 1
   my_values
       <dbl>
 1      54.0
 2      61.4
 3      62.5
 4      60.8
 5      60.5
 6      55.5
 7      61.4
 8      59.0
 9      57.9
10      53.3

[[4]]
# A tibble: 6 × 1
  my_values
      <dbl>
1      87.8
2      79.1
3      80.5
4      82.7
5      85.2
6      80.6

你可以使用mapply

df1[unlist(mapply(function(x,y) x:y, df2$window_start, df2$window_end)),]

# A tibble: 38 x 1
   my_values
       <dbl>
 1     0.671
 2    -0.617
 3    -0.354
 4     2.76 
 5     0.382
 6    -0.488
 7     0.889
 8    -1.32 
 9     0.328
10     0.779
# ... with 28 more rows

purrr對於此類數據轉換非常有效。 但是,如果要復制數據,長度為 10000 的列表可能仍然很強大。

x = vector(mode = "list", 10000L)

x = transpose(df2) %>% map(function(x){x = as.numeric(x); df1[x[1]:x[2],]})

as.numeric在轉置列表上獲取范圍,可用於對 df1 進行子集化。

我們可以使用map2

library(tidyverse)

map2(df2[[1]], df2[[2]], ~ df1[.x:.y, ])
#> [[1]]
#> # A tibble: 8 × 1
#>   my_values
#>       <dbl>
#> 1   1.33   
#> 2   1.27   
#> 3   0.415  
#> 4  -1.54   
#> 5  -0.929  
#> 6  -0.295  
#> 7  -0.00577
#> 8   2.40   
#> 
#> [[2]]
#> # A tibble: 5 × 1
#>   my_values
#>       <dbl>
#> 1   -0.224 
#> 2    0.377 
#> 3    0.133 
#> 4    0.804 
#> 5   -0.0571
#> 
#> [[3]]
#> # A tibble: 12 × 1
#>    my_values
#>        <dbl>
#>  1   -0.377 
#>  2    2.44  
#>  3   -0.795 
#>  4   -0.0549
#>  5    0.250 
#>  6    0.618 
#>  7   -0.173 
#>  8   -2.22  
#>  9   -1.26  
#> 10    0.359 
#> 11   -0.0110
#> 12   -0.941 
#> 
#> [[4]]
#> # A tibble: 13 × 1
#>    my_values
#>        <dbl>
#>  1    -0.118
#>  2    -0.912
#>  3    -1.44 
#>  4    -0.797
#>  5     1.25 
#>  6     0.772
#>  7    -0.220
#>  8    -0.425
#>  9    -0.419
#> 10     0.997
#> 11    -0.276
#> 12     1.26 
#> 13     0.647

或者創造性地使用 dplyr。

df2 %>%
  rowwise() %>%
  transmute(windows = list(c_across(starts_with("window")) %>% {df1[.[[1]]:.[[2]], ]}))
#> # A tibble: 4 × 1
#> # Rowwise: 
#>   windows          
#>   <list>           
#> 1 <tibble [8 × 1]> 
#> 2 <tibble [5 × 1]> 
#> 3 <tibble [12 × 1]>
#> 4 <tibble [13 × 1]>

代表 package (v2.0.1) 於 2022 年 1 月 9 日創建

數據:

set.seed(0)

# dataframe of data to subset
df1 <- tibble(my_values = rnorm(100))

# dataframe of windows (i.e. row number IDs) to extract from data
df2 <- tibble::tribble(
  ~window_start, ~window_end,
  3L, 10L,
  21L, 25L,
  52L, 63L,
  78L, 90L
)

一個簡單的基本 R 解決方案將使用sequence function 生成您需要子集 dataframe 的所有行索引。 sequence 的第一個參數指定要生成的sequence的長度,每個從第二個參數中給出的數字開始。 這應該非常有效,因為 function 所做的唯一事情就是創建一個整數序列。

df1[sequence(df2$window_end - df2$window_start + 1L, df2$window_start), ]

Output

> set.seed(1234L)
> df1 <- tibble(my_values = rnorm(100))
> df1[sequence(df2$window_end - df2$window_start + 1L, df2$window_start), ]
# A tibble: 38 x 1
   my_values
       <dbl>
 1     1.08 
 2    -2.35 
 3     0.429
 4     0.506
 5    -0.575
 6    -0.547
 7    -0.564
 8    -0.890
 9     0.134
10    -0.491
# ... with 28 more rows

您還可以通過使用data.table:::vecseq獲得較小的性能改進。 代碼與上面幾乎相同:

df1[data.table:::vecseq(df2$window_start, df2$window_end - df2$window_start + 1L, NULL), ]

延伸閱讀: data.table高效回收V2

暫無
暫無

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

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