6

I have the following data

library(tidyr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(data.table)
#> 
#> Attaching package: 'data.table'
#> The following objects are masked from 'package:dplyr':
#> 
#>     between, first, last

df <- structure(list(filename = c("PS92_019-6_rovT_irrad.tab", "PS92_019-6_rovT_irrad.tab", 
  "PS92_019-6_rovT_irrad.tab", "PS92_019-6_rovT_irrad.tab"), depth = c(5, 
  10, 20, 75), ps = c(3.26223404971255, 3.38947945477306, 3.97380593851983, 
  0.428074807655144)), row.names = c(NA, -4L), class = c("tbl_df", "tbl", 
  "data.frame"), .Names = c("filename", "depth", "ps"))

df
#> # A tibble: 4 x 3
#>                    filename depth        ps
#>                       <chr> <dbl>     <dbl>
#> 1 PS92_019-6_rovT_irrad.tab     5 3.2622340
#> 2 PS92_019-6_rovT_irrad.tab    10 3.3894795
#> 3 PS92_019-6_rovT_irrad.tab    20 3.9738059
#> 4 PS92_019-6_rovT_irrad.tab    75 0.4280748

In this data, there is a missing observation at depth = 0. Using tidyr, I can complete it with:

df %>% tidyr::complete(depth = c(0, unique(depth))) %>% fill(everything(), .direction = "up")  ## use the last observations to fill the new line
#> # A tibble: 5 x 3
#>   depth                  filename        ps
#>   <dbl>                     <chr>     <dbl>
#> 1     0 PS92_019-6_rovT_irrad.tab 3.2622340
#> 2     5 PS92_019-6_rovT_irrad.tab 3.2622340
#> 3    10 PS92_019-6_rovT_irrad.tab 3.3894795
#> 4    20 PS92_019-6_rovT_irrad.tab 3.9738059
#> 5    75 PS92_019-6_rovT_irrad.tab 0.4280748

The problem is that I have to run this on a large dataset and I found that the complete/fill functions are a bit slow. Thus, I wanted to give it a go with data.table to see if it can speed up things. However I can't get my head around it. Any help appreciated.

Jaap
  • 81,064
  • 34
  • 182
  • 193
Philippe Massicotte
  • 1,321
  • 12
  • 24

1 Answers1

7

There is no specific function for it, but you can achieve the same with:

# load package
library(data.table)

# convert to a 'data.table'
setDT(df)

# expand and fill the dataset with a rolling join
df[.(c(0, depth)), on = .(depth), roll = -Inf]

which gives:

                    filename depth        ps
1: PS92_019-6_rovT_irrad.tab     0 3.2622340
2: PS92_019-6_rovT_irrad.tab     5 3.2622340
3: PS92_019-6_rovT_irrad.tab    10 3.3894795
4: PS92_019-6_rovT_irrad.tab    20 3.9738059
5: PS92_019-6_rovT_irrad.tab    75 0.4280748

Heads up to @Frank for the improvement suggestion.


Old solution:

df[CJ(depth = c(0,unique(depth))), on = 'depth'
   ][, c(1,3) := lapply(.SD, zoo::na.locf, fromLast = TRUE), .SDcols = c(1,3)][]
Jaap
  • 81,064
  • 34
  • 182
  • 193
  • 2
    thx for answer. how to add `group_by` to this case? if I have few `filename` with different number of rows? – jyjek Jul 01 '19 at 08:49