【问题标题】:Calculating values in a column as a function of previous column value in same row position计算列中的值作为同一行位置中前一列值的函数
【发布时间】:2020-08-16 19:57:22
【问题描述】:

我有很多列,我想根据函数 (1 + x) ^ k 计算其值,其中 x 是来自特定列的值,k 是我们尝试计算的列的索引。我只想为表的所有列的一个子集计算这个。

例如:

df = data.frame(A = c(0.1, 0.05, 0.2), B = c(1, 1, 1), C = c(NA, NA, NA), D = c(NA, NA, NA)

我只想使用 A 列中的值将该函数应用于 C 列和 D 列。

例如 df[1,4] 将被计算为 (1 + (-0.1)^4,因为 4 是 D 列的索引。

另一种解释是,对于选定的列(本例中为 C 和 D),该值是前一列的值乘以 (1+x),即 df[1,4] = df[1,3] * (1 + (-0.1)),给出相同的结果

【问题讨论】:

    标签: r function dataframe


    【解决方案1】:

    一个dplyr 选项可能是:

    df %>%
     rowwise() %>%
     mutate((1 + A)^(across(C:D, ~ replace(., is.na(.), 1)) * which(names(.) %in% c("C", "D"))))
    
          A     B     C     D
      <dbl> <dbl> <dbl> <dbl>
    1  0.1      1  1.33  1.46
    2  0.05     1  1.16  1.22
    3  0.2      1  1.73  2.07
    

    或者如果 C 和 D 列总是 NA:

    df %>%
     rowwise() %>%
     mutate((1 + A)^(1^across(C:D) * which(names(.) %in% c("C", "D"))))
    

    【讨论】:

      【解决方案2】:

      可能是这样的:

      f = function(df, target_cols = c("C", "D"), index_col = "A"){
        
        # df is your data frame 
        # target_cols is a vector of columns you want apply the function (1 + x)^k 
        # index_col is the the x in (1 + x)^k
      
        stopifnot(all(target_cols %in% names(df)))
        stopifnot(index_col %in% names(df))
        
        # Get index of target columns i.e k
        which_col = which(names(df) %in% target_cols)
        
        # Loop over columns
        for(i in which_col){
          df[, i] = (1 + df[, index_col])^i
        }
        
        return(df)
        
      }
      
      df = data.frame(A = c(0.1, 0.05, 0.2), B = c(1, 1, 1), C = c(NA, NA, NA), D = c(NA, NA, NA))
      f(df)                
      
           A B        C        D
      1 0.10 1 1.331000 1.464100
      2 0.05 1 1.157625 1.215506
      3 0.20 1 1.728000 2.073600
      

      【讨论】:

        【解决方案3】:

        你描述的函数定义如下:

        func1 = function(df, i) {
          (1+df[1]^i)
        }
        

        【讨论】:

          【解决方案4】:

          base R 中的一个选项是

          df[3:4] <- (1 + df$A)^col(df)[, 3:4]
          

          Reduce

          df[c('C', 'D')] <- lapply(match(c('C', 'D'), names(df)), function(i) 
               Reduce(function(x, y) (1 + y)^i, df[, 'A'],
                    accumulate = TRUE, init = df$A[1])[-1])
          
          df
          #     A B        C        D
          #1 0.10 1 1.331000 1.464100
          #2 0.05 1 1.157625 1.215506
          #3 0.20 1 1.728000 2.073600
          

          或使用map/accumulate

          library(purrr)
          library(dplyr)
          map_dfc(set_names(match(c('C', 'D'), names(df)), names(df)[3:4]), ~ {
                      i <- .x
                      accumulate(df$A,  ~(1 + .y)^i, 
                        .init = first(df$A))[-1]}) %>% 
             bind_cols(df[1:2], .)
          #     A B        C        D
          #1 0.10 1 1.331000 1.464100
          #2 0.05 1 1.157625 1.215506
          #3 0.20 1 1.728000 2.073600
          

          【讨论】:

          • 谢谢!这证明了对于接缝复杂的问题通常有简单的解决方案。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-12
          • 2022-12-07
          • 2022-11-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多