rdataframetime-series

Make a time series (ts) object using day of year


I am attempting to run a Seasonal Kendall trend test using the R package wql. In order to run the seaKen function, the time series needs to be a ts object. The example I am working with involves a three-year time series with one value per day (i.e., three data points for each day of the year). The Seasonal Kendall analysis runs, but all the slope estimates are returned as NA and the p-values as NaN. I believe the issue may be related to how I'm converting the data frame from daily observations into a ts object. Any guidance on how to create a ts object using the day of the year?

library(tidyverse)
library(wql)
#> 
#> Attaching package: 'wql'
#> The following object is masked from 'package:lubridate':
#> 
#>     years

set.seed(333)

# Example time series
df <- data.frame(
  date = seq(as.Date('2021-01-01'),
             as.Date('2023-12-31'),
             '1 day'),
  value = round(rnorm(1095, 100, 50))
)

# Data wrangling
df <- df |> 
  mutate(season = yday(date),
         year = lubridate::year(date)) |>
  select(!date) |> 
  pivot_wider(
    names_from = season,
    values_from = value
  )

head(df)
#> # A tibble: 3 × 366
#>    year   `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`  `12`
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1  2021    96   197    -3   114    24    87   162   132   118    72    44    56
#> 2  2022    23   140    97   151   191   151   107   105    55   140   -17   123
#> 3  2023   153    66   164    33    -9   150    56    68    52    66    48    46
#> # ℹ 353 more variables: `13` <dbl>, `14` <dbl>, `15` <dbl>, `16` <dbl>, …

# Create the ts object
df_matrix <- as.matrix(df[, -1])

ts_data <- ts(df_matrix,
              start = 1,
              deltat = 1/365)

row.names(ts_data) <- c(2021, 2022, 2023)

str(ts_data)
#>  Time-Series [1:3, 1:365] from 1 to 1.01: 96 23 153 197 140 66 -3 97 164 114 ...
#>  - attr(*, "dimnames")=List of 2
#>   ..$ : chr [1:3] "2021" "2022" "2023"
#>   ..$ : chr [1:365] "1" "2" "3" "4" ...

head(ts_data)
#>        1   2   3   4   5   6   7   8   9  10  11  12  13 14  15  16  17  18  19
#> 2021  96 197  -3 114  24  87 162 132 118  72  44  56 102 71  59 106 118 103 168
#> 2022  23 140  97 151 191 151 107 105  55 140 -17 123 186 90  93 219 159  62 125
#> 2023 153  66 164  33  -9 150  56  68  52  66  48  46  15 81 112 119 129  86 169

# Run seasonal kendall analysis
sk_trend <- seaKen(ts_data)

head(sk_trend)
#>   sen.slope sen.slope.rel p.value  miss
#> 1        NA            NA     NaN 0.992
#> 2        NA            NA     NaN 0.992
#> 3        NA            NA     NaN 0.992
#> 4        NA            NA     NaN 0.992
#> 5        NA            NA     NaN 0.992
#> 6        NA            NA     NaN 0.992

Created on 2025-06-20 with reprex v2.1.1


Solution

  • Turns out there is no need to make the data frame a matrix prior to converting to a ts object. Also, the seasonTrend function is needed to see the associated trend results for each "season".

    library(tidyverse)
    library(wql)
    #> 
    #> Attaching package: 'wql'
    #> The following object is masked from 'package:lubridate':
    #> 
    #>     years
    
    # Example time series ----
    set.seed(333)
    
    df <- data.frame(
      date = seq(as.Date("2021-01-01"), as.Date("2023-12-31"), "1 day"),
      value = round(rnorm(1095, 100, 50))
    )
    
    head(df)
    #>         date value
    #> 1 2021-01-01    96
    #> 2 2021-01-02   197
    #> 3 2021-01-03    -3
    #> 4 2021-01-04   114
    #> 5 2021-01-05    24
    #> 6 2021-01-06    87
    
    # Convert time series to ts object ----
    ts_data <- ts(
      df[, 2],
      start = 2021,
      frequency = 365
    )
    
    ts_data
    #> Time Series:
    #> Start = c(2021, 1) 
    #> End = c(2023, 365) 
    #> Frequency = 365 
    #>    [1]  96 197  -3 114  24  87 162 132 118  72  44  56 102  71  59 106 118 103
    
    # Run seasonal trend test ----
    sk_trend <- seasonTrend(ts_data, plot = F, type = "slope")
    
    head(sk_trend)
    #>   season sen.slope sen.slope.rel p.value miss
    #> 1      1      28.5     0.2968750   1.000    0
    #> 2      2     -65.5    -0.3324873   0.334    0
    #> 3      3      83.5   -27.8333333   0.334    0
    #> 4      4     -40.5    -0.3552632   1.000    0
    #> 5      5     -16.5    -0.6875000   1.000    0
    #> 6      6      31.5     0.3620690   1.000    0
    

    Created on 2025-06-23 with reprex v2.1.1