![](/img/trans.png)
[英]R select all rows from a dataframe where a value is duplicated one column but has a specific value in another column
[英]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
,我們可以使用lag
和cumsum
創建組,並選擇每個組的第一行。
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
這取決於采用TRUE
和FALSE
之間的差異。 如果更改,則差異將為-1或1。
使用data.table包中的輔助函數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.