Lọc cột khung dữ liệu có chứa vectơ

Jan 13 2021

Tôi muốn lọc một cột chứa vectơ trên toàn bộ nội dung của ô. Tôi đã nhìn vào R dplyr. Lọc khung dữ liệu có chứa một cột vectơ số , nhưng nhu cầu của tôi hơi khác.

Df mẫu (bản đại diện đầy đủ bên dưới)

df <- tibble::tribble(
    ~id, ~len, ~vec,
     1L,   1L,   1L,
     2L,   2L,   1:2,
     3L,   2L,   c(1L, 2L),
     4L,   3L,   c(1L, 2L, 3L),
     5L,   3L,   1:3,
     6L,   3L,   c(1L, 3L, 2L),
     7L,   3L,   c(3L, 2L, 1L),
     8L,   3L,   c(1L, 3L, 2L),
     9L,   4L,   c(1L, 2L, 4L, 3L),
    10L,   3L,   c(3L, 2L, 1L)
    )

cho (được mã hóa màu cho các kết quả phù hợp)

Tôi có thể nhóm_bằng cột vec:

dfg <- df %>% 
    group_by(vec) %>% 
    summarise(n = n()
             ,total_len = sum(len))

Đối với các ô riêng lẻ, so sánh thẳng không hoạt động, nhưng giống hệt nhau thì:

df$vec[4] == df$vec[5]
#> Error in df$vec[4] == df$vec[5]: comparison of these types is not implemented

identical(df$vec[4], df$vec[5])
#> [1] TRUE

Nhưng không có thiết bị tương đương nào hoạt động trong một bộ lọc , đó là những gì tôi cần:

df %>% filter(vec == c(1L, 2L, 3L))
#> Warning in vec == c(1L, 2L, 3L): longer object length is not a multiple of
#> shorter object length
#> Error: Problem with `filter()` input `..1`.
#> x 'list' object cannot be coerced to type 'integer'
#> i Input `..1` is `vec == c(1L, 2L, 3L)`.

df %>% filter(identical(vec, c(1L, 2L, 3L)))
#> # A tibble: 0 x 3
#> # ... with 3 variables: id <int>, len <int>, vec <list>

df %>% filter(identical(vec, vec[5]))
#> # A tibble: 0 x 3
#> # ... with 3 variables: id <int>, len <int>, vec <list>

Tôi chắc rằng có một giải pháp đơn giản mà tôi đang thiếu.

Một nhu cầu nâng cao hơn là khớp với nơi nội dung của ô khớp theo bất kỳ thứ tự nào, vì vậy 6 ô được đánh dấu màu cam, tím và vàng ở trên sẽ khớp với tất cả. Một giải pháp cũng hoạt động với danh sách cũng như vectơ cũng sẽ rất tuyệt vì đây có thể là nhu cầu trong tương lai.

Reprex đầy đủ:

library(tibble)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

df <- tibble::tribble(
    ~id, ~len, ~vec,
     1L,   1L,   1L,
     2L,   2L,   1:2,
     3L,   2L,   c(1L, 2L),
     4L,   3L,   c(1L, 2L, 3L),
     5L,   3L,   1:3,
     6L,   3L,   c(1L, 3L, 2L),
     7L,   3L,   c(3L, 2L, 1L),
     8L,   3L,   c(1L, 3L, 2L),
     9L,   4L,   c(1L, 2L, 4L, 3L),
    10L,   3L,   c(3L, 2L, 1L)
    )
df
#> # A tibble: 10 x 3
#>       id   len vec      
#>    <int> <int> <list>   
#>  1     1     1 <int [1]>
#>  2     2     2 <int [2]>
#>  3     3     2 <int [2]>
#>  4     4     3 <int [3]>
#>  5     5     3 <int [3]>
#>  6     6     3 <int [3]>
#>  7     7     3 <int [3]>
#>  8     8     3 <int [3]>
#>  9     9     4 <int [4]>
#> 10    10     3 <int [3]>

dfg <- df %>% 
    group_by(vec) %>% 
    summarise(n = n()
             ,total_len = sum(len))
#> `summarise()` ungrouping output (override with `.groups` argument)
dfg           
#> # A tibble: 6 x 3
#>   vec           n total_len
#>   <list>    <int>     <int>
#> 1 <int [1]>     1         1
#> 2 <int [2]>     2         4
#> 3 <int [3]>     2         6
#> 4 <int [3]>     2         6
#> 5 <int [3]>     2         6
#> 6 <int [4]>     1         4

df$vec[4] == df$vec[5]
#> Error in df$vec[4] == df$vec[5]: comparison of these types is not implemented

identical(df$vec[4], df$vec[5])
#> [1] TRUE

df %>% filter(vec == c(1L, 2L, 3L))
#> Warning in vec == c(1L, 2L, 3L): longer object length is not a multiple of
#> shorter object length
#> Error: Problem with `filter()` input `..1`.
#> x 'list' object cannot be coerced to type 'integer'
#> i Input `..1` is `vec == c(1L, 2L, 3L)`.

df %>% filter(identical(vec, c(1L, 2L, 3L)))
#> # A tibble: 0 x 3
#> # ... with 3 variables: id <int>, len <int>, vec <list>

df %>% filter(identical(vec, vec[5]))
#> # A tibble: 0 x 3
#> # ... with 3 variables: id <int>, len <int>, vec <list>

Created on 2021-01-13 by the reprex package (v0.3.0)

Trả lời

2 RonakShah Jan 13 2021 at 14:19

Ném vào rowwisevà cũng kiểm tra lengthvector để so sánh để tránh các cảnh báo.

library(dplyr)

compare <- c(1L, 2L, 3L)

df %>% 
  rowwise() %>%
  filter(length(vec) == length(compare) && all(vec == compare))

#     id   len vec      
#  <int> <int> <list>   
#1     4     3 <int [3]>
#2     5     3 <int [3]>

Trước filtertiên, chúng ta có thể tính theo độ dài có thể nhanh hơn trên các bộ dữ liệu lớn hơn.

df %>% 
  filter(lengths(vec) == length(compare)) %>%
  rowwise() %>%
  filter(all(vec == compare)) 

Logic tương tự trong cơ sở R:

subset(df, sapply(vec, function(x) 
                  length(x) == length(compare) && all(x == compare)))
1 akrun Jan 13 2021 at 23:48

Chúng ta có thể sử dụng map

library(dplyr)
library(purrr)
compare <- c(1L, 2L, 3L)
df %>%
   filter(map_lgl(vec, ~ length(.x) == length(compare)  && all(.x == compare)))
 # A tibble: 2 x 3
 #     id   len vec      
 #  <int> <int> <list>   
 #1     4     3 <int [3]>
 #2     5     3 <int [3]>