Обрезать фрейм данных сверху или снизу в зависимости от столбца с NA

У меня есть фрейм данных, похожий на final_df ниже, который я получаю следующим образом:

datadf <- data.frame(time=1:100, A=rnorm(100), B=rnorm(100), C=rnorm(100))
datadf <- as.data.frame(tidyr::pivot_longer(datadf, -time, names_to = "letter", values_to = "value"))
calldf <- data.frame(call=sample(LETTERS[1:3], 10, replace=T),
                     time=seq(from=5, by=9, length=10),
                     callnum=1:10, callnum_rev=10:1)
final_df <- dplyr::left_join(datadf, calldf, by = "time")

И это выглядит так:

> final_df
    time letter        value call callnum callnum_rev
1      1      A  0.008684912 <NA>      NA          NA
2      1      B -0.229217147 <NA>      NA          NA
3      1      C  1.675954809 <NA>      NA          NA
4      2      A  0.011244567 <NA>      NA          NA
5      2      B  0.593363139 <NA>      NA          NA
6      2      C -1.124759422 <NA>      NA          NA
7      3      A  0.271118167 <NA>      NA          NA
8      3      B  1.768275352 <NA>      NA          NA
9      3      C  0.287273528 <NA>      NA          NA
10     4      A  1.083097563 <NA>      NA          NA
11     4      B  1.990573158 <NA>      NA          NA
12     4      C -0.953178506 <NA>      NA          NA
13     5      A -0.076200582    A       1          10
14     5      B  1.159319799    A       1          10
15     5      C -0.484462797    A       1          10
16     6      A  0.506393522 <NA>      NA          NA
17     6      B -0.847847907 <NA>      NA          NA
18     6      C -0.429095586 <NA>      NA          NA
19     7      A -0.591182884 <NA>      NA          NA
20     7      B  0.996488879 <NA>      NA          NA
...

Единственное, что я хочу сделать, это иметь возможность обрезать n верхние строки и/или n нижние строки в соответствии с переменными callnum (считается сверху) и/или callnum_rev (считается снизу).

Некоторые примеры:

  • Скажем, я передаю значение для top=3. Я хотел бы, чтобы результирующий фрейм данных начинался с первой строки, где callnum == 3 (строка 67), и до самого конца.

  • Скажем, я передаю значение для дна = 4. Я бы хотел, чтобы результирующий фрейм данных начинался сверху и доходил до последней строки, где callnum_rev == 4 (строка 177).

  • Скажем, я передаю как значение top=3, так и значение low=4. Я хотел бы, чтобы результирующий фрейм данных переместился из строки 67 в строку 177.

На самом деле было бы лучше всего оставить некоторое количество строк NA над верхней строкой и количество строк NA под нижней строкой, чтобы это количество составляло половину строк NA между этим значением и предыдущим/следующим.

В данном случае это просто, потому что я всегда оставляю 8 строк NA между двумя значениями вызова (seq на 9)... Итак, в примере значения для верхнего = 3 и значения для нижнего = 4 мне бы хотелось, чтобы мой результат фрейм данных для перехода от строки 55 (67-12, 12=8/23, как в 3-х буквах) к строке 189 (177+12, 12=8/23, как в 3-х буквах).

Это может оказаться запутанным, потому что в моих реальных данных строки со значениями callnum могут иметь переменное количество строк NA между ними.

Любая помощь?


1
53
1

Ответ:

Решено
head_tail <- function(data, top=NULL, bottom=NULL) {
    if (!is.null(top)) 
      s1 <- min(which(data[,'callnum']==top))
    else
      s1 <- 1
    
    if (!is.null(bottom))
      s2 <- max(which(data[,'callnum_rev']==bottom))
    else
      s2 <- nrow(data)

    return(data[seq(s1, s2),])
}

library(data.table)
final_dt <- setDT(final_df)

head_tail(final_dt, top=3)

      time letter       value   call callnum callnum_rev
     <num> <char>       <num> <char>   <int>       <int>
  1:    23      A -1.15224027      A       3           8
  2:    23      B -0.22485125      A       3           8
  3:    23      C -0.36342374      A       3           8
  4:    24      A  0.65140424   <NA>      NA          NA
  5:    24      B  0.07724828   <NA>      NA          NA
 ---                                                    
230:    99      B -1.13818328   <NA>      NA          NA
231:    99      C -0.00105447   <NA>      NA          NA
232:   100      A  0.41389275   <NA>      NA          NA
233:   100      B -2.48077559   <NA>      NA          NA
234:   100      C  1.32573054   <NA>      NA          NA

head_tail(final_dt, bottom=4)

      time letter      value   call callnum callnum_rev
     <num> <char>      <num> <char>   <int>       <int>
  1:     1      A -0.8785872   <NA>      NA          NA
  2:     1      B  0.6806222   <NA>      NA          NA
  3:     1      C  1.5115759   <NA>      NA          NA
  4:     2      A -0.9589247   <NA>      NA          NA
  5:     2      B -0.7238646   <NA>      NA          NA
 ---                                                   
173:    58      B -0.3192178   <NA>      NA          NA
174:    58      C  1.4266444   <NA>      NA          NA
175:    59      A -2.1541144      A       7           4
176:    59      B -0.4405924      A       7           4
177:    59      C  0.2283863      A       7           4

head_tail(final_dt, top=3, bottom=4)

      time letter       value   call callnum callnum_rev
     <num> <char>       <num> <char>   <int>       <int>
  1:    23      A -1.15224027      A       3           8
  2:    23      B -0.22485125      A       3           8
  3:    23      C -0.36342374      A       3           8
  4:    24      A  0.65140424   <NA>      NA          NA
  5:    24      B  0.07724828   <NA>      NA          NA
 ---                                                    
107:    58      B -0.31921775   <NA>      NA          NA
108:    58      C  1.42664445   <NA>      NA          NA
109:    59      A -2.15411443      A       7           4
110:    59      B -0.44059240      A       7           4
111:    59      C  0.22838630      A       7           4