【问题标题】:How to create a new column based on other columns with if conditions in r如何使用 r 中的 if 条件基于其他列创建新列
【发布时间】:2019-11-29 01:37:58
【问题描述】:

无法找到一种方法来根据列中事件组的 if 条件生成新列。

名为“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”列的值大于“flow”列的值,因此,第 10 行中 BF_1(我要创建的列)的值是 37,表示最接近的较低flow 的值,在本例中为 flow[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 值。

【问题讨论】:

    标签: r for-loop if-statement col


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      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结合,如果每组的前3个值满足条件,则返回它,否则返回第一个满足条件的值小于实际值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-05
        • 1970-01-01
        相关资源
        最近更新 更多