首页 > 解决方案 > 以 R 中另一列中的切换布尔变量为条件选择数据框中的行

问题描述

假设我在 R 中有以下数据框:

set.seed(23)

# Create sample data
time = 1:15
x = rnorm(n = 15) 
y = rnorm(n = 15)
boolean = sample(c(TRUE,FALSE), 15, TRUE)
df <- data.frame(time, x, y, boolean)

# Output
> df
time           x            y boolean
1     1  0.19321233  0.308136896    TRUE
2     2 -0.43468211 -0.520178315    TRUE
3     3  0.91326710 -0.442313801   FALSE # select
4     4  1.79338809 -0.599312812    TRUE # select
5     5  0.99660511  1.294577829    TRUE
6     6  1.10749049  0.835391247    TRUE
7     7 -0.27808628 -0.566015100    TRUE
8     8  1.01920549  0.788419350   FALSE # select
9     9  0.04543718 -1.165929326    TRUE # select
10   10  1.57577959 -0.530820006   FALSE # select
11   11  0.21828845 -0.001058737   FALSE
12   12 -1.04653534 -0.512562365   FALSE
13   13 -0.28868865  1.242867513   FALSE
14   14  0.48155029 -0.660582851   FALSE
15   15 -1.21637643  0.166624215    TRUE # select

问题

我想选择所有行,其中第 4 列中的布尔值从FALSE到切换,TRUE反之亦然(如上面的数据框所示)。

问题

我如何在 R 中做到这一点?

试图

我在 中找到select()select_if()函数tidyverse package,但是,我无法根据列中的前一个值选择值。

标签: rdataframedata-manipulation

解决方案


我们可以用来创建一个计数器,它随着值rle的每次变化而递增。boolean我们duplicated只为每个计数器使用并选择第一行。这也将选择第一行,但由于它不是boolean值的实际变化,我们删除该行(通过使用[-1])。

df[!duplicated(with(rle(df$boolean), rep(seq_along(values), lengths))), ][-1, ]

#   time           x            y boolean
#2     2 -0.43468211 -0.566015100    TRUE
#3     3  0.91326710  0.788419350   FALSE
#6     6  1.10749049 -0.001058737    TRUE
#8     8  1.01920549  1.242867513   FALSE
#9     9  0.04543718 -0.660582851    TRUE
#13   13 -0.28868865 -1.146665860   FALSE
#15   15 -1.21637643 -0.202111683    TRUE

可以应用相同的逻辑data.table::rleid,这将使其更短

df[!duplicated(data.table::rleid(df$boolean)), ][-1, ]

在中,我们可以使用和dplyr创建组,并选择每个组的第一行。lagcumsum

library(dplyr)
df %>%
  group_by(group = cumsum(boolean != lag(boolean, default = first(boolean)))) %>%
  slice(1L) %>%
  ungroup %>%
  slice(-1L) %>%
  select(-group)

数据

df <- structure(list(time = 1:15, x = c(0.19321233, -0.43468211, 0.9132671, 
1.79338809, 0.99660511, 1.10749049, -0.27808628, 1.01920549, 
0.04543718, 1.57577959, 0.21828845, -1.04653534, -0.28868865, 
0.48155029, -1.21637643), y = c(0.835391247, -0.5660151, 0.78841935, 
-1.165929326, -0.530820006, -0.001058737, -0.512562365, 1.242867513, 
-0.660582851, 0.166624215, -0.55320524, 0.098181415, -1.14666586, 
-1.249927257, -0.202111683), boolean = c(FALSE, TRUE, FALSE, 
FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, 
FALSE, TRUE)), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14","15"))

推荐阅读