Как создать столбец из суммы, которая имеет подвижные фиксированные ячейки и начинается с разных строк в R

#r

#r

Вопрос:

Я пытаюсь заполнить столбец суммой выражения, содержащего фиксированные ячейки, но по мере перемещения выражения вниз по столбцам фиксированные ячейки для суммы меняются, как и количество строк, которые необходимо включить. Я думал, что смогу достичь этого с помощью функций lead amp; lag, но нет.

Я надеюсь, что это возможно, я мог бы записать каждое выражение для каждой ячейки, а затем создать столбец из значений, но это будет частью функции, через которую передаются наборы данных разного размера, поэтому мне нужно, чтобы это было автоматизировано до конца time_bin .

Выходной столбец в данных — это то, на что я надеюсь.

 NCP <- c(96.05655668, 16.94332276, 19.8844913, 17.74200903, 17.6135507)
time_bin <- c(100,200,300,400,500)
output <- c(14.01221047, 6.51265852, 5.399067538, 3.743397662, 2.02022025)
df <- data.frame(NCP, time_bin, output)
  

Выражение будет выглядеть примерно так: (но аккуратно и удобно)

 output = 
row1 = sum(((NCP/(exp(-0.0008*(time_bin[1])))-(NCP/(exp(-0.0008*0)))))) # Could use lag(time_bin with default 0 to fro last expression
row2 = sum((NCP***Starting at row 2***/(exp(-0.0008*time_bin[2])))-(NCP/(exp(-0.0008*time_bin[1])))),
row3 = sum((NCP***Starting at row 3***/(exp(-0.0008*time_bin[3])))-(NCP/(exp(-0.0008*time_bin[2])))),
row4 = sum((NCP***Starting at row 4***/(exp(-0.0008*time_bin[4])))-(NCP/(exp(-0.0008*time_bin[3])))),
row5 = sum((NCP***Starting at row 5***/(exp(-0.0008*time_bin[5])))-(NCP/(exp(-0.0008*time_bin[4]))))
  

Спасибо всем!

Комментарии:

1. Является ли вторая ссылка на NCP в каждом вычислении целым вектором или тем же подмножеством, что и первая ссылка на NCP ?

2. Привет, извините, может быть, не самое четкое объяснение, начиная со строки 2, я имею в виду NCP суммы, исключая значения из NCP row1, вторая ссылка на NCP также исключит row1, затем row3 исключит значения row1 и row2 и т. Д

Ответ №1:

Попробуй это:

 len <- nrow(df)
df$out2 <- mapply(
  function(i, tb, tblag) sum(df$NCP[i:len]/tb - df$NCP[i:len]/tblag),
  seq_len(len), exp(-0.0008 * df$time_bin), exp(-0.0008 * c(0, df$time_bin[-len])))
df
#        NCP time_bin    output      out2
# 1 96.05656      100 14.012210 14.012210
# 2 16.94332      200  6.512659  6.512659
# 3 19.88449      300  5.399068  5.399068
# 4 17.74201      400  3.743398  3.743398
# 5 17.61355      500  2.020220  2.020220
  

Если вы хотите, чтобы это было в одном calc (векторизованном) вместо использования mapply :

 len <- nrow(df)
e <- exp(-0.0008 * c(0, df$time_bin))
o <- outer(df$NCP, e[-1], `/`) - outer(df$NCP, e[-(len 1)], `/`)
df$out3 <- colSums(replace(o, upper.tri(o), 0))
df
#        NCP time_bin    output      out2      out3
# 1 96.05656      100 14.012210 14.012210 14.012210
# 2 16.94332      200  6.512659  6.512659  6.512659
# 3 19.88449      300  5.399068  5.399068  5.399068
# 4 17.74201      400  3.743398  3.743398  3.743398
# 5 17.61355      500  2.020220  2.020220  2.020220
  

(С этим образцом данных это немного быстрее, чем с другими, но не настолько, чтобы меня беспокоил бенчмарк.)

Сквозной:

  • нам не нужно пересчитывать exp(-0.0008 * time_bin) для каждого из них и его задержки, поэтому выполнение этого один раз и последующая обработка задержки эффективны, следовательно

     e <- exp(-0.0008 * c(0, df$time_bin))
    ### verifying equality
    exp(-0.0008 * df$time_bin)
    # [1] 0.9231163 0.8521438 0.7866279 0.7261490 0.6703200
    e[-1]
    # [1] 0.9231163 0.8521438 0.7866279 0.7261490 0.6703200
    exp(-0.0008 * c(0, df$time_bin[-len]))
    # [1] 1.0000000 0.9231163 0.8521438 0.7866279 0.7261490
    e[-(len 1)]
    # [1] 1.0000000 0.9231163 0.8521438 0.7866279 0.7261490
      
  • на самом деле немного быстрее (я думаю) вычислить для всех NCP и отбросить, поскольку операции деления и вычитания также выполняются довольно быстро. outer Функция берет два вектора и разворачивает их в матрицу (столько строк, сколько length(vec1) , столько столбцов, сколько length(vec2) , применяя функцию к каждой паре. В этом случае мы разделим их, так что

     outer(df$NCP, e[-1], `/`)
    #           [,1]      [,2]      [,3]      [,4]      [,5]
    # [1,] 104.05683 112.72341 122.11182 132.28215 143.29954
    # [2,]  18.35448  19.88317  21.53918  23.33312  25.27647
    # [3,]  21.54061  23.33467  25.27814  27.38349  29.66418
    # [4,]  19.21969  20.82044  22.55451  24.43301  26.46797
    # [5,]  19.08053  20.66969  22.39121  24.25611  26.27633
    o <- outer(df$NCP, e[-1], `/`) - outer(df$NCP, e[-(len 1)], `/`)
    o
    #          [,1]     [,2]     [,3]      [,4]      [,5]
    # [1,] 8.000269 8.666588 9.388403 10.170335 11.017392
    # [2,] 1.411160 1.528691 1.656011  1.793936  1.943347
    # [3,] 1.656121 1.794054 1.943476  2.105342  2.280690
    # [4,] 1.477680 1.600752 1.734073  1.878499  2.034954
    # [5,] 1.466981 1.589162 1.721518  1.864898  2.020220
      
  • в общем, нам нужны суммы столбцов, но поскольку вы хотите, чтобы второе значение начиналось со второго NCP , мы отбрасываем первое значение во втором столбце, первые два значения в третьем столбце и т.д. К счастью, мы можем использовать upper.tri() , чтобы сократить это:

     upper.tri(o)
    #       [,1]  [,2]  [,3]  [,4]  [,5]
    # [1,] FALSE  TRUE  TRUE  TRUE  TRUE
    # [2,] FALSE FALSE  TRUE  TRUE  TRUE
    # [3,] FALSE FALSE FALSE  TRUE  TRUE
    # [4,] FALSE FALSE FALSE FALSE  TRUE
    # [5,] FALSE FALSE FALSE FALSE FALSE
    replace(o, upper.tri(o), 0)
    #          [,1]     [,2]     [,3]     [,4]    [,5]
    # [1,] 8.000269 0.000000 0.000000 0.000000 0.00000
    # [2,] 1.411160 1.528691 0.000000 0.000000 0.00000
    # [3,] 1.656121 1.794054 1.943476 0.000000 0.00000
    # [4,] 1.477680 1.600752 1.734073 1.878499 0.00000
    # [5,] 1.466981 1.589162 1.721518 1.864898 2.02022
    colSums(replace(o, upper.tri(o), 0))
    # [1] 14.012210  6.512659  5.399068  3.743398  2.020220
      

удобный для dplyr подход к группировке:

 func <- function(ncp, i, tb, tblag) sum(ncp[i:length(ncp)]/tb - ncp[i:length(ncp)]/tblag)

df2 <- bind_rows(df, df, .id = "grp")
df2
#    grp   NCP time_bin output
# 1    1 96.06      100 14.012
# 2    1 16.94      200  6.513
# 3    1 19.88      300  5.399
# 4    1 17.74      400  3.743
# 5    1 17.61      500  2.020
# 6    2 96.06      100 14.012
# 7    2 16.94      200  6.513
# 8    2 19.88      300  5.399
# 9    2 17.74      400  3.743
# 10   2 17.61      500  2.020

df2 %>%
  group_by(grp) %>%
  mutate(out2 = mapply(func, list(NCP), row_number(), exp(-0.0008 * time_bin), exp(-0.0008 * lag(time_bin, default = 0)))) %>%
  ungroup()
# # A tibble: 10 x 5
#    grp     NCP time_bin output  out2
#    <chr> <dbl>    <dbl>  <dbl> <dbl>
#  1 1      96.1      100  14.0  14.0 
#  2 1      16.9      200   6.51  6.51
#  3 1      19.9      300   5.40  5.40
#  4 1      17.7      400   3.74  3.74
#  5 1      17.6      500   2.02  2.02
#  6 2      96.1      100  14.0  14.0 
#  7 2      16.9      200   6.51  6.51
#  8 2      19.9      300   5.40  5.40
#  9 2      17.7      400   3.74  3.74
# 10 2      17.6      500   2.02  2.02
  

Или с помощью purrr :

 df2 %>%
  group_by(grp) %>%
  mutate(out2 = pmap_dbl(list(list(NCP), row_number(), exp(-0.0008 * time_bin), exp(-0.0008 * lag(time_bin, default = 0))), func)) %>%
  ungroup()
  

Комментарии:

1. Прошу прощения за медленный ответ, это идеально. Спасибо!

2. Привет, я не уверен, что это действительно должен быть отдельный вопрос, но есть ли способ применить это к сгруппированным данным, чтобы он выполнялся отдельно для каждой группы? Я пытался использовать pmap, но не очень далеко продвинулся, подход tidyverse был бы отличным, если это возможно.