簡體   English   中英

根據R中另一列中的布爾布爾變量來選擇數據框中的行

[英]Select rows in dataframe conditional on a switching boolean variable in another column in 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中執行此操作?

嘗試

我在tidyverse package找到了select()select_if()函數,但是,我無法根據該列中的前一個值來選擇值。

我們可以使用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"))

這是另一個base解決方案:

df[c(FALSE, diff(df$boolean) != 0), ]

   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

這取決於采用TRUEFALSE之間的差異。 如果更改,則差異將為-1或1。

使用包中的輔助函數shift() (以及Ronak提供的正確數據):

subset(df, boolean != shift(boolean, fill = boolean[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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM