-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
14 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"hash": "0c7a92cf7e0db38fdefb25315df58884", | ||
"result": { | ||
"markdown": "---\ntitle: \"Modeling each month\"\ncache: true\n---\n\n\nHere we modify our first modeling workflow to produce a model for each month. In the [previous workflow](modeling-01.qmd) we produced one model covering observations covering all times; we then applied the model to the various months. \n\n## Load data\n\nHere we load the observation and background data points. We add a column identifying the month of the year. \n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-1_e35d59038fe3799ba4e644ab0d67b2d0'}\n\n```{.r .cell-code}\nsource(\"setup.R\")\nobs = sf::read_sf(file.path(\"data\", \"obs\", \"obs-covariates.gpkg\")) |>\n sf::st_set_geometry(\"geometry\") |>\n dplyr::mutate(month = factor(format(month_id, \"%b\"), levels = month.abb), \n .before = geometry)\nbkg = sf::read_sf(file.path(\"data\", \"bkg\", \"bkg-covariates.gpkg\")) |>\n sf::st_set_geometry(\"geometry\") |>\n dplyr::mutate(month = factor(format(month_id, \"%b\"), levels = month.abb), \n .before = geometry)\n```\n:::\n\n\n## Do we model every month?\n\nLet's do a quick check by counting each by month. Note that we drop the spatial info so that we can make simply tallies.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-2_80a187bb1c38cbffb49e1feee10e7252'}\n\n```{.r .cell-code}\ncounts = sf::st_drop_geometry(obs) |> \n dplyr::count(month, name = \"n_obs\") |>\n dplyr::left_join(sf::st_drop_geometry(bkg) |> dplyr::count(month, name = \"n_bkg\"), \n by = 'month') |>\n print(n = 12)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n# A tibble: 12 × 3\n month n_obs n_bkg\n <fct> <int> <int>\n 1 Jan 33 51\n 2 Feb 40 57\n 3 Mar 50 79\n 4 Apr 341 528\n 5 May 541 943\n 6 Jun 2137 3471\n 7 Jul 2108 3233\n 8 Aug 1698 2597\n 9 Sep 725 1205\n10 Oct 328 485\n11 Nov 494 739\n12 Dec 66 90\n```\n:::\n:::\n\n\nSo the colder months have fewer observations than the warmer months. We already knew that, but it will be interesting to see how that manifests itself in the models.\n\n### Build the monthly models\n\nSince we are building 12 models (rather than one) it is useful to create a function that computes a model for any month, and then iterate through the months of the year.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-3_14408e426c7c9e84885d104d1381d64b'}\n\n```{.r .cell-code}\n# A function for making one month's model\n#\n# @param tbl a data frame of one month's observations\n# @param key a data frame that holds the current iteration's month name\n# @param bkg a complete data frame of background data (which we filter for the given month)\n# @param path the path where the model is saved\n# @return a model, which is also saved in \"data/model/v2/v2.<monthname>\"\nmodel_month = function(tbl, key, bkg = NULL, path = \".\"){\n \n bkg = bkg |>\n dplyr::filter(month == key$month) |>\n sf::st_drop_geometry() |>\n dplyr::select(dplyr::all_of(c(\"sst\", \"u_wind\", \"v_wind\"))) |>\n na.omit()\n \n obs = tbl |>\n sf::st_drop_geometry() |>\n dplyr::select(dplyr::all_of(c(\"sst\", \"u_wind\", \"v_wind\"))) |>\n na.omit()\n \n # these are the predictor variables row bound\n x = dplyr::bind_rows(obs, bkg)\n \n # and the flag indicating presence/background\n flag = c(rep(1, nrow(obs)), rep(0, nrow(bkg)))\n \n model_path = file.path(path, paste0(\"v2.\", key$month, \".rds\"))\n\n model = maxnet::maxnet(flag, x) |>\n maxnetic::write_maxnet(model_path)\n \n model\n}\n\npath = file.path(\"data\", \"model\", \"v2\")\nok = dir.create(path, recursive = TRUE, showWarnings = FALSE)\nmodels = obs |>\n dplyr::group_by(month) |>\n dplyr::group_map(model_month, bkg = bkg, path = path) |>\n rlang::set_names(levels(obs$month))\n```\n:::\n\n\nWe can look at the response plots for every month, but for demonstration purposes, we'll just show one month. It is interesting to compare this respinse to that for the [basic model](modeling-01.qmd).\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-4_56127f4832cd034c70d9efb8b0100319'}\n\n```{.r .cell-code}\nplot(models[['Jun']], type = 'cloglog')\n```\n\n::: {.cell-output-display}\n![](modeling-02_files/figure-html/unnamed-chunk-4-1.png){width=672}\n:::\n:::\n\n\n## Predict with rasters\nFirst we load the raster databases as these are lightweight to pass into a function that iterates through the months.\n\n### Load the raster databases (`sst` and `u_wind` and `v_wind`)\n\nWe also make sure they are in date order and add a \"month\" variable to each.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-5_aec22c8734e04228e9c12ddd7dbebd94'}\n\n```{.r .cell-code}\nsst_path = \"data/oisst\"\nsst_db = oisster::read_database(sst_path) |>\n dplyr::arrange(date) |>\n dplyr::mutate(month = format(date, \"%b\"))\n \n\nwind_path = \"data/nbs\"\nwind_db = nbs::read_database(wind_path) |>\n dplyr::arrange(date)|>\n dplyr::mutate(month = format(date, \"%b\"))\n\nu_wind_db = wind_db |>\n dplyr::filter(param == \"u_wind\")\n\nv_wind_db = wind_db |>\n dplyr::filter(param == \"v_wind\")\n```\n:::\n\n\n### Iterate through the months making predictions\nNow we can build an iterator function that will make a prediction for each month. Let's narrow our predictions to just those for a particular year, 2019, and read the rasters in all at once.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-6_c05a1ac68684d54c6ff8b072d57654ad'}\n\n```{.r .cell-code}\ndates = as.Date(c(\"2019-01-01\", \"2019-12-31\"))\nx = read_predictors(\n sst_db = dplyr::filter(sst_db, dplyr::between(date, dates[1], dates[2])),\n u_wind_db = dplyr::filter(u_wind_db, dplyr::between(date, dates[1], dates[2])),\n v_wind_db = dplyr::filter(v_wind_db, dplyr::between(date, dates[1], dates[2]))\n)\n```\n:::\n\n\nNow we can iterate through the months.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-7_88b6e121185be4feda4a2f5f5d3eb399'}\n\n```{.r .cell-code}\ndate_sequence = seq(from = dates[1], to = dates[2], by = \"month\")\npred_rasters = lapply(names(models),\n function(mon){\n ix = which(month.abb %in% mon)\n predict(models[[mon]], dplyr::slice(x, time, ix, drop), type = \"cloglog\")\n }) \npred_rasters = do.call(c, append(pred_rasters, list(along = list(time = date_sequence))))\n```\n:::\n\n\nLet's plot them.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-8_004777e1101dedbce37699ae5d54f4c2'}\n\n```{.r .cell-code}\ncoast = rnaturalearth::ne_coastline(scale = 'large', returnclass = 'sf') |>\n sf::st_geometry() |>\n sf::st_crop(pred_rasters)\n\nplot_coast = function() {\n plot(coast, col = 'green', add = TRUE)\n}\nplot(pred_rasters, hook = plot_coast)\n```\n\n::: {.cell-output-display}\n![](modeling-02_files/figure-html/unnamed-chunk-8-1.png){width=672}\n:::\n:::\n\n\nLet's see what we can discern from the predict abilities. We can extract the predicted values at the observed locations. Having those in hand allows us to compute pAUC for each month.\n\n\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-9_a7e317262834717357a0fd9d3b7b9f20'}\n\n```{.r .cell-code}\npred_obs = stars::st_extract(pred_rasters, \n dplyr::filter(obs, dplyr::between(date, dates[1], dates[2])),\n time_column = \"month_id\") |>\n dplyr::mutate(month = factor(format(month_id, \"%b\"), levels = month.abb)) |>\n dplyr::group_by(month)\n\npaucs = dplyr::group_map(pred_obs,\n function(x, y) {\n ix = month.abb %in% y$month\n s = dplyr::slice(pred_rasters, \"time\", ix)\n pauc = maxnetic::pAUC(s,x)\n dplyr::tibble(month = y$month, \n auc = pauc$area,\n pauc = list(pauc))\n })|>\n dplyr::bind_rows() |>\n print(n = 12)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n# A tibble: 12 × 3\n month auc pauc \n <fct> <dbl> <list> \n 1 Jan 0.703 <pAUC [3]>\n 2 Feb 0.689 <pAUC [3]>\n 3 Mar 0.698 <pAUC [3]>\n 4 Apr 0.677 <pAUC [3]>\n 5 May 0.654 <pAUC [3]>\n 6 Jun 0.662 <pAUC [3]>\n 7 Jul 0.665 <pAUC [3]>\n 8 Aug 0.696 <pAUC [3]>\n 9 Sep 0.663 <pAUC [3]>\n10 Oct 0.633 <pAUC [3]>\n11 Nov 0.627 <pAUC [3]>\n12 Dec 0.665 <pAUC [3]>\n```\n:::\n:::\n\n\nNote that last element, `pauc`, is the result returned by the `maxnetic::pAUC()` function which we can plot.\n\n\n::: {.cell hash='modeling-02_cache/html/unnamed-chunk-10_d4439b1d52a25443e93dea2dfb9413f1'}\n\n```{.r .cell-code}\npp = paucs |>\n dplyr::group_by(month) |>\n dplyr::group_map(\n function(tbl, key){\n plot(tbl$pauc[[1]], title = key$month, xlab = \"\", ylab = \"\")\n }\n )\npatchwork::wrap_plots(pp, ncol = 4)\n```\n\n::: {.cell-output-display}\n![](modeling-02_files/figure-html/unnamed-chunk-10-1.png){width=672}\n:::\n:::\n\n\nWell, it would be easy to become dispirited by this result. It would be reasonable to expect AUC values to improve if we built monthly models rather than a single model applied to any month. But it seems to not be the dramatic improvement hoped for. Darn!", | ||
"supporting": [], | ||
"filters": [ | ||
"rmarkdown/pagebreak.lua" | ||
], | ||
"includes": {}, | ||
"engineDependencies": {}, | ||
"preserve": {}, | ||
"postProcess": true | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.