如何使用r中的if条件基于其他列创建新列

时间:2019-07-20 08:17:29

标签: r for-loop if-statement col

无法找到一种基于列中事件组的条件来生成新列的方法。

称为“ BF”的列表示流列的(i-3),并且对于每个“事件”组将是相同的BF。例如,在第5行中,“ BF”的值为39,这是事件列中所有“ 2”的流列(行2的流)的前一个第3个值。 问题在于BF [i]不能大于flow [i]。如果BF [i]大于flow [i],则BF应该是流量的(i-4)或(i-5)或(1-6)...,直到BF [i]等于或小于flow [i]。例如,在第10行中,“ BF”列的值大于“流”列的值,因此,第10行中的BF_1(我要创建的列)的值为37,表示最接近的下限流量值,在这种情况下为流量[i-6]。

作为示例,我们具有以下数据框:

flow<- c(40, 39, 38, 37, 50, 49, 46, 44, 43, 45, 40, 30, 80, 75, 50, 55, 53, 51, 49, 100)
event<- c(1,1,1,1,2,2,2,2,2,3,3,3,4,4,4,5,5,5,5,6)
BF<- c(NA, NA, NA, NA, 39, 39, 39, 39, 39, 46, 46, 46, 45, 45, 45, 80, 80, 80, 80, 53)
a<- data.frame(flow, event, BF)

这是我正在寻找的愿望输出。我要创建BF_1列。

   flow event BF  BF_1
1    40   1   NA   NA
2    39   1   NA   NA
3    38   1   NA   NA
4    37   1   NA   NA
5    50   2   39   39
6    49   2   39   39
7    46   2   39   39
8    44   2   39   39
9    43   2   39   39
10   45   3   46   37
11   40   3   46   37
12   30   3   46   37
13   80   4   45   45
14   75   4   45   45
15   50   4   45   45
16   55   5   80   30
17   53   5   80   30
18   51   5   80   30
19   49   5   80   30
20  100   6   53   53

是否有可能生成BF_1列?请让我知道任何想法。我正在使用for循环并使用if条件,但无法保存整个事件列组的BF值。

2 个答案:

答案 0 :(得分:1)

编码效率低下,可以使用dplyr等。但是它将完成工作并匹配给定的BF_1

flow <- c(40, 39, 38, 37, 50, 49, 46, 44, 43, 45, 40, 30, 80, 75, 50, 55, 53, 51, 49, 100)
event <- c(1,1,1,1,2,2,2,2,2,3,3,3,4,4,4,5,5,5,5,6)
BF <- c(NA, NA, NA, NA, 39, 39, 39, 39, 39, 46, 46, 46, 45, 45, 45, 80, 80, 80, 80, 53)
a <- data.frame(flow, event, BF)

a$BF_1 <- NA #default to NA first

for(i in 1:length(unique(a$event))){

  if(is.na(a[a$event == i, "BF"][1])) next

  if(a[a$event == i, "BF"][1] < a[a$event == i, "flow"][1]) a[a$event == i, "BF_1"] <- a[a$event == i, "BF"][1]

  if(a[a$event == i, "BF"][1] > a[a$event == i, "flow"][1]) {
    head <- min(which(a$event==i))-6 
    if (min(head-6) < 0) head <- 1 #making sure it doesn't overflow to row 0
    a[a$event == i, "BF_1"] <- min( a[  head:min(which(a$event==i)), "flow"] ) #fill the min of the subset flow column given position
  }

}

a

答案 1 :(得分:1)

一种tidyverse可能是:

a %>%
 left_join(crossing(a, a) %>%
            filter(event > event1) %>%
            group_by(event) %>%
            filter(flow == first(flow)) %>%
            slice(1:(n() - 3)) %>%
            slice(which.max(cumsum(flow > flow1))) %>%
            ungroup() %>%
            transmute(event,
                      flow_flag = flow1), by = c("event" = "event")) %>%
 mutate(BF_1 = ifelse(lag(flow, 3) > flow, flow_flag, lag(flow, 3))) %>%
 group_by(event) %>%
 mutate(BF_1 = first(BF_1)) %>%
 select(-flow_flag)

    flow event    BF  BF_1
   <dbl> <dbl> <dbl> <dbl>
 1    40     1    NA    NA
 2    39     1    NA    NA
 3    38     1    NA    NA
 4    37     1    NA    NA
 5    50     2    39    39
 6    49     2    39    39
 7    46     2    39    39
 8    44     2    39    39
 9    43     2    39    39
10    45     3    46    37
11    40     3    46    37
12    30     3    46    37
13    80     4    45    45
14    75     4    45    45
15    50     4    45    45
16    55     5    80    30
17    53     5    80    30
18    51     5    80    30
19    49     5    80    30
20   100     6    53    53

它可能过于复杂,但是首先要做的是创建值的所有组合(因为理论上所需的值可以在数据中的任何位置)。其次,它确定每组满足条件的第一种情况(不考虑先前的第三个值)。最后,将其与原始df相结合,如果每组的第三个先前值满足条件,则将其返回,否则返回值首先满足条件的值小于实际值。

相关问题