<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>R DELİSİ</title>
<link>https://r-delisi.github.io/en/</link>
<atom:link href="https://r-delisi.github.io/en/index.xml" rel="self" type="application/rss+xml"/>
<description>Open and Reproducible Science</description>
<language>en</language>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Wed, 02 Sep 2026 21:00:00 GMT</lastBuildDate>
<item>
  <title>Modelling Monthly Soil Surface Water Content over MODIS Tile h18v03</title>
  <dc:creator>Mehmet Göktuğ Öztürk</dc:creator>
  <link>https://r-delisi.github.io/en/posts/2026-09-03-soil-moisture-modelling/</link>
  <description><![CDATA[ 




<p>Hello, and welcome to my first blog post in English!</p>
<p>I have already been writing a Turkish blog about R, ecology, and spatial data science, and for a while I have been thinking about starting an English version as well.</p>
<p>Finally, here we are. :)</p>
<p>This post is about a hackathon.</p>
<p>Three weeks ago, we attended the <a href="https://opengeohub.org/">OpenGeoHub Foundation</a> Earth Observation Summer School 2026 at Istanbul Technical University in İstanbul. It was a wonderful experience once again — I also attended the summer school in Poznań in 2023.</p>
<p>As part of the summer school, we had to complete a hackathon project. I selected the topic <a href="https://www.kaggle.com/competitions/modeling-monthly-soil-surface-water-content">Modelling Monthly Soil Surface Water Content over MODIS Tile h18v03</a> and, fortunately, managed to finish it.</p>
<p>My submission was not the top-ranked one, and I think there are some issues with the modelling approach. Still, I wanted to share it here, discuss what worked and what did not, and reflect on what I would improve next time. I have also made a few changes to the original notebook for this blog post.</p>
<p>I am still developing my experience with spatial machine-learning workflows, so I do not consider this analysis a definitive solution. There may be aspects of the modelling and validation strategy that could be improved. I would therefore be very interested in comments, alternative approaches, and suggestions from readers with more experience in this area.</p>
<p>Enjoy the read!</p>
<section id="introduction" class="level1">
<h1>Introduction</h1>
<p>Soil moisture in the uppermost soil layer mediates infiltration, evapotranspiration and runoff, and it responds quickly to rainfall and to the atmospheric demand for water. Mapping how it varies from month to month is valuable for a range of environmental applications, but direct measurements are sparse in space. A common strategy is to learn a statistical relationship between in-situ measurements and spatially exhaustive covariates — satellite imagery, and climate reanalysis — and then to apply that relationship where no measurements exist <span class="citation" data-cites="hengl2018rf">(Hengl et al. 2018)</span>.</p>
<p>The objective here is to predict monthly soil surface water content, denoted <code>sswc_m</code>, for a set of stations on MODIS tile h18v03. The model quality is judged by the root-mean-square error (<img src="https://latex.codecogs.com/png.latex?RMSE">) on the hidden test stations.</p>
</section>
<section id="data" class="level1">
<h1>Data</h1>
<section id="station-observations" class="level2">
<h2 class="anchored" data-anchor-id="station-observations">Station observations</h2>
<p>The training and test tables share the same structure. Each row is one station-month and carries the station coordinates (<code>x</code>, <code>y</code>), a set of MODIS-derived predictors, and a year-month label (<code>YEARMON</code>). The training table additionally contains the response <code>sswc_m</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dplyr"</span>)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tidyr"</span>)</span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tidymodels"</span>)</span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"terra"</span>)</span>
<span id="cb1-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sf"</span>)</span>
<span id="cb1-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ecmwfr"</span>)</span>
<span id="cb1-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span>)</span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"patchwork"</span>)</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidymodels_prefer</span>()</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Options</span></span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scipen=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">999</span>)</span>
<span id="cb2-3">ggplot2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(ggplot2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_bw</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Inter"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>))</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read.csv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/input/train.csv"</span>)</span>
<span id="cb3-2">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> train[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(train) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"X"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unnamed..0"</span>)]</span>
<span id="cb3-3">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names&lt;-</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>(train, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tolower</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(train)))</span>
<span id="cb3-4"></span>
<span id="cb3-5">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read.csv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/input/test.csv"</span>)</span>
<span id="cb3-6">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> test[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(test) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"X"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"row_id"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cluster"</span>)]</span>
<span id="cb3-7">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names&lt;-</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>(test, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tolower</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(test)))</span>
<span id="cb3-8"></span>
<span id="cb3-9">prep_features <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(df) {</span>
<span id="cb3-10">    df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>year <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">substr</span>(df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>yearmon, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb3-11">    df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>month <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">substr</span>(df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>yearmon, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>))</span>
<span id="cb3-12">    df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>month_sin <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pi <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>month <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb3-13">    df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>month_cos <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cos</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pi <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>month <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb3-14">    df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>loc_id <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste</span>(df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x, df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sep=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>)</span>
<span id="cb3-15">    </span>
<span id="cb3-16">    df</span>
<span id="cb3-17">}</span>
<span id="cb3-18"></span>
<span id="cb3-19">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep_features</span>(train)</span>
<span id="cb3-20">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep_features</span>(test)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(train)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>'data.frame':   154594 obs. of  15 variables:
 $ x        : num  192611 192611 192611 192611 192611 ...
 $ y        : num  5685001 5685001 5685001 5685001 5685001 ...
 $ dlst     : num  2796 2762 2790 2853 2918 ...
 $ dlst.95  : num  2822 2768 2797 2900 2943 ...
 $ nlst     : num  2744 2737 2745 2749 2799 ...
 $ nlst.95  : num  2759 2772 2764 2786 2815 ...
 $ geom     : int  -31 -51 -37 0 60 121 170 190 178 136 ...
 $ evi      : int  1594 1592 1554 1721 2435 2770 2777 2559 2268 2585 ...
 $ sswc_m   : num  133 123 122 104 121 ...
 $ yearmon  : chr  "2005-12" "2006-01" "2006-02" "2006-03" ...
 $ year     : int  2005 2006 2006 2006 2006 2006 2006 2006 2006 2006 ...
 $ month    : int  12 1 2 3 4 5 6 7 8 9 ...
 $ month_sin: num  -0.000000000000000245 0.499999999999999944 0.866025403784438597 1 0.866025403784438708 ...
 $ month_cos: num  1 0.8660254037844387076 0.500000000000000111 0.0000000000000000612 -0.499999999999999778 ...
 $ loc_id   : chr  "192610.797746353_5685001.46987854" "192610.797746353_5685001.46987854" "192610.797746353_5685001.46987854" "192610.797746353_5685001.46987854" ...</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(test)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>'data.frame':   73998 obs. of  14 variables:
 $ x        : num  118207 118207 118207 118207 118207 ...
 $ y        : num  5836536 5836536 5836536 5836536 5836536 ...
 $ dlst     : num  2797 2817 2881 2919 2954 ...
 $ dlst.95  : num  2819 2819 2914 2949 2978 ...
 $ nlst     : num  2752 2766 2766 2782 2834 ...
 $ nlst.95  : num  2754 2792 2793 2800 2853 ...
 $ geom     : int  -62 -48 -9 51 113 162 183 171 128 68 ...
 $ evi      : int  2367 2382 2654 3119 3288 3359 3555 3493 3258 3087 ...
 $ yearmon  : chr  "2001-01" "2001-02" "2001-03" "2001-04" ...
 $ year     : int  2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 ...
 $ month    : int  1 2 3 4 5 6 7 8 9 10 ...
 $ month_sin: num  0.5 0.866 1 0.866 0.5 ...
 $ month_cos: num  0.8660254037844387076 0.500000000000000111 0.0000000000000000612 -0.499999999999999778 -0.8660254037844387076 ...
 $ loc_id   : chr  "118206.773972219_5836535.61571117" "118206.773972219_5836535.61571117" "118206.773972219_5836535.61571117" "118206.773972219_5836535.61571117" ...</code></pre>
</div>
</div>
</section>
<section id="era5-land-precipitation-and-soil-moisture" class="level2">
<h2 class="anchored" data-anchor-id="era5-land-precipitation-and-soil-moisture">ERA5-Land precipitation and soil moisture</h2>
<p>ERA5-Land provides hourly and monthly land-surface fields at roughly 9 km resolution from 1950 onward <span class="citation" data-cites="munoz2021era5land">(<span class="nocase">Muñoz-Sabater et al.</span> 2021)</span>, derived from the ERA5 reanalysis <span class="citation" data-cites="hersbach2020era5">(<span class="nocase">Hersbach et al.</span> 2020)</span>. It covers the full 2001–2024 study period, which makes it a natural match for this problem. We retrieve two monthly variables over the tile’s bounding box: total precipitation and volumetric soil water in the top layer (<code>swvl1</code> in <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7Bm%5E3%5C,m%5E%7B-3%7D%7D">, which is closely related to the response variable and provides a physically meaningful predictor). Downloads use the <code>ecmwfr</code> interface to the Copernicus Climate Data Store <span class="citation" data-cites="ecmwfr2023">(Hufkens et al. 2023)</span>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">era_path <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/input/era5land_monthly_2001_2024.nc"</span></span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dir.create</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dirname</span>(era_path), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">showWarnings=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">recursive=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb8-3"></span>
<span id="cb8-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file.exists</span>(era_path)) {</span>
<span id="cb8-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">R_KEYRING_BACKEND=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"env"</span>)</span>
<span id="cb8-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">keyring_backend=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"env"</span>)</span>
<span id="cb8-7">    rc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readLines</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">path.expand</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"~/.cdsapirc"</span>))</span>
<span id="cb8-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wf_set_key</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">key=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">substr</span>(rc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">41</span>))</span>
<span id="cb8-9">    </span>
<span id="cb8-10">    request <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb8-11">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dataset_short_name=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"reanalysis-era5-land-monthly-means"</span>,</span>
<span id="cb8-12">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">product_type=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"monthly_averaged_reanalysis"</span>,</span>
<span id="cb8-13">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variable=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total_precipitation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"volumetric_soil_water_layer_1"</span>),</span>
<span id="cb8-14">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">year=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2001</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>),</span>
<span id="cb8-15">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">month=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%02d"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>),</span>
<span id="cb8-16">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">time=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"00:00"</span>,</span>
<span id="cb8-17">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">area=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">65</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>), <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># N, W, S, E</span></span>
<span id="cb8-18">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data_format=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"netcdf"</span>,</span>
<span id="cb8-19">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">download_format=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unarchived"</span>,</span>
<span id="cb8-20">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basename</span>(era_path)</span>
<span id="cb8-21">    )</span>
<span id="cb8-22">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wf_request</span>(request, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">transfer=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">path=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dirname</span>(era_path), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">time_out=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1800</span>, </span>
<span id="cb8-23">               <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">retry=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">verbose=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb8-24">}</span></code></pre></div></div>
</div>
<p>The reanalysis grid is sampled at every station. Because ERA5-Land is defined on land cells only, coastal stations fall on masked (water) cells and would otherwise return missing values for all months. We snap those stations to the nearest land cell before extracting, which removes the gaps without discarding stations. The previous month’s precipitation is then formed per station as a one-month lag; only the first month of each series (January 2001) is left undefined and is median-imputed later.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">sinu <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs"</span></span>
<span id="cb9-2"></span>
<span id="cb9-3">era5 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(era_path)</span>
<span id="cb9-4"></span>
<span id="cb9-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Unique stations across train and test, projected to the reanalysis CRS</span></span>
<span id="cb9-6">locs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_rows</span>(</span>
<span id="cb9-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(train, loc_id, x, y),</span>
<span id="cb9-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(test, loc_id, x, y)</span>
<span id="cb9-9">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(loc_id, x, y)</span>
<span id="cb9-11">locs_v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(locs, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geom=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs=</span>sinu) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb9-12"></span>
<span id="cb9-13">ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract</span>(era5, locs_v, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ID=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb9-14">ex<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>loc_id <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> locs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>loc_id</span>
<span id="cb9-15"></span>
<span id="cb9-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Snap water-cell stations to the nearest land cell (static land mask)</span></span>
<span id="cb9-17">na_idx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(ex[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swvl1_1"</span>]]))</span>
<span id="cb9-18"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(na_idx) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) {</span>
<span id="cb9-19">    land_xy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xyFromCell</span>(era5, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">values</span>(era5[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mat=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>))))</span>
<span id="cb9-20">    na_ll <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crds</span>(locs_v[na_idx])</span>
<span id="cb9-21">    snap_xy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">t</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapply</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_len</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(na_ll)), <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(i) {</span>
<span id="cb9-22">        d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> (land_xy[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> na_ll[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (land_xy[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> na_ll[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># euclidean distance</span></span>
<span id="cb9-23">        land_xy[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.min</span>(d), ]</span>
<span id="cb9-24">    }, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">numeric</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)))</span>
<span id="cb9-25">    patch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract</span>(era5, snap_xy)</span>
<span id="cb9-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ID"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(patch)) patch<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ID <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb9-27">    </span>
<span id="cb9-28">    ex[na_idx, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(era5)] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> patch[, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(era5)]</span>
<span id="cb9-29">}</span>
<span id="cb9-30"></span>
<span id="cb9-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Reshape to (station, month) and build the one-month precipitation lag</span></span>
<span id="cb9-32">months_seq <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.Date</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2001-01-01"</span>), </span>
<span id="cb9-33">                         <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.Date</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-12-01"</span>), </span>
<span id="cb9-34">                         <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"month"</span>), </span>
<span id="cb9-35">                     <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y-%m"</span>)</span>
<span id="cb9-36">era5_cov <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ex <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-37">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>loc_id, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"layer"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-38">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb9-39">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">var=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sub</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_[0-9]+$"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>, layer), </span>
<span id="cb9-40">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">idx=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sub</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^.*_"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>, layer)), </span>
<span id="cb9-41">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yearmon=</span>months_seq[idx]</span>
<span id="cb9-42">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-43">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(loc_id, yearmon, var, value) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-44">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_wider</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_from=</span>var, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_from=</span>value) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-45">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">era5_precip=</span>tp, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">era5_swvl1=</span>swvl1) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-46">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(loc_id, yearmon) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-47">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(loc_id) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-48">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">era5_precip_lag1=</span>dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lag</span>(era5_precip)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-49">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ungroup</span>()</span>
<span id="cb9-50"></span>
<span id="cb9-51"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">colSums</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(era5_cov))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>          loc_id          yearmon       era5_swvl1      era5_precip 
               0                0                0                0 
era5_precip_lag1 
             915 </code></pre>
</div>
</div>
<p>Before modelling, it is worth checking whether the reanalysis data are temporally aligned with the response. Figure&nbsp;1 compares the seasonal cycles of ERA5-Land top-layer soil water and the response variable. The two series show similar seasonal patterns, providing a useful sanity check for temporal alignment.</p>
<p>The two series are standardized to z-scores to facilitate comparison of their seasonal patterns despite their different scales.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">train2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(era5_cov, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"loc_id"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yearmon"</span>))</span>
<span id="cb11-2"></span>
<span id="cb11-3">train2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">month=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">substr</span>(yearmon, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(month) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sswc_m (target)</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(sswc_m, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">na.rm=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb11-7">              <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ERA5-Land swvl1</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(era5_swvl1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">na.rm=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb11-8">              <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.groups=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"drop"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>month, \(x) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale</span>(x)))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>month, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variable"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(month, z, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span>variable)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-12">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-13">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">breaks=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-15">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Month"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Standardized monthly mean (z-score)"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-era5" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-era5-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://r-delisi.github.io/en/posts/2026-09-03-soil-moisture-modelling/index_files/figure-html/fig-era5-1.png" class="img-fluid figure-img" width="1152">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-era5-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Seasonal cycles of the target soil water content and ERA5-Land top-layer soil water, standardized as z-scores. Their similar seasonal patterns provide a useful sanity check for temporal alignment.
</figcaption>
</figure>
</div>
</div>
</div>
<p>There are missing values in <code>dlst</code>, <code>dlst.95</code>, <code>nlst</code>, <code>nlst.95</code>, and <code>era5_precip_lag1</code> variables. Missing values are median-imputed in the model.</p>
</section>
<section id="exploratory-analysis" class="level2">
<h2 class="anchored" data-anchor-id="exploratory-analysis">Exploratory analysis</h2>
<p>Two patterns stand out and motivate the modelling choices. The left panel of Figure&nbsp;2 shows that the test stations are interspersed among the training stations rather than forming a separate block, so the relevant validation scenario is prediction at scattered new sites within the same region. The right panel shows the seasonal cycle of the response: soil water content is highest in winter and reaches a clear minimum in June–July, when evapotranspiration is greatest. This seasonal signal is strong and smooth, which is why an encoding of the month is included from the outset.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">world <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> maps<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"world"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sf</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_geometry</span>()</span>
<span id="cb12-4"></span>
<span id="cb12-5">all_locs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_rows</span>(</span>
<span id="cb12-6">    train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(loc_id, x, y),</span>
<span id="cb12-7">    test <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(loc_id, x, y)</span>
<span id="cb12-8">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(loc_id, x, y)</span>
<span id="cb12-10"></span>
<span id="cb12-11">loc_sf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sf</span>(all_locs, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coords=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs=</span>sinu)</span>
<span id="cb12-12"></span>
<span id="cb12-13">aoi_sinu <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> loc_sf <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_union</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-15">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_convex_hull</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-16">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_buffer</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30000</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-17">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sf</span>()</span>
<span id="cb12-18"></span>
<span id="cb12-19">aoi_ext <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(aoi_sinu))</span>
<span id="cb12-20"></span>
<span id="cb12-21">bb <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(aoi_ext, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs=</span>sinu) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_bbox</span>()</span>
<span id="cb12-22"></span>
<span id="cb12-23">dt_sf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_rows</span>(</span>
<span id="cb12-24">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(train[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">set=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"train"</span>),</span>
<span id="cb12-25">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(test[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">set=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"test"</span>)</span>
<span id="cb12-26">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-27">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sf</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coords=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs=</span>sinu)</span>
<span id="cb12-28">dt_sf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> dt_sf[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">duplicated</span>(dt_sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>geometry), ]</span>
<span id="cb12-29">p_space <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-30">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_sf</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data=</span>world) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-31">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_sf</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data=</span>dt_sf, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span>set), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-32">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">train=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"steelblue"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">test=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"firebrick"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-33">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_sf</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlim=</span>bb[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ylim=</span>bb[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)]) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-34">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Spatial hold-out design"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-35">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.background=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_rect</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lightblue"</span>),</span>
<span id="cb12-36">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.background=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_rect</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>),</span>
<span id="cb12-37">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.key=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_rect</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>))</span>
<span id="cb12-38"></span>
<span id="cb12-39">p_season <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-40">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(month) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-41">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mean_sswc=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(sswc_m), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.groups=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"drop"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-42">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(month, mean_sswc)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-43">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-44">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-45">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">breaks=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-46">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Seasonal cycle of the response"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Month"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean sswc_m"</span>)</span>
<span id="cb12-47"></span>
<span id="cb12-48">p_space <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> p_season</span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-eda" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-eda-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://r-delisi.github.io/en/posts/2026-09-03-soil-moisture-modelling/index_files/figure-html/fig-eda-1.png" class="img-fluid figure-img" width="1344">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-eda-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Left: training (blue) and test (red) stations share the same region, so the test set represents new, interspersed locations. Right: the monthly mean of the response shows a pronounced seasonal cycle with a mid-summer minimum.
</figcaption>
</figure>
</div>
</div>
</div>
</section>
</section>
<section id="cross-validation-design" class="level1">
<h1>Cross-validation design</h1>
<p>Because the test stations are new locations, a random split of the station-month rows would place records from the same station in both the training and the assessment folds. The strong within-station similarity would then leak into validation and produce an optimistic error estimate that does not reflect performance at genuinely new sites <span class="citation" data-cites="roberts2017cv meyer2018">(Roberts et al. 2017; Meyer et al. 2018)</span>. We therefore use <em>location-blocked</em> cross-validation: whole stations are assigned to folds, so that no station contributes rows to both sides of a split. This mirrors the competition’s own train/test design.</p>
<p>The same folds and the same metric set are reused for every model so that comparisons are fair. <img src="https://latex.codecogs.com/png.latex?RMSE"> is the competition metric and our primary criterion; we also report the coefficient of determination (<img src="https://latex.codecogs.com/png.latex?R%5E2">) and the mean absolute error (<img src="https://latex.codecogs.com/png.latex?MAE">).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb13-2">folds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_vfold_cv</span>(train2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group=</span>loc_id, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">v=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb13-3">metrics <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_set</span>(rmse, rsq, mae)</span></code></pre></div></div>
</div>
</section>
<section id="models" class="level1">
<h1>Models</h1>
<section id="random-forest" class="level2">
<h2 class="anchored" data-anchor-id="random-forest">Random forest</h2>
<p>The first substantive model is a random forest, which handles nonlinear responses and predictor interactions with little tuning and is a strong default for tabular environmental data <span class="citation" data-cites="breiman2001 hengl2018rf">(Breiman 2001; Hengl et al. 2018)</span>. We use the <code>ranger</code> engine <span class="citation" data-cites="wright2017ranger">(Wright and Ziegler 2017)</span> with 500 trees. Missing values are median-imputed inside the recipe.</p>
<p>The full set of predictors used in the model is:</p>
<p><strong>Location and time</strong></p>
<ul>
<li><code>x</code>, <code>y</code>: station coordinates (in the sinusoidal MODIS grid CRS)</li>
<li><code>year</code>, <code>month</code>: calendar year and month</li>
<li><code>month_sin</code>, <code>month_cos</code>: cyclical (sine/cosine) encoding of month, used so the model can learn a smooth seasonal cycle without treating December and January as far apart</li>
</ul>
<p><strong>MODIS-derived covariates</strong> (see the <a href="https://codeberg.org/opengeohub/MODIS_LST_trend_analysis_tutorial">MODIS LST tutorial</a> for details)</p>
<ul>
<li><code>dlst</code>: day-time mean monthly land surface temperature (LST)</li>
<li><code>nlst</code>: night-time mean monthly LST</li>
<li><code>dlst.95</code>: upper 95th percentile of monthly day-time temperatures</li>
<li><code>nlst.95</code>: upper 95th percentile of monthly night-time temperatures</li>
<li><code>geom</code>: geometric temperature monthly</li>
<li><code>evi</code>: Enhanced Vegetation Index, based on the MODIS monthly product</li>
</ul>
<p><strong>ERA5-Land covariates</strong> (added independently, see the ERA5-Land section above)</p>
<ul>
<li><code>era5_swvl1</code>: monthly volumetric soil water in the top layer</li>
<li><code>era5_precip</code>: mean daily precipitation for the month</li>
<li><code>era5_precip_lag1</code>: one-month lag of the monthly mean daily precipitation</li>
</ul>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">rec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(sswc_m <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> dlst <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> dlst<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.95</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> nlst <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> nlst<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.95</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> evi <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb14-2">                  year <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> month <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> month_sin <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> month_cos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> era5_swvl1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb14-3">                  era5_precip <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> era5_precip_lag1, </span>
<span id="cb14-4">              <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data=</span>train2) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_impute_median</span>(dlst, dlst<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.95</span>, nlst, nlst<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.95</span>, era5_precip_lag1)</span>
<span id="cb14-6"></span>
<span id="cb14-7">rf_spec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rand_forest</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">trees=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_engine</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">num.threads=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_mode</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression"</span>)</span>
<span id="cb14-10"></span>
<span id="cb14-11">wf_rf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_recipe</span>(rec) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_model</span>(rf_spec)</span>
<span id="cb14-12"></span>
<span id="cb14-13">res_rf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit_resamples</span>(wf_rf, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resamples=</span>folds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metrics=</span>metrics)</span>
<span id="cb14-14"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect_metrics</span>(res_rf)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 3 × 6
  .metric .estimator   mean     n std_err .config        
  &lt;chr&gt;   &lt;chr&gt;       &lt;dbl&gt; &lt;int&gt;   &lt;dbl&gt; &lt;chr&gt;          
1 mae     standard   26.2      10  0.671  pre0_mod0_post0
2 rmse    standard   34.8      10  1.58   pre0_mod0_post0
3 rsq     standard    0.482    10  0.0155 pre0_mod0_post0</code></pre>
</div>
</div>
<p>The random forest achieves a location-blocked cross-validated <img src="https://latex.codecogs.com/png.latex?RMSE"> of approximately 34.8 and an <img src="https://latex.codecogs.com/png.latex?R%5E2"> of approximately 0.48 at held-out locations. This is a reasonable starting point, but the modest <img src="https://latex.codecogs.com/png.latex?R%5E2"> signals that much of the station-to-station variability is not captured by the provided predictors.</p>
</section>
</section>
<section id="results-and-discussion" class="level1">
<h1>Results and Discussion</h1>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb16-2"></span>
<span id="cb16-3">final_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit</span>(wf_rf, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data=</span>train2)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">test2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> test <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb17-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.row_order=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_number</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb17-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(era5_cov, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"loc_id"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yearmon"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb17-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(.row_order)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1">pred_test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(final_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data=</span>test2)</span>
<span id="cb18-2">test2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pred <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> pred_test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>.pred</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb19-1">submission <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read.csv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/input/sample_submission.csv"</span>)</span>
<span id="cb19-2"></span>
<span id="cb19-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stopifnot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(submission) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(test2))</span>
<span id="cb19-4"></span>
<span id="cb19-5">submission<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>sswc_m <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> test2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pred</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dir.create</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/output"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">showWarnings=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">recursive=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb20-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write.csv</span>(submission, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data/output/submission_rf.csv"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">row.names=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, </span>
<span id="cb20-3">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">quote=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span></code></pre></div></div>
</div>
<p>The final model is the random forest with the MODIS, and ERA5-Land predictors. It is refitted on the entire training set and applied to the test stations. The submission is written by copying the sample submission and replacing its response column, which guarantees that the row order and identifiers match the grader exactly.</p>
<p>Because the MODIS predictors are only available at the station points, the predictions are shown as station maps rather than a continuous surface; producing a gridded map would require the MODIS temperature and vegetation layers for the whole tile. Figure&nbsp;3 contrasts a winter and a summer month at the test stations and reproduces the expected seasonal pattern, with markedly wetter soils in January than in July.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1">test2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb21-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(yearmon <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2020-01"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2020-07"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb21-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(x, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour=</span>pred)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb21-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb21-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_viridis_c</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sswc_m"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb21-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_wrap</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>yearmon) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb21-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_equal</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb21-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-maps" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-maps-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://r-delisi.github.io/en/posts/2026-09-03-soil-moisture-modelling/index_files/figure-html/fig-maps-1.png" class="img-fluid figure-img" width="1152">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-maps-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Predicted monthly soil surface water content at the test stations for a representative winter month (January 2020) and summer month (July 2020).
</figcaption>
</figure>
</div>
</div>
</div>
<p>This prediction task is actually quite challenging because the data have both spatial and temporal structure, and the validation strategy should account for potential spatial and temporal autocorrelation. By blocking folds by station identity, we partially avoid the overly optimistic scores that a naive random split could produce. This also makes the validation setup more similar to the hidden test set, where predictions are required for unseen stations.</p>
<p>However, station-based blocking does not necessarily guarantee spatial independence between folds. Multiple stations may still fall within the same or neighbouring grid cells, especially given the relatively coarse resolution of some predictors. A more rigorous approach could therefore involve spatial thinning and spatial cross-validation methods such as block cross-validation or kNNDM cross-validation <span class="citation" data-cites="gmd-17-5897-2024">(Linnenbrink et al. 2024)</span>.</p>
<p>In addition, including spatial coordinates improved predictive performance, suggesting that geographic location contains information that is not fully captured by the MODIS and ERA5-Land covariates. However, the coarse spatial resolution of ERA5-Land may limit its ability to represent fine-scale differences among locations.</p>
<p>Also, using spatial coordinates directly as covariates may not be an ideal modelling strategy. A better approach could be to account for spatial dependence more explicitly using methods such as RFsp, RFSI, RandomForestsGLS or spatialRF <span class="citation" data-cites="hengl2018rf rs12101687 nowosad2025">(Hengl et al. 2018; Sekulić et al. 2020; Nowosad 2025)</span>.</p>
<p>The most promising next steps would be to include covariates that vary at the station scale and plausibly influence water retention, such as soil texture and organic carbon from products like SoilGrids, land-cover classes, and higher-resolution satellite soil-moisture products where temporal coverage allows.</p>
<p>On the modelling side, gradient-boosted trees may outperform random forests, while more systematic feature engineering could also help improve predictive performance.</p>
</section>
<section id="reproducibility" class="level1 unnumbered">
<h1 class="unnumbered">Reproducibility</h1>
<p><strong>Note on the use of AI tools:</strong> I used large language models as supporting tools during the preparation of this post, mainly for language editing, code style and debugging suggestions, and occasional methodological feedback. The analysis workflow, modelling decisions, and the majority of the code were developed by me. I reviewed, revised, and reran the complete notebook multiple times, and I take full responsibility for the final content, code, interpretations, and any remaining errors.</p>
<div class="cell">
<details class="code-fold">
<summary>Code</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sessionInfo</span>()</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>R version 4.6.1 (2026-06-24)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 26.04.1 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so;  LAPACK version 3.12.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=tr_TR.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=tr_TR.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=tr_TR.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=tr_TR.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Istanbul
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] patchwork_1.3.2    ranger_0.18.0      ecmwfr_2.0.3       sf_1.1-2          
 [5] terra_1.9-46       yardstick_1.4.0    workflowsets_1.1.1 workflows_1.3.0   
 [9] tune_2.1.0         tailor_0.1.0       rsample_1.3.2      recipes_1.4.0     
[13] purrr_1.2.2        parsnip_1.6.0      modeldata_1.6.0    infer_1.1.0       
[17] ggplot2_4.0.3      dials_1.4.4        scales_1.4.0       broom_1.0.13      
[21] tidymodels_1.5.0   tidyr_1.3.2        dplyr_1.2.1       

loaded via a namespace (and not attached):
 [1] DBI_1.3.0           conflicted_1.2.0    rlang_1.3.0        
 [4] magrittr_2.0.5      furrr_0.4.0         otel_0.2.0         
 [7] e1071_1.7-17        compiler_4.6.1      vctrs_0.7.3        
[10] maps_3.4.3          pkgconfig_2.0.3     fastmap_1.2.0      
[13] backports_1.5.1     labeling_0.4.3      utf8_1.2.6         
[16] rmarkdown_2.32      prodlim_2026.03.11  xfun_0.60          
[19] cachem_1.1.0        jsonlite_2.0.0      parallel_4.6.1     
[22] R6_2.6.1            RColorBrewer_1.1-3  parallelly_1.48.0  
[25] rpart_4.1.27        lubridate_1.9.5     Rcpp_1.1.2         
[28] knitr_1.51          future.apply_1.20.2 Matrix_1.7-6       
[31] splines_4.6.1       nnet_7.3-21         timechange_0.4.0   
[34] tidyselect_1.2.1    rstudioapi_0.19.0   dichromat_2.0-0.1  
[37] yaml_2.3.12         timeDate_4052.112   codetools_0.2-20   
[40] curl_8.0.0          listenv_1.0.0       lattice_0.23-1     
[43] tibble_3.3.1        withr_3.0.3         S7_0.2.2           
[46] evaluate_1.0.5      future_1.75.0       survival_3.8-11    
[49] units_1.0-1         proxy_0.4-29        pillar_1.11.1      
[52] KernSmooth_2.23-27  generics_0.1.4      mirai_2.7.2        
[55] globals_0.19.1      class_7.3-24        glue_1.8.1         
[58] tools_4.6.1         data.table_1.18.6.1 gower_1.0.2        
[61] reactable_0.4.5     grid_4.6.1          ipred_0.9-16       
[64] cli_3.6.6           DiceDesign_1.10     viridisLite_0.4.3  
[67] lava_1.9.3          keyring_1.4.1       gtable_0.3.6       
[70] digest_0.6.39       classInt_0.4-11     nanonext_1.10.2    
[73] htmlwidgets_1.6.4   farver_2.1.2        memoise_2.0.1      
[76] htmltools_0.5.9     lifecycle_1.0.5     hardhat_1.4.3      
[79] httr_1.4.9          sparsevctrs_0.3.6   MASS_7.3-66        </code></pre>
</div>
</div>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-breiman2001" class="csl-entry">
Breiman, Leo. 2001. <span>“Random Forests.”</span> <em>Machine Learning</em> 45 (1): 5–32. <a href="https://doi.org/10.1023/A:1010933404324">https://doi.org/10.1023/A:1010933404324</a>.
</div>
<div id="ref-hengl2018rf" class="csl-entry">
Hengl, Tomislav, Madlene Nussbaum, Marvin N. Wright, Gerard B. M. Heuvelink, and Benedikt Gräler. 2018. <span>“Random Forest as a Generic Framework for Predictive Modeling of Spatial and Spatio-Temporal Variables.”</span> <em>PeerJ</em> 6: e5518. <a href="https://doi.org/10.7717/peerj.5518">https://doi.org/10.7717/peerj.5518</a>.
</div>
<div id="ref-hersbach2020era5" class="csl-entry">
<span class="nocase">Hersbach, Hans, Bill Bell, Paul Berrisford, et al.</span> 2020. <span>“The <span>ERA5</span> Global Reanalysis.”</span> <em>Quarterly Journal of the Royal Meteorological Society</em> 146 (730): 1999–2049. <a href="https://doi.org/10.1002/qj.3803">https://doi.org/10.1002/qj.3803</a>.
</div>
<div id="ref-ecmwfr2023" class="csl-entry">
Hufkens, Koen, Reto Stauffer, and Elio Campitelli. 2023. <em>Ecmwfr: Interface to ’ECMWF’ and ’CDS’ Data Web Services</em>.
</div>
<div id="ref-gmd-17-5897-2024" class="csl-entry">
Linnenbrink, J., C. Milà, M. Ludwig, and H. Meyer. 2024. <span>“kNNDM CV: <img src="https://latex.codecogs.com/png.latex?k">-Fold Nearest-Neighbour Distance Matching Cross-Validation for Map Accuracy Estimation.”</span> <em>Geoscientific Model Development</em> 17 (15): 5897–912. <a href="https://doi.org/10.5194/gmd-17-5897-2024">https://doi.org/10.5194/gmd-17-5897-2024</a>.
</div>
<div id="ref-meyer2018" class="csl-entry">
Meyer, Hanna, Christoph Reudenbach, Tomislav Hengl, Marwan Katurji, and Thomas Nauss. 2018. <span>“Improving Performance of Spatio-Temporal Machine Learning Models Using Forward Feature Selection and Target-Oriented Validation.”</span> <em>Environmental Modelling &amp; Software</em> 101: 1–9. <a href="https://doi.org/10.1016/j.envsoft.2017.12.001">https://doi.org/10.1016/j.envsoft.2017.12.001</a>.
</div>
<div id="ref-munoz2021era5land" class="csl-entry">
<span class="nocase">Muñoz-Sabater, Joaquín, Emanuel Dutra, Anna Agustí-Panareda, et al.</span> 2021. <span>“<span>ERA5-Land</span>: A State-of-the-Art Global Reanalysis Dataset for Land Applications.”</span> <em>Earth System Science Data</em> 13 (9): 4349–83. <a href="https://doi.org/10.5194/essd-13-4349-2021">https://doi.org/10.5194/essd-13-4349-2021</a>.
</div>
<div id="ref-nowosad2025" class="csl-entry">
Nowosad, Jakub. 2025. <span>“Specialized <span>R</span> Packages for Spatial Machine Learning: <span>An</span> Introduction to <span>RandomForestsGLS,</span> <span class="nocase">spatialRF,</span> and Meteo.”</span> June 25. <a href="https://geocompx.org/post/2025/sml-bp5/">https://geocompx.org/post/2025/sml-bp5/</a>.
</div>
<div id="ref-roberts2017cv" class="csl-entry">
Roberts, David R., Volker Bahn, Simone Ciuti, et al. 2017. <span>“Cross-Validation Strategies for Data with Temporal, Spatial, Hierarchical, or Phylogenetic Structure.”</span> <em>Ecography</em> 40 (8): 913–29. <a href="https://doi.org/10.1111/ecog.02881">https://doi.org/10.1111/ecog.02881</a>.
</div>
<div id="ref-rs12101687" class="csl-entry">
Sekulić, Aleksandar, Milan Kilibarda, Gerard B. M. Heuvelink, Mladen Nikolić, and Branislav Bajat. 2020. <span>“Random Forest Spatial Interpolation.”</span> <em>Remote Sensing</em> 12 (10). <a href="https://doi.org/10.3390/rs12101687">https://doi.org/10.3390/rs12101687</a>.
</div>
<div id="ref-wright2017ranger" class="csl-entry">
Wright, Marvin N., and Andreas Ziegler. 2017. <span>“<span class="nocase">ranger</span>: A Fast Implementation of Random Forests for High Dimensional Data in <span>C++</span> and <span>R</span>.”</span> <em>Journal of Statistical Software</em> 77 (1): 1–17. <a href="https://doi.org/10.18637/jss.v077.i01">https://doi.org/10.18637/jss.v077.i01</a>.
</div>
</div></section></div> ]]></description>
  <category>R</category>
  <category>spatial data science</category>
  <category>remote sensing</category>
  <category>GIS</category>
  <category>r-spatial</category>
  <category>machine learning</category>
  <guid>https://r-delisi.github.io/en/posts/2026-09-03-soil-moisture-modelling/</guid>
  <pubDate>Wed, 02 Sep 2026 21:00:00 GMT</pubDate>
</item>
</channel>
</rss>
