กรองคอลัมน์ดาต้าเฟรมที่มีเวกเตอร์

Jan 13 2021

ฉันต้องการกรองคอลัมน์ที่มีเวกเตอร์ในเนื้อหาทั้งหมดของเซลล์ ฉันดูR dplyr แล้ว กรองดาต้าเฟรมที่มีคอลัมน์เวกเตอร์ตัวเลขแต่ความต้องการของฉันแตกต่างกันเล็กน้อย

ตัวอย่าง df (reprex แบบเต็มด้านล่าง)

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

ให้ (รหัสสีสำหรับการแข่งขัน)

ฉันสามารถgroup_โดยคอลัมน์ vec:

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

สำหรับแต่ละเซลล์การเปรียบเทียบแบบตรงไม่ได้ผล แต่จะเหมือนกัน :

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>

ฉันแน่ใจว่ามีวิธีง่ายๆที่หายไป

ความต้องการขั้นสูงคือการจับคู่เนื้อหาของเซลล์ที่ตรงกันในลำดับใด ๆ ดังนั้นเซลล์ที่ไฮไลต์สีส้มสีม่วงและสีทอง 6 รายการด้านบนจะตรงกันทั้งหมด โซลูชันที่ใช้งานได้กับรายการและเวกเตอร์ก็จะดีเช่นกันเนื่องจากอาจเป็นความต้องการในอนาคต

reprex เต็ม:

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)

คำตอบ

2 RonakShah Jan 13 2021 at 14:19

โยนเข้าrowwiseและตรวจสอบlengthเวกเตอร์เพื่อเปรียบเทียบเพื่อหลีกเลี่ยงคำเตือน

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

เราทำได้filterตามความยาวก่อนซึ่งอาจเร็วกว่าในชุดข้อมูลขนาดใหญ่

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

ตรรกะที่คล้ายกันในฐาน R:

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

เราสามารถใช้ 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]>