Filter kolom dataframe yang berisi vektor

Jan 13 2021

Saya ingin memfilter kolom yang berisi vektor di seluruh konten sel. Saya telah melihat R dplyr. Filter kerangka data yang berisi kolom vektor numerik , tetapi kebutuhan saya sedikit berbeda.

Contoh df (reprex lengkap di bawah)

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)
    )

memberi (kode warna untuk pertandingan)

Saya dapat mengelompokkan_ berdasarkan kolom vec:

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

Untuk sel individu, perbandingan langsung tidak berfungsi, tetapi identik berfungsi :

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

Tetapi tidak ada padanan yang berfungsi dalam filter , yang saya butuhkan:

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>

Saya yakin ada solusi sederhana yang saya lewatkan.

Kebutuhan yang lebih maju adalah mencocokkan tempat konten sel cocok dalam urutan apa pun, sehingga 6 sel yang disorot oranye, ungu, dan emas di atas semuanya akan cocok. Solusi yang juga berfungsi dengan list serta vektor juga akan bagus karena ini mungkin merupakan kebutuhan masa depan.

Reprex penuh:

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)

Jawaban

2 RonakShah Jan 13 2021 at 14:19

Lempar rowwisedan juga periksa lengthvektor untuk dibandingkan untuk menghindari peringatan.

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]>

Kita bisa lihat filterpanjangnya dulu yang mungkin lebih cepat pada dataset yang lebih besar.

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

Logika serupa di basis R:

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

Kita bisa menggunakan 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]>