通过匹配连续列中的值过滤 R 数据帧行

Filter R dataframe rows by matching value in consecutive columns

我有一个包含真 (1) 和假 (0) 信息的大型数据框。下面是它的简化示例。

df <- read.table(text = "  0m-10m 0m-15m 0m-20m 0m-25m
                 X 1 0 1 1 
                 Y 1 1 0 0 
                 Z 0 1 0 1 ", header = T)

我需要对两个连续对比为真(都== 1)的行进行子集化,以便结果看起来像这样

   0m-10m 0m-15m 0m-20m 0m-25m
X  1 0 1 1
Y  1 1 0 0 

我可以按 rowSums >=2 进行过滤,但对于我需要排除的 Z 行也是如此。想法?

只需删除第一列和最后一列,使用 & 创建逻辑矩阵,然后使用 rowSums 创建子集

的逻辑向量
df[rowSums(df[-1] & df[-ncol(df)]) > 0,]

-输出

  0m-10m 0m-15m 0m-20m 0m-25m
X      1      0      1      1
Y      1      1      0      0

上面的rowSums不是基于单一数据。我们通过删除第一列和最后一列然后使用 & 从两个大小相等的数据集创建一个逻辑矩阵,因此,如果两者在同一位置都有 1,则只有它会 return TRUE 否则为 FALSE。 rowSums 在这个矩阵上 returns TRUE 的总和(或 TRUE/FALSE -> 1/0)

> df[-1] & df[-ncol(df)]
  0m-15m 0m-20m 0m-25m
X  FALSE  FALSE   TRUE
Y   TRUE  FALSE  FALSE
Z  FALSE  FALSE  FALSE
> rowSums(df[-1] & df[-ncol(df)])
X Y Z 
1 1 0 
> rowSums(df[-1] & df[-ncol(df)]) > 0
    X     Y     Z 
 TRUE  TRUE FALSE 

或者如果我们正在寻找一般情况,我们可以通过使用 applyMARGIN = 1。对于每个相邻的相似值,rle return 是 valueslengthslist。然后,我们根据 lengthsvalues 创建一个逻辑向量,即如果 'values' 是 1,'lengths' 是 2。

n <- 2
df[apply(df, 1, FUN = function(x) with(rle(x), any(lengths == n & values))),]
  0m-10m 0m-15m 0m-20m 0m-25m
X      1      0      1      1
Y      1      1      0      0

-代码分解

> apply(df, 1, FUN = rle)
$X
Run Length Encoding
  lengths: Named int [1:3] 1 1 2
 - attr(*, "names")= chr [1:3] "0m-15m" "0m-20m" ""
  values : Named int [1:3] 1 0 1
 - attr(*, "names")= chr [1:3] "0m-10m" "0m-15m" "0m-25m"

$Y
Run Length Encoding
  lengths: Named int [1:2] 2 2
 - attr(*, "names")= chr [1:2] "0m-20m" ""
  values : Named int [1:2] 1 0
 - attr(*, "names")= chr [1:2] "0m-15m" "0m-25m"

$Z
Run Length Encoding
  lengths: Named int [1:4] 1 1 1 1
 - attr(*, "names")= chr [1:4] "0m-15m" "0m-20m" "0m-25m" ""
  values : Named int [1:4] 0 1 0 1
 - attr(*, "names")= chr [1:4] "0m-10m" "0m-15m" "0m-20m" "0m-25m"
> apply(df, 1, FUN = function(x) with(rle(x),lengths == n & values))
$X
0m-15m 0m-20m        
 FALSE  FALSE   TRUE 

$Y
0m-20m        
  TRUE  FALSE 

$Z
0m-15m 0m-20m 0m-25m        
 FALSE  FALSE  FALSE  FALSE 
> apply(df, 1, FUN = function(x) with(rle(x), any(lengths == n & values)))
    X     Y     Z 
 TRUE  TRUE FALSE 

这是使用数据透视表的另一种方法:

library(dplyr)
library(tidyr)

df %>% 
  rownames_to_column("xyz") %>% 
  pivot_longer(
    -xyz
  ) %>% 
  group_by(xyz) %>% 
  mutate(helper = lag(value),
         flag = ifelse(value==1 & helper==1, 1,0)) %>% 
  filter(any(flag==1)) %>% 
  pivot_wider(
    names_from = name,
    values_from = value,
    values_fill = 0
  ) %>% 
  summarize(across(starts_with("X"), sum)) %>% 
  column_to_rownames("xyz")

  X0m.10m X0m.15m X0m.20m X0m.25m
X       1       0       1       1
Y       1       1       0       0

基于创建辅助列将所有原始列连接为字符串(使用 tidyr::unite)然后在字符串上使用 stringr::str_detect 的解决方案:

library(tidyverse)

df <- read.table(text = "  0m-10m 0m-15m 0m-20m 0m-25m
                 X 1 0 1 1 
                 Y 1 1 0 0 
                 Z 0 1 0 1 ", header = T)

df %>% 
  unite(aux, sep = "", remove = F) %>% 
  filter(str_detect(aux, "11")) %>%
  select(-aux)

#>   X0m.10m X0m.15m X0m.20m X0m.25m
#> X       1       0       1       1
#> Y       1       1       0       0