根据多个条件选择单行
Choosing a single row based on multiple criteria
谁能想到如何在 R 中做到这一点?
简单数据:
seq<-c("A","A","A","B","B","B","B")
rank<-c(1,2,3,1,2,3,4)
match<-c("y","n","y","n","n","y","y")
df<- as.data.frame(cbind(seq,rank,match))
seq rank match
1 A 1 y
2 A 2 n
3 A 3 y
4 B 1 n
5 B 2 n
6 B 3 y
7 B 4 y
我想创建一个 ‘choose’
列,其中,对于每个唯一的序列,match
下 y
的第一个实例被赋予 T
,所有其余的被赋予 F
。
所需的输出为:
seq rank match choose
1 A 1 y T
2 A 2 n F
3 A 3 y F
4 B 1 n F
5 B 2 n F
6 B 3 y T
7 B 4 y F
通过将 ifelse
语句与滞后相结合,很容易 return 排名 1 和 2 的正确值,但是一旦排名 >2
,我就被难住了。
真正的 dataset
包含 +100k rows
,排名可能会上升到数百,所以我不想只扩展 ifelse
语句来使用滞后检查以上值.
我的最终目标是从 "choose" 下的所有 T 中创建一个新的 dataset
,所以如果有人知道如何直接将它们拉出而不创建新列,那就更好了!
我猜 ifelse
声明是一种愚蠢的做法,但我被卡住了:/
任何帮助将不胜感激:)
一个 dplyr
可能性是:
df %>%
group_by(seq) %>%
mutate(choose = +(match == "y") * (cumsum(match == "y") == 1))
seq rank match choose
<fct> <fct> <fct> <int>
1 A 1 y 1
2 A 2 n 0
3 A 3 y 0
4 B 1 n 0
5 B 2 n 0
6 B 3 y 1
7 B 4 y 0
如果你想要 TRUE/FALSE 个值:
df %>%
group_by(seq) %>%
mutate(choose = as.logical(+(match == "y") * (cumsum(match == "y") == 1)))
seq rank match choose
<fct> <fct> <fct> <lgl>
1 A 1 y TRUE
2 A 2 n FALSE
3 A 3 y FALSE
4 B 1 n FALSE
5 B 2 n FALSE
6 B 3 y TRUE
7 B 4 y FALSE
与base R
相同:
with(df, ave(match, seq, FUN = function(x) +(x == "y") * (cumsum(x == "y") == 1)))
或:
with(df, ave(match, seq, FUN = function(x) as.logical(+(x == "y") * (cumsum(x == "y") == 1))))
您可以尝试类似的方法:
library(dplyr)
df %>% group_by(seq) %>% filter(choose =="T") %>% top_n(1) %>% mutate(choose = "T")
df[is.na(df)] <- "F
一个选项:
df %>%
group_by(seq) %>%
mutate(choose = row_number() %in% which(match == 'y')[1])
输出:
# A tibble: 7 x 4
# Groups: seq [2]
seq rank match choose
<fct> <fct> <fct> <lgl>
1 A 1 y TRUE
2 A 2 n FALSE
3 A 3 y FALSE
4 B 1 n FALSE
5 B 2 n FALSE
6 B 3 y TRUE
7 B 4 y FALSE
您可以将新列创建为逻辑向量,当 match == 'y'
并且该行是 (match, seq) 对的第一次出现(即 rowid(match, seq) == 1
时,它是 TRUE
)
library(data.table)
setDT(df)
df[, choose := match == 'y' & rowid(match, seq) == 1]
df
# seq rank match choose
# 1: A 1 y TRUE
# 2: A 2 n FALSE
# 3: A 3 y FALSE
# 4: B 1 n FALSE
# 5: B 2 n FALSE
# 6: B 3 y TRUE
# 7: B 4 y FALSE
或者直接对数据进行子集化而不创建新列
df[match == 'y' & rowid(match, seq) == 1]
# seq rank match
# 1: A 1 y
# 2: B 3 y
一个选项是
library(dplyr)
df %>%
group_by(seq) %>%
mutate(choose = row_number() == match("y", match))
# A tibble: 7 x 4
# Groups: seq [2]
# seq rank match choose
# <fct> <fct> <fct> <lgl>
#1 A 1 y TRUE
#2 A 2 n FALSE
#3 A 3 y FALSE
#4 B 1 n FALSE
#5 B 2 n FALSE
#6 B 3 y TRUE
#7 B 4 y FALSE
谁能想到如何在 R 中做到这一点?
简单数据:
seq<-c("A","A","A","B","B","B","B")
rank<-c(1,2,3,1,2,3,4)
match<-c("y","n","y","n","n","y","y")
df<- as.data.frame(cbind(seq,rank,match))
seq rank match
1 A 1 y
2 A 2 n
3 A 3 y
4 B 1 n
5 B 2 n
6 B 3 y
7 B 4 y
我想创建一个 ‘choose’
列,其中,对于每个唯一的序列,match
下 y
的第一个实例被赋予 T
,所有其余的被赋予 F
。
所需的输出为:
seq rank match choose
1 A 1 y T
2 A 2 n F
3 A 3 y F
4 B 1 n F
5 B 2 n F
6 B 3 y T
7 B 4 y F
通过将 ifelse
语句与滞后相结合,很容易 return 排名 1 和 2 的正确值,但是一旦排名 >2
,我就被难住了。
真正的 dataset
包含 +100k rows
,排名可能会上升到数百,所以我不想只扩展 ifelse
语句来使用滞后检查以上值.
我的最终目标是从 "choose" 下的所有 T 中创建一个新的 dataset
,所以如果有人知道如何直接将它们拉出而不创建新列,那就更好了!
我猜 ifelse
声明是一种愚蠢的做法,但我被卡住了:/
任何帮助将不胜感激:)
一个 dplyr
可能性是:
df %>%
group_by(seq) %>%
mutate(choose = +(match == "y") * (cumsum(match == "y") == 1))
seq rank match choose
<fct> <fct> <fct> <int>
1 A 1 y 1
2 A 2 n 0
3 A 3 y 0
4 B 1 n 0
5 B 2 n 0
6 B 3 y 1
7 B 4 y 0
如果你想要 TRUE/FALSE 个值:
df %>%
group_by(seq) %>%
mutate(choose = as.logical(+(match == "y") * (cumsum(match == "y") == 1)))
seq rank match choose
<fct> <fct> <fct> <lgl>
1 A 1 y TRUE
2 A 2 n FALSE
3 A 3 y FALSE
4 B 1 n FALSE
5 B 2 n FALSE
6 B 3 y TRUE
7 B 4 y FALSE
与base R
相同:
with(df, ave(match, seq, FUN = function(x) +(x == "y") * (cumsum(x == "y") == 1)))
或:
with(df, ave(match, seq, FUN = function(x) as.logical(+(x == "y") * (cumsum(x == "y") == 1))))
您可以尝试类似的方法:
library(dplyr)
df %>% group_by(seq) %>% filter(choose =="T") %>% top_n(1) %>% mutate(choose = "T")
df[is.na(df)] <- "F
一个选项:
df %>%
group_by(seq) %>%
mutate(choose = row_number() %in% which(match == 'y')[1])
输出:
# A tibble: 7 x 4
# Groups: seq [2]
seq rank match choose
<fct> <fct> <fct> <lgl>
1 A 1 y TRUE
2 A 2 n FALSE
3 A 3 y FALSE
4 B 1 n FALSE
5 B 2 n FALSE
6 B 3 y TRUE
7 B 4 y FALSE
您可以将新列创建为逻辑向量,当 match == 'y'
并且该行是 (match, seq) 对的第一次出现(即 rowid(match, seq) == 1
时,它是 TRUE
)
library(data.table)
setDT(df)
df[, choose := match == 'y' & rowid(match, seq) == 1]
df
# seq rank match choose
# 1: A 1 y TRUE
# 2: A 2 n FALSE
# 3: A 3 y FALSE
# 4: B 1 n FALSE
# 5: B 2 n FALSE
# 6: B 3 y TRUE
# 7: B 4 y FALSE
或者直接对数据进行子集化而不创建新列
df[match == 'y' & rowid(match, seq) == 1]
# seq rank match
# 1: A 1 y
# 2: B 3 y
一个选项是
library(dplyr)
df %>%
group_by(seq) %>%
mutate(choose = row_number() == match("y", match))
# A tibble: 7 x 4
# Groups: seq [2]
# seq rank match choose
# <fct> <fct> <fct> <lgl>
#1 A 1 y TRUE
#2 A 2 n FALSE
#3 A 3 y FALSE
#4 B 1 n FALSE
#5 B 2 n FALSE
#6 B 3 y TRUE
#7 B 4 y FALSE