【问题标题】:Defining indices for row sequences more succintly更简洁地定义行序列的索引
【发布时间】:2021-09-07 02:08:22
【问题描述】:

我有一个这样的数据框:

set.seed(123)
df <- data.frame(A = sample(LETTERS[1:5], 50, replace = TRUE), 
                 B = sample(LETTERS[1:5], 50, replace = TRUE))

我想根据两个参数过滤数据框:(i) target 符合特定条件的行和 (ii) 目标行之前的特定行数。具体来说,我想过滤 A == "A" &amp; B == "A" 的行以及目标行之前的 行。我可以通过两步操作来做到这一点:首先定义一个函数,然后将函数用作slice 的输入:

Sequ <- function(col1, col2) {
  # get row indices of target row with function `which`
  inds <- which(col1 == "A" & col2 == "A") 
  # sort row indices of the rows before target row AND target row itself
  sort(unique(c(inds-5, inds-4, inds-3,inds-2, inds-1, inds)))
}

library(dplyr)
df %>%
  slice(Sequ(col1 = A, col2 = B))
   A B
1  D C
2  D B
3  C B
4  C D
5  B B
6  A A
7  E B
8  E D
9  D C
10 D D
11 A A
12 C C
13 D E
14 B E
15 B E
16 B A
17 A A
18 C D
19 C B
20 B D
21 A B
22 A A

但肯定有一个更有效的替代这部分:sort(unique(c(inds-5, inds-4, inds-3,inds-2, inds-1, inds)))。如果我不仅要过滤前面的 5 行,而且要过滤 10100 行,这种单独定义每个索引的方式很快就会变得不切实际.这部分如何编码更经济?

【问题讨论】:

  • 那么,要明确的是,这两者中的哪一个适用?是不是 (1) 您想要过滤数据集以包含符合条件 (A == "A" &amp; B == "A") 的那些行,然后还包括紧接在每个此类行之后的 5 行。或者 (2) 您想过滤数据集以仅包含 (a) 符合条件且 (b) 前面有 5 行也符合条件的行?
  • 只是选项(1)...
  • 明白了,谢谢!据推测,如果一个匹配的前 5 行与另一匹配的前 5 行重叠,您不希望重复。
  • 给定n &lt;- 5,您可以使用data.table 进行滚动连接,全部在一行中:setkey(df[, row := .I], row)[A == "A" &amp; B == "B"][setkey(df[, row := .I], row), roll = -n, nomatch = 0]。结果字段需要清理,但是i.A中的数据| i.B | ...应该是你想要的。

标签: r dplyr indices


【解决方案1】:

1) 定义bothA,它接受一个矩阵,如果任何一行都是A,则返回TRUE。然后使用 rollapply 将其应用为移动窗口。

library(zoo)

bothA <- function(x) any(rowSums(rbind(x) == "A") == 2)
ok <- rollapply(df, 6, bothA, align = "left", partial = TRUE, by.column = FALSE)
df[ok, ]

2)或在管道中

df %>% 
  filter(rollapply(., 6, bothA, align = "left", partial = TRUE, by.column = FALSE))

3) 这也有效:

ok <- rollapply(rowSums(df == "A") == 2, 6, any, align = "left", partial = TRUE)
df[ok, ]

【讨论】:

  • 很好,谢谢。问题是解决方案很大程度上依赖于A == "A" &amp; B == "A" 的仅说明性条件。在实际数据中,条件可能更加多样和复杂。问题的重点是如何更有效地对索引序列进行编码。
  • 不是这样。这是完全一般的。 bothA 可以替换为任意函数。
  • 好的,我明白了。 (这就是我投票赞成答案的原因。)所以假设我保留我的函数名为 Sequ,我怎么能使用 rollaplly 呢?
  • 我认为大部分问题在于 Sequ 不是一个理想的。您想为每一行生成一个真或假,而不是一堆难以处理的索引。改用bothA或用其他东西代替它,但保持相同的理念。
【解决方案2】:

dplyrpurrr 的一个解决方案可能是:

df %>%
 filter(!row_number() %in% unlist(map(which(A == "A" & B == "A"), ~ (.x-5):.x))) 

【讨论】:

    【解决方案3】:

    这里有dplyr的解决方案,可以直接在管道中使用,不需要filter

    Sequ <- function(x, col1, col2, value = "A"){
      x %>%
        mutate(grp = lag(cumsum({{col1}} == value & {{col2}} == value), default = 0)) %>%
        group_by(grp) %>%
        slice_tail(n = 5) %>%
        ungroup() %>%
        select(-grp)
    }
    
    df %>% Sequ(A, B)
    ## A tibble: 23 x 2
    #   A     B    
    #   <chr> <chr>
    # 1 B     D    
    # 2 C     C    
    # 3 E     A    
    # 4 D     B    
    # 5 A     A    
    # 6 C     D    
    # 7 E     E    
    # 8 C     E    
    # 9 C     C    
    #10 A     A    
    ## … with 13 more rows
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-29
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      相关资源
      最近更新 更多