根据多个条件选择一行

时间:2019-07-31 13:10:47

标签: r lag ranking lead

谁能想到如何在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’列,其中,对于每个唯一的序列,y下的match的第一个实例都被赋予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语句与滞后值结合起来,可以很容易地为等级1和等级2返回正确的值,但是一旦等级>2,我就很困惑。

真实的dataset包含+100k rows,排名可能上升到数百,因此我不想仅仅扩展ifelse语句来使用滞后检查上面的值。

我的最终目标是从“选择”下的所有T中创建一个新的dataset,因此,如果有人知道如何直接将它们拉出而不创建新的列,那就更好了!

我猜测ifelse语句是一种愚蠢的做法,但是我被困在:/

任何帮助将不胜感激:)

5 个答案:

答案 0 :(得分:1)

一种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))))

答案 1 :(得分:1)

您可以尝试类似:

sql_mode=''

答案 2 :(得分:1)

一个选项:

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 

答案 3 :(得分:1)

您可以将新列创建为逻辑向量,当TRUE时,该列为match == 'y',并且该行是(match,seq)对(即rowid(match, seq) == 1)的第一个出现< / p>

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

答案 4 :(得分:1)

一个选项是

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