diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..88eb4ad --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1 @@ +^development\.R$ diff --git a/.quarto/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json b/.quarto/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json index f40d397..5d646d1 100644 --- a/.quarto/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json +++ b/.quarto/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "df96dd7b0c06e257f0066e58be1df75f", + "hash": "2759d1707cdb7cd48df6fad351b0353b", "result": { - "markdown": "---\ntitle: \"Building R packages\"\ndescription: |\n This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\nauthor: Andrew MacDonald\ndate: \"2021-05-04\"\ncategories: [Technical, EN]\ntoc: true\nnumber-sections: true\nnumber-depth: 1\n---\n\n\n\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n### *Mise en place* : development environment\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles taht R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stderr}\n```\n✔ Setting active project to '/Users/katherine/Documents/GitHub/bios2.github.io-quarto'\n✔ Adding '^development\\\\.R$' to 'posts/2021-05-04-building-r-packages/.Rbuildignore'\n```\n:::\n:::\n\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n", + "markdown": "---\ntitle: \"Building R packages\"\ndescription: |\n This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\nauthor: Andrew MacDonald\ndate: \"2021-05-04\"\nimage: altumcode-PNbDkQ2DDgM-unsplash.jpeg\ncategories: [Technical, EN]\ntoc: true\nnumber-sections: true\nnumber-depth: 1\n---\n\n\n\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n### *Mise en place* : development environment\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles that R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n\n::: {.cell}\n\n:::\n\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/.quarto/idx/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd.json b/.quarto/idx/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd.json index 7d770b5..e9a3111 100644 --- a/.quarto/idx/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd.json +++ b/.quarto/idx/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd.json @@ -1 +1 @@ -{"title":"Mathematical Modeling in Ecology and Evolution","markdown":{"yaml":{"title":"Mathematical Modeling in Ecology and Evolution","description":"This workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n","categories":["Technical","EN"],"author":[{"name":"Dr Sarah P. Otto","affiliation":"University of British Columbia"}],"base_url":"https://bios2.github.io/","bibliography":"citations.bib","image":"StabilityPictures.jpg","date":"2020-01-14","toc":true,"number-sections":true,"number-depth":1},"headingText":"Content","containsRefs":false,"markdown":"\n\nIn this workshop, I introduce various modelling techniques, using mostly ecological and evolutionary examples, with a focus on how computer software programs can help biologists analyze such models.\n\n\n**Part 1:** Classic one-variable models in ecology and evolution\\\n**Part 2:** Equilibria and their stability\\\n**Part 3:** Beyond equilibria\\\n**Part 4:** Example of building a model from scratch\\\n**Part 5:** Extending to models with more than one variable\\\n**Part 6:** Another example of building a model from scratch\n\n### Software\n\nIn my research, I primarily use Mathematica, which is a powerful software package to organize and conduct analytical modelling, but it is not free (at UBC, we have some licenses available). I will also show some example code and provide translation of most of what I present in a free software package called Maxima.\n\n#### Mathematica installation\n\nThere is a free trial version that you can use for 15 days, if you don't have a copy (click [here](http://www.wolfram.com/mathematica/trial/) to access), or you can buy a [student version](https://www.wolfram.com/mathematica/pricing/students/) online. If you want to make sure that all is working, copy the code below, put your cursor over each of the following lines and press enter (on some computers, \"enter\" is a separate button, on others, press \"shift\" and \"return\" at the same time):\n\n``` mathematica\nD[x^3,x]\nListPlot[Table[x, {x,1,10}],Joined->True]\nRSolve[{x[t+1]\\[Equal]A x[t],x[0]\\[Equal]x0},x[t],t]\nPDF[NormalDistribution[0,1],x]\n```\n\nYou should see (a) $3x^2$, (b) a plot of a line, (c) ${{x[t]->A^t x0}}$, and (d) $\\frac{e^\\frac{-x^2}{2}}{\\sqrt{2\\pi }}$.\n\n#### Maxima installation:\n\nOn a Mac, install using the instructions [here](https://themaximalist.org/about/my-mac-os-installation/). For other file systems, download [here](https://sourceforge.net/projects/maxima/files/).\n\n#### Maxima testing\n\nWhen you first open Maxima, it will give you a choice of GUIs, chose wxMaxima. Once wxMaxima is launched type this command and hit return to see if it answers 4:\n\n``` maxima\n2+2;\n```\n\nIf it doesn't, then scan the installation document for the error that you run into.\n\nIf it does return 4, then type in and enter these commands:\n\n``` maxima\ndiff(x^3, x);\n\nwxplot2d (3*x, [x, 0, 2*%pi]);\n\nload(\"solve_rec\")$\nsolve_rec(x[t+1] = A*x[t], x[t], x[0]=x0);\n\nload(\"distrib\")$\npdf_normal(x,0,1);\n```\n\nYou should see (a) $3x^2$, (b) a plot of a line, (c) ${{x[t]->A^t x0}}$, and (d) $\\frac{e^\\frac{-x^2}{2}}{\\sqrt{2\\pi }}$.\n\n### Material\n\n| Mathematica | Maxima | PDF |\n|:----------------------:|:----------------------:|:----------------------:|\n| [Notebook](files/BIOS2_WorkshopMathematica.nb) | [Notebook](files/Bios2_WorkshopMaxima.wxmx) | Embeded below |\n| [Hints and solutions](files/BIOS2_WorkshopMathematicaSOLUTIONS.nb) | [Hints and solutions](files/Bios2_WorkshopMaximaSOLUTIONS.wxmx) | |\n| | | [Homework](files/Homework1.pdf) |\n| [Homework answers](files/HomeworkAnswers.nb) | | [Homework answers](files/HomeworkAnswers.pdf) |\n| [Guide](files/MathematicaGuide.nb) | [Guide](files/MaximaQuickReference.wxm) | |\n\n#### Follow along PDF\n\nThis PDF was generated from the Mathematica notebook linked above. It doesn't include dynamic plots, but it's a good alternative if you want to print out or have a quick reference at hand.\n\n\n\n

\n\n![Stability analysis of a recursion equation in a discrete-time model.](StabilityPictures.png)\n\n### Other resources\n\n- *An Introduction to Mathematical Modeling in Ecology and Evolution* [@otto2007biologist].\n\n- [Biomathematical modeling lecture notes](http://www.zoology.ubc.ca/~bio301/Bio301/Lectures.html).\n\n- [Mathematica labs UBC](http://www.zoology.ubc.ca/biomath/labs.htm).\n\n### Thanks\n\nNiki Love and Gil Henriques did a great job of translating the code into wxMaxima, with limited help from me. Thanks, Niki and Gil!!\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Mathematical Modeling in Ecology and Evolution","description":"This workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n","categories":["Technical","EN"],"author":[{"name":"Dr Sarah P. Otto","affiliation":"University of British Columbia"}],"base_url":"https://bios2.github.io/","bibliography":["citations.bib"],"image":"StabilityPictures.jpg","date":"2020-01-14","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file +{"title":"Mathematical Modeling in Ecology and Evolution","markdown":{"yaml":{"title":"Mathematical Modeling in Ecology and Evolution","description":"This workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n","categories":["Technical","EN"],"author":[{"name":"Sarah P. Otto","affiliation":"University of British Columbia"}],"base_url":"https://bios2.github.io/","bibliography":"citations.bib","image":"StabilityPictures.jpg","date":"2020-01-14","toc":true,"number-sections":true,"number-depth":1},"headingText":"Content","containsRefs":false,"markdown":"\n\nIn this workshop, I introduce various modelling techniques, using mostly ecological and evolutionary examples, with a focus on how computer software programs can help biologists analyze such models.\n\n\n**Part 1:** Classic one-variable models in ecology and evolution\\\n**Part 2:** Equilibria and their stability\\\n**Part 3:** Beyond equilibria\\\n**Part 4:** Example of building a model from scratch\\\n**Part 5:** Extending to models with more than one variable\\\n**Part 6:** Another example of building a model from scratch\n\n### Software\n\nIn my research, I primarily use Mathematica, which is a powerful software package to organize and conduct analytical modelling, but it is not free (at UBC, we have some licenses available). I will also show some example code and provide translation of most of what I present in a free software package called Maxima.\n\n#### Mathematica installation\n\nThere is a free trial version that you can use for 15 days, if you don't have a copy (click [here](http://www.wolfram.com/mathematica/trial/) to access), or you can buy a [student version](https://www.wolfram.com/mathematica/pricing/students/) online. If you want to make sure that all is working, copy the code below, put your cursor over each of the following lines and press enter (on some computers, \"enter\" is a separate button, on others, press \"shift\" and \"return\" at the same time):\n\n``` mathematica\nD[x^3,x]\nListPlot[Table[x, {x,1,10}],Joined->True]\nRSolve[{x[t+1]\\[Equal]A x[t],x[0]\\[Equal]x0},x[t],t]\nPDF[NormalDistribution[0,1],x]\n```\n\nYou should see (a) $3x^2$, (b) a plot of a line, (c) ${{x[t]->A^t x0}}$, and (d) $\\frac{e^\\frac{-x^2}{2}}{\\sqrt{2\\pi }}$.\n\n#### Maxima installation:\n\nOn a Mac, install using the instructions [here](https://themaximalist.org/about/my-mac-os-installation/). For other file systems, download [here](https://sourceforge.net/projects/maxima/files/).\n\n#### Maxima testing\n\nWhen you first open Maxima, it will give you a choice of GUIs, chose wxMaxima. Once wxMaxima is launched type this command and hit return to see if it answers 4:\n\n``` maxima\n2+2;\n```\n\nIf it doesn't, then scan the installation document for the error that you run into.\n\nIf it does return 4, then type in and enter these commands:\n\n``` maxima\ndiff(x^3, x);\n\nwxplot2d (3*x, [x, 0, 2*%pi]);\n\nload(\"solve_rec\")$\nsolve_rec(x[t+1] = A*x[t], x[t], x[0]=x0);\n\nload(\"distrib\")$\npdf_normal(x,0,1);\n```\n\nYou should see (a) $3x^2$, (b) a plot of a line, (c) ${{x[t]->A^t x0}}$, and (d) $\\frac{e^\\frac{-x^2}{2}}{\\sqrt{2\\pi }}$.\n\n### Material\n\n| Mathematica | Maxima | PDF |\n|:----------------------:|:----------------------:|:----------------------:|\n| [Notebook](files/BIOS2_WorkshopMathematica.nb) | [Notebook](files/Bios2_WorkshopMaxima.wxmx) | Embeded below |\n| [Hints and solutions](files/BIOS2_WorkshopMathematicaSOLUTIONS.nb) | [Hints and solutions](files/Bios2_WorkshopMaximaSOLUTIONS.wxmx) | |\n| | | [Homework](files/Homework1.pdf) |\n| [Homework answers](files/HomeworkAnswers.nb) | | [Homework answers](files/HomeworkAnswers.pdf) |\n| [Guide](files/MathematicaGuide.nb) | [Guide](files/MaximaQuickReference.wxm) | |\n\n#### Follow along PDF\n\nThis PDF was generated from the Mathematica notebook linked above. It doesn't include dynamic plots, but it's a good alternative if you want to print out or have a quick reference at hand.\n\n\n\n

\n\n![Stability analysis of a recursion equation in a discrete-time model.](StabilityPictures.png)\n\n### Other resources\n\n- *An Introduction to Mathematical Modeling in Ecology and Evolution* [@otto2007biologist].\n\n- [Biomathematical modeling lecture notes](http://www.zoology.ubc.ca/~bio301/Bio301/Lectures.html).\n\n- [Mathematica labs UBC](http://www.zoology.ubc.ca/biomath/labs.htm).\n\n### Thanks\n\nNiki Love and Gil Henriques did a great job of translating the code into wxMaxima, with limited help from me. Thanks, Niki and Gil!!\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Mathematical Modeling in Ecology and Evolution","description":"This workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n","categories":["Technical","EN"],"author":[{"name":"Sarah P. Otto","affiliation":"University of British Columbia"}],"base_url":"https://bios2.github.io/","bibliography":["citations.bib"],"image":"StabilityPictures.jpg","date":"2020-01-14","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file diff --git a/.quarto/idx/posts/2020-12-07-making-websites-with-hugo/index.qmd.json b/.quarto/idx/posts/2020-12-07-making-websites-with-hugo/index.qmd.json index 1515a3f..a3041fd 100644 --- a/.quarto/idx/posts/2020-12-07-making-websites-with-hugo/index.qmd.json +++ b/.quarto/idx/posts/2020-12-07-making-websites-with-hugo/index.qmd.json @@ -1 +1 @@ -{"title":"Making websites with HUGO","markdown":{"yaml":{"title":"Making websites with HUGO","description":"This workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n","author":[{"name":"Dominique Gravel"},{"name":"Guillaume Larocque"}],"image":"image.jpg","categories":["Technical","Transversal competencies","EN"],"date":"12-07-2020","toc":true,"number-sections":true,"number-depth":1},"headingText":"Why this training workshop ?","containsRefs":false,"markdown":"\n\n\nI am only 10 hours of a crash course in web development ahead of you. As part of a major research project on setting a biodiversity observation network, I had to develop a prototype of a portal for the project, for biodiversity information and bunch of dashboards on biodiversity trends. Never made a website before. I know how to code in a few langages, and I know that I hate playing with boxes, menus, importing images manually, and most of all, dealing with a crash of the system and having to redo the whole thing because I made a mistake somewhere. Not that a bug when I try to compile is better, but at least it is more tractable.\n\nHugo made it very easily because of its fundamental feature (which is the same reason I edit papers with LaTeX): the distinction between the view and the content. Once you have set up the rules defining the visual aspects of the pages, then you can focus on the content and let the software automatically constructing the html code for you. It's fast, accessible, scriptable and could be version-controlled. All qualities for an open and reproducible science.\n\nTook me a few hours to learn the basics (much harder to get the higher level skills, especially to write your own Go scripts), I took some tricks here and there in different templates and at looking what others do, and that was it I had my website. Realized that it could be a good entry level course to BIOS2 fellows and decided to turn that experience into a training workshop.\n\nYou will find below basic instructions to install and run a template. The following is not a full tutorial, for that I recommend simply to take time looking at the documentation provided on the Hugo page (https://gohugo.io/). I also consulted the online book **Hugo in action** (https://www.manning.com/books/hugo-in-action). There are many other references, all of them with goods and bads. But it's nice to have multiple ones because sometimes the description of a concept may be obscure in one reference but better in the other and it's by comparing and switching between them that you can make progress.\n\n# Make sure Hugo is installed and check version\n\nFirst step, you have to make sure that it is properly installed on you computer. Type the following command in terminal to make sure :\n\n``` bash\nhugo version\n```\n\nYou can access to the help menu with the simple command :\n\n``` bash\nhugo help\n```\n\n# Be Timothée Poisot for fun\n\nWe will use Tim's website, which is a simple but efficient example of what we could achieve with Hugo. The strenght of the website is that it automatically updates with the addition of new content, such as publications, lab members and projects. The only thing you have to do, once the template is properly set up, is to update the content. That way, yo can focus on the material you want to put on, without struggling on how to place the boxes, format the police and all of the complicate stuff that comes with html and css. The content, written in markdown, is human readable and therefore could be easily edited by lab members. Further, since it's all scripted, it's easy to maintain and control versions.\n\nTake few minutes to look at the final webpage at https://poisotlab.io/\n\nNow you will clone the repository on your own computer so that you could start playing with the content, edit the files, modify list of papers and so on.\n\nYou can either use the clone button on the top of the page or the following command :\n\n``` bash\ngit clone https://github.com/bios2/Hugo-training-workshop.git\n```\n\nWe will take a few minutes to look at the content of the different folders. This structure is common to most of the Hugo templates. You will find multiple folders, it's useful to understand what's located where because the compiler expects this structure when it looks for specific information.\n\n**archetypes** (not in here, but usually in most templates). These are basic instructions to generate new content with the *hugo new* command. We won't use this feature today, but information about this feature is easy to find.\n\n**assets** contains the css files where the controls for visual aspect of the pages are specified. That's where you'll search for the different items and how to specify things such as box sizes, font colors and dimensions etc.... Note: assets directory is not created by default.\n\n**content** holds all of the .md files where the main content of the pages is provided. It's divided in several subfolders, corresponding to the different pages from the menu. Each top-level folder in Hugo is considered a content section (which is described usually in the config file). For instance, you have one folder called **Research** where the projects are described. You'll find one .md file per projec tin this folder. Note also that the folders contain systematically a \\_index.md file where the metadata and the top level information of the page are specified. We'll come back to that later.\n\n**data** stores specific information that will be consulted by the parser during compilation (configurationfiles). There are also data templates, and at the moment, there is one json file where the papers are listed and two toml files with a list of the students, past and present. json files could be edited with a text editor (not so fun), but there are some tools to do it efficiently.\n\n**layouts** contains the core files to compile the website. You will find in them instructions, in a strange blend of html and Go langages. No so easy and pleasant to play with, but looking at them tells you a bit about what the compiler does (a good example is for *people*). *list.html* for instance contains a loop that goes through the toml files in order to create the icons, the text and the link to the full markdown page where you have description for each student. You will find layouts for the main pages, as well as for partials (like the header menu).\n\n**resources** also contains css instructions for the template. We won't work with this one.\n\n**static** contains bunch of little things that are called during compilation. You'll find the logo for the lab, the pictures for students, pdf files for applications, images for each research project ...\n\nThere is also one very important file in the main folder the **config.toml** file. Inside, you will find a lot of the metadata that will control the structure of the main page. This find can be very simple for some templates, much more complicated for other ones. Note that for some templates, the config file may be in a distinct folder. Not all templates have exactly the same folder structure.\n\n*toml* is a file format for configuration files, it contains key parameters for the webpage. It consists of key = \"value\" pairs, \\[section names\\], and \\# comments. Let's open this one to have a closer look.\n\n## Exercise : Edit the toml file to include your own information.\n\nYou may want to change the section *People* to *Collaborators* and also provide a proper reference to your on github page. You can also add or remove sections, this will affect the menu at the top of the page. For instance, you can add a blog section.\n\n# Build the static html files\n\n## Build for local development\n\nHugo will use all of the material to generate static html files that will be displayed on your browser. The command is really easy to use to run it on your own computer, you simply have to type the following in the main folder :\n\n``` bash\nhugo server\n```\n\nAnd that's it, it compiles and you can simply open it in your browser by clicking on the adress indicated in the terminal. Congratulations for your first Hugo webste !\n\nThere are useful information in the terminal about the building process.\n\n## Build for publishing your website\n\nThe command *hugo server* is very fast and useful to test your website while you develop it. But once you'll be ready to distribute it, you'll need all of the html files and related material to distribute the website. This is easily done with the even simpler command\n\n``` bash\nhugo\n```\n\nYou will find in the directory that a new folder named **public** appeared, with all of the material needed to deploy the website. If you click on the *index.html* file, you'll get to the home page of the website. It is interesting to open this file in your text editor, you'll get a sense of the html code that hugo generated automatically for you. You can also take a look at other files.\n\n# Edit content\n\nEditing content is the easier thing to do. First thing to do, is to modify the content of the introduction paragraph on the main page. You'll find it in the \\*\\_index.md\\* file in the **content** folder. Open it and modify the text. You can after build the main page again to see the update.\n\nYou can also add material, with new md files. We will do so with a new research project (note the following could be done manually):\n\n``` bash\nhugo new research/chapter1.md\n```\n\nThis will generate a new markdown file, in which you can start adding material. But those files do have a particular structure, so before editing it, we'll take a quick look at another one, *datascience.md*.\n\nThe header section is typical of a markdown file with metadata (in toml or yaml format). You have to specify information to the parser about the title, the image and associated papers. Note that it will work if some of these (e.g. papers) are missing. You can modify the image as well.\n\nThe file here also a particular structure, with the marker between two paragraphs. This command indicates that only the first paragraph is displayed on the main page of the **Research** tab, and the full content follows if you click to know more about the project.\n\nNote that here you can use the basic features of markdown, with headers, bold, italics and so on. You can also include html code directly into the markdown and it should work. That said, it may conflict with higher level instructions in the layout or in the theme and may cause difficulties at building. While it is feasible to add such command, it is not recommended to do so. People rather suggest to use shortcodes (Tomorrow) or to modify the layout of the website.\n\n## Exercise\n\nTake 15 minutes to remove Tim's material and replace it by the three chapters of your thesis.\n\n# Hosting the website on a server\n\nThere are many options to host your new website on a server. An easy one, free, and that could be coupled with version control is to run it on github. Full instructions are available here :\n\nhttps://gohugo.io/hosting-and-deployment/hosting-on-github/\n\nWe will simply follow the instructions copied here for hosting a personal page. Note that you can also develop a page for a project.\n\n## GitHub User or Organization Pages\n\n### Step-by-step Instructions\n\n1. Create a (e.g. blog) repository on GitHub. This repository will contain Hugo's content and other source files.\n2. Create a .github.io GitHub repository. This is the repository that will contain the fully rendered version of your Hugo website.\n3. git clone && cd \n4. Paste your existing Hugo project into the new local repository. Make sure your website works locally (hugo server or hugo server -t ) and open your browser to http://localhost:1313.\n5. Once you are happy with the results: Press Ctrl+C to kill the server Before proceeding run rm -rf public to completely remove the public directory\n6. git submodule add -b main https://github.com//.github.io.git public. This creates a git submodule. Now when you run the hugo command to build your site to public, the created public directory will have a different remote origin (i.e. hosted GitHub repository).\n7. Make sure the baseURL in your config file is updated with: .github.io\n\n### Put it Into a Script\n\nYou're almost done. In order to automate next steps create a deploy.sh script. You can also make it executable with chmod +x deploy.sh.\n\nThe following are the contents of the deploy.sh script:\n\n``` bash\n #!/bin/sh\n\n # If a command fails then the deploy stops\n set -e\n\n printf \"\\033[0;32mDeploying updates to GitHub...\\033[0m\\n\"\n\n # Build the project.\n hugo # if using a theme, replace with `hugo -t `\n\n # Go To Public folder\n cd public\n\n # Add changes to git.\n git add .\n\n # Commit changes.\n msg=\"rebuilding site $(date)\"\n if [ -n \"$*\" ]; then\n msg=\"$*\"\n fi\n git commit -m \"$msg\"\n```\n\n# Push source and build repos.\n\n``` bash\ngit push origin main\n```\n\nYou can then run `./deploy.sh \"Your optional commit message\"` to send changes to .github.io. Note that you likely will want to commit changes to your repository as well.\n\nThat's it! Your personal page should be up and running at https://.github.io within a couple minutes.\n\n## Using a theme\n\nIt is usually a good idea to not modify a template directly, but to have the template and the site in a separate folder. The basic concept when doing this is that the config.toml file of the site has to link to the proper folder of the theme.\n\nFor example\n\n``` toml\ntheme = \"template-site\"\nthemesDir = \"../..\"\n```\n\nThis means that the template site is in a folder named template-site which is a parent folder of the site folder. Other options are possible.\n\nUsually, all the content should go in the site folder, not in the theme folder.\n\n### Exercise 1\n\n- Start modifying the theme to make it look like a website for a Zoo. Choose your preferred color scheme by changing the style= parameter in the config.toml file.\n\n- Feel free to download some images from [unsplash](https://unsplash.com) and save them in the static/img folder. You can then use these images in the carrousel, as \"testimonial\" photos or as background images for some of the sections. You can add or remove sections from the home page by editing the config.toml file and changing the enable= parameter in the params. segment at the bottom.\n\n- You can also try to create a new blog entry by adding a new file in the content/blog folder. This file will have a .md extension and will be written in markdown format.\n\n## Customizing a theme\n\n## Basics of HTML\n\nCore structure of an HTML page\n\n``` html\n\n\n\nThis is my great website\n\n\n\n

Main title

\n
Main content goes here
\n\n\n```\n\n### A divider, used to organize content into blocks\n\n``` html\n
\n```\n\n### A span, used to organize content or text into sections with different styles. Usually on the same line.\n\n``` html\n\n```\n\n### A paragraph\n\n``` html\n

\n```\n\n### Headings at different levels\n\n``` html\n

Main title

\n

Second level

\n

Third level

\n```\n\n### An image\n\n``` html\n\n```\n\n### A link\n\n``` html\nGreat website here!\n```\n\n## Link between HTML and CSS\n\n### In html\n\nid is always unique. Class is not.\n\n``` html\n
\nOne great div!\n
\n```\n\n### In CSS\n\n\"\\#\" is applied to id and \".\" is applied to class. When nothing is specified, applies to tag.\n\n``` css\n#this-div-only{\n font-size:24px;\n}\n\n.this-type-of-div{\n color: #bb0000;\n}\n\ndiv{\n display:block;\n}\n```\n\n## Basics of CSS\n\n[W3 Schools CSS reference](https://www.w3schools.com/cssref/)\n\n| Property | Description | Example |\n|------------------------|------------------------|------------------------|\n| width, height | width of item | 200px, 200pt, 100%, 100vw/vh |\n| min-width, min-height | minimum size of item | 200px, 200pt, 100%, 100vw |\n| color | font color | #aa0000, red or rgb(255,0,0) |\n| background-color | color of background | #aa0000, red or rgb(255,0,0) |\n| border-color | color of border | #aa0000, red or rgb(255,0,0) |\n| border | size, type and color of border | 1px solid black |\n| margin | margin around item (top right bottom left) | 1px, or 1px 2px 2px 1px |\n| padding | padding within item, inside div for example | 10px |\n| font-family | name of font | Verdana, Arial |\n| font-size | size of text | 14px, 2em |\n| display | should item be on the same line, or in a separate block? | inline, block, inline-block, flex, ... |\n\n### Exercise 2\n\n- Create a file named custom.css under template-site/my-site/static/css/.\n\n- Right-click on elements on the web page that you want to modify, then click on Inspect element and try to find CSS properties that you could modify to improve the look of the page. Then, choosing the proper class, add entries in the custom.css file that start with a dot (.) followed by the proper class names.\n\n``` css\n.this-class {\n font-size:28px;\n}\n```\n\n## Partials\n\nPartials are snippets of HTML code that could be reused on different places on the website. For example, you will see that the layouts/index.html file in the template-site folder lists all the partials that create the home page.\n\nAn important point to remember is that Hugo will look for files first in the site's folders, and if it doesn't find the files there, it will look for them in the theme's folder. So site folder layouts and CSS take priority over the theme folder.\n\n### Exercise 3\n\n- Create a new folder template-site/my-site/layouts. In this folder, create a new file named index.html and copy the content of the template-site/layouts/index.html file into it. Remove the testimonials section from the newly created file.\n\n- Create a new folder template-site/my-site/layouts/partials. In this folder, create a new file named featured-species.html put the following content into it, replacing the information with the species you selected.\n\n``` html\n
\n\"\"\n
\n

Red-Eyed Tree Frog

\n

This frog can be found in the tropical rain forests of Costa Rica.

\n
\n
\n```\n\n- Then, add this section to the index.html file created above.\n\n\n\n {{ partial \"featured_species.html\" . }}\n\n- You will probably need to restart the Hugo server to see the changes appear on the site.\n\n- Now, you need to edit the CSS! In your custom.css file, add the following lines.\n\n``` css\n\n.featured-species{\n height:300px;\n background-color: #1d1f20;\n color:white;\n}\n\n.species-image{\n height:300px;\n float:left;\n}\n\n.featured-species h3{\n color:white;\n font-size:1.5em;\n}\n\n.species-description{\n float:left;\n padding:20px;\n font-size:2em;\n}\n```\n\nModify this as you see fit!\n\n## Now a bit of GO lang to make the featured species different.\n\n[Introduction to Hugo templating](https://gohugo.io/templates/introduction/)\n\n### Exercise 4\n\n- Replace your partial featured-species.html content with this one\n\n``` html\n{{ range .Site.Data.species }}\n {{ if eq (.enable) true }}\n
\n \"\"\n
\n

{{ .name }}

\n

{{ .description }}

\n
\n
\n {{end}}\n{{end}}\n```\n\n- Now, create a new folder /template-site/my-site/data/species.\n\n- In this folder, create new file named frog.yaml with the following content.\n\n``` yaml\nenable: true\nname: \"Red-eyed tree frog\"\ndescription: \"This frog can be found in the forests of Costa Rica\"\nimage: \"frog.jpg\"\n```\n\n- Find other species photos and add them to the img folder. Then you can add new .yaml files in the data/species folder for each species.\n\n## iFrames\n\nAn iFrame is a HTML tag that essentially allows you to embed another web page inside of your site.\n\n### Exercise 5\n\nFind a Youtube video and click on the share option below the video. Find the Embed option and copy the code that starts with `\n\n```\n\nEdit the custom.css file and add this section\n\n``` css\n.video{\n width:100%;\n background-color:black;\n text-align:center;\n}\n```\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Making websites with HUGO","description":"This workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n","author":[{"name":"Dominique Gravel"},{"name":"Guillaume Larocque"}],"image":"image.jpg","categories":["Technical","Transversal competencies","EN"],"date":"12-07-2020","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file +{"title":"Making Websites with HUGO","markdown":{"yaml":{"title":"Making Websites with HUGO","description":"This workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n","author":[{"name":"Dominique Gravel"},{"name":"Guillaume Larocque"}],"image":"image.jpg","categories":["Technical","Transversal competencies","EN"],"date":"12-07-2020","toc":true,"number-sections":true,"number-depth":1},"headingText":"Why this training workshop ?","containsRefs":false,"markdown":"\n\n\nI am only 10 hours of a crash course in web development ahead of you. As part of a major research project on setting a biodiversity observation network, I had to develop a prototype of a portal for the project, for biodiversity information and bunch of dashboards on biodiversity trends. Never made a website before. I know how to code in a few langages, and I know that I hate playing with boxes, menus, importing images manually, and most of all, dealing with a crash of the system and having to redo the whole thing because I made a mistake somewhere. Not that a bug when I try to compile is better, but at least it is more tractable.\n\nHugo made it very easily because of its fundamental feature (which is the same reason I edit papers with LaTeX): the distinction between the view and the content. Once you have set up the rules defining the visual aspects of the pages, then you can focus on the content and let the software automatically constructing the html code for you. It's fast, accessible, scriptable and could be version-controlled. All qualities for an open and reproducible science.\n\nTook me a few hours to learn the basics (much harder to get the higher level skills, especially to write your own Go scripts), I took some tricks here and there in different templates and at looking what others do, and that was it I had my website. Realized that it could be a good entry level course to BIOS2 fellows and decided to turn that experience into a training workshop.\n\nYou will find below basic instructions to install and run a template. The following is not a full tutorial, for that I recommend simply to take time looking at the documentation provided on the Hugo page (https://gohugo.io/). I also consulted the online book **Hugo in action** (https://www.manning.com/books/hugo-in-action). There are many other references, all of them with goods and bads. But it's nice to have multiple ones because sometimes the description of a concept may be obscure in one reference but better in the other and it's by comparing and switching between them that you can make progress.\n\n# Make sure Hugo is installed and check version\n\nFirst step, you have to make sure that it is properly installed on you computer. Type the following command in terminal to make sure :\n\n``` bash\nhugo version\n```\n\nYou can access to the help menu with the simple command :\n\n``` bash\nhugo help\n```\n\n# Be Timothée Poisot for fun\n\nWe will use Tim's website, which is a simple but efficient example of what we could achieve with Hugo. The strenght of the website is that it automatically updates with the addition of new content, such as publications, lab members and projects. The only thing you have to do, once the template is properly set up, is to update the content. That way, yo can focus on the material you want to put on, without struggling on how to place the boxes, format the police and all of the complicate stuff that comes with html and css. The content, written in markdown, is human readable and therefore could be easily edited by lab members. Further, since it's all scripted, it's easy to maintain and control versions.\n\nTake few minutes to look at the final webpage at https://poisotlab.io/\n\nNow you will clone the repository on your own computer so that you could start playing with the content, edit the files, modify list of papers and so on.\n\nYou can either use the clone button on the top of the page or the following command :\n\n``` bash\ngit clone https://github.com/bios2/Hugo-training-workshop.git\n```\n\nWe will take a few minutes to look at the content of the different folders. This structure is common to most of the Hugo templates. You will find multiple folders, it's useful to understand what's located where because the compiler expects this structure when it looks for specific information.\n\n**archetypes** (not in here, but usually in most templates). These are basic instructions to generate new content with the *hugo new* command. We won't use this feature today, but information about this feature is easy to find.\n\n**assets** contains the css files where the controls for visual aspect of the pages are specified. That's where you'll search for the different items and how to specify things such as box sizes, font colors and dimensions etc.... Note: assets directory is not created by default.\n\n**content** holds all of the .md files where the main content of the pages is provided. It's divided in several subfolders, corresponding to the different pages from the menu. Each top-level folder in Hugo is considered a content section (which is described usually in the config file). For instance, you have one folder called **Research** where the projects are described. You'll find one .md file per projec tin this folder. Note also that the folders contain systematically a \\_index.md file where the metadata and the top level information of the page are specified. We'll come back to that later.\n\n**data** stores specific information that will be consulted by the parser during compilation (configurationfiles). There are also data templates, and at the moment, there is one json file where the papers are listed and two toml files with a list of the students, past and present. json files could be edited with a text editor (not so fun), but there are some tools to do it efficiently.\n\n**layouts** contains the core files to compile the website. You will find in them instructions, in a strange blend of html and Go langages. No so easy and pleasant to play with, but looking at them tells you a bit about what the compiler does (a good example is for *people*). *list.html* for instance contains a loop that goes through the toml files in order to create the icons, the text and the link to the full markdown page where you have description for each student. You will find layouts for the main pages, as well as for partials (like the header menu).\n\n**resources** also contains css instructions for the template. We won't work with this one.\n\n**static** contains bunch of little things that are called during compilation. You'll find the logo for the lab, the pictures for students, pdf files for applications, images for each research project ...\n\nThere is also one very important file in the main folder the **config.toml** file. Inside, you will find a lot of the metadata that will control the structure of the main page. This find can be very simple for some templates, much more complicated for other ones. Note that for some templates, the config file may be in a distinct folder. Not all templates have exactly the same folder structure.\n\n*toml* is a file format for configuration files, it contains key parameters for the webpage. It consists of key = \"value\" pairs, \\[section names\\], and \\# comments. Let's open this one to have a closer look.\n\n## Exercise : Edit the toml file to include your own information.\n\nYou may want to change the section *People* to *Collaborators* and also provide a proper reference to your on github page. You can also add or remove sections, this will affect the menu at the top of the page. For instance, you can add a blog section.\n\n# Build the static html files\n\n## Build for local development\n\nHugo will use all of the material to generate static html files that will be displayed on your browser. The command is really easy to use to run it on your own computer, you simply have to type the following in the main folder :\n\n``` bash\nhugo server\n```\n\nAnd that's it, it compiles and you can simply open it in your browser by clicking on the adress indicated in the terminal. Congratulations for your first Hugo webste !\n\nThere are useful information in the terminal about the building process.\n\n## Build for publishing your website\n\nThe command *hugo server* is very fast and useful to test your website while you develop it. But once you'll be ready to distribute it, you'll need all of the html files and related material to distribute the website. This is easily done with the even simpler command\n\n``` bash\nhugo\n```\n\nYou will find in the directory that a new folder named **public** appeared, with all of the material needed to deploy the website. If you click on the *index.html* file, you'll get to the home page of the website. It is interesting to open this file in your text editor, you'll get a sense of the html code that hugo generated automatically for you. You can also take a look at other files.\n\n# Edit content\n\nEditing content is the easier thing to do. First thing to do, is to modify the content of the introduction paragraph on the main page. You'll find it in the \\*\\_index.md\\* file in the **content** folder. Open it and modify the text. You can after build the main page again to see the update.\n\nYou can also add material, with new md files. We will do so with a new research project (note the following could be done manually):\n\n``` bash\nhugo new research/chapter1.md\n```\n\nThis will generate a new markdown file, in which you can start adding material. But those files do have a particular structure, so before editing it, we'll take a quick look at another one, *datascience.md*.\n\nThe header section is typical of a markdown file with metadata (in toml or yaml format). You have to specify information to the parser about the title, the image and associated papers. Note that it will work if some of these (e.g. papers) are missing. You can modify the image as well.\n\nThe file here also a particular structure, with the marker between two paragraphs. This command indicates that only the first paragraph is displayed on the main page of the **Research** tab, and the full content follows if you click to know more about the project.\n\nNote that here you can use the basic features of markdown, with headers, bold, italics and so on. You can also include html code directly into the markdown and it should work. That said, it may conflict with higher level instructions in the layout or in the theme and may cause difficulties at building. While it is feasible to add such command, it is not recommended to do so. People rather suggest to use shortcodes (Tomorrow) or to modify the layout of the website.\n\n## Exercise\n\nTake 15 minutes to remove Tim's material and replace it by the three chapters of your thesis.\n\n# Hosting the website on a server\n\nThere are many options to host your new website on a server. An easy one, free, and that could be coupled with version control is to run it on github. Full instructions are available here :\n\nhttps://gohugo.io/hosting-and-deployment/hosting-on-github/\n\nWe will simply follow the instructions copied here for hosting a personal page. Note that you can also develop a page for a project.\n\n## GitHub User or Organization Pages\n\n### Step-by-step Instructions\n\n1. Create a (e.g. blog) repository on GitHub. This repository will contain Hugo's content and other source files.\n2. Create a .github.io GitHub repository. This is the repository that will contain the fully rendered version of your Hugo website.\n3. git clone && cd \n4. Paste your existing Hugo project into the new local repository. Make sure your website works locally (hugo server or hugo server -t ) and open your browser to http://localhost:1313.\n5. Once you are happy with the results: Press Ctrl+C to kill the server Before proceeding run rm -rf public to completely remove the public directory\n6. git submodule add -b main https://github.com//.github.io.git public. This creates a git submodule. Now when you run the hugo command to build your site to public, the created public directory will have a different remote origin (i.e. hosted GitHub repository).\n7. Make sure the baseURL in your config file is updated with: .github.io\n\n### Put it Into a Script\n\nYou're almost done. In order to automate next steps create a deploy.sh script. You can also make it executable with chmod +x deploy.sh.\n\nThe following are the contents of the deploy.sh script:\n\n``` bash\n #!/bin/sh\n\n # If a command fails then the deploy stops\n set -e\n\n printf \"\\033[0;32mDeploying updates to GitHub...\\033[0m\\n\"\n\n # Build the project.\n hugo # if using a theme, replace with `hugo -t `\n\n # Go To Public folder\n cd public\n\n # Add changes to git.\n git add .\n\n # Commit changes.\n msg=\"rebuilding site $(date)\"\n if [ -n \"$*\" ]; then\n msg=\"$*\"\n fi\n git commit -m \"$msg\"\n```\n\n# Push source and build repos.\n\n``` bash\ngit push origin main\n```\n\nYou can then run `./deploy.sh \"Your optional commit message\"` to send changes to .github.io. Note that you likely will want to commit changes to your repository as well.\n\nThat's it! Your personal page should be up and running at https://.github.io within a couple minutes.\n\n## Using a theme\n\nIt is usually a good idea to not modify a template directly, but to have the template and the site in a separate folder. The basic concept when doing this is that the config.toml file of the site has to link to the proper folder of the theme.\n\nFor example\n\n``` toml\ntheme = \"template-site\"\nthemesDir = \"../..\"\n```\n\nThis means that the template site is in a folder named template-site which is a parent folder of the site folder. Other options are possible.\n\nUsually, all the content should go in the site folder, not in the theme folder.\n\n### Exercise 1\n\n- Start modifying the theme to make it look like a website for a Zoo. Choose your preferred color scheme by changing the style= parameter in the config.toml file.\n\n- Feel free to download some images from [unsplash](https://unsplash.com) and save them in the static/img folder. You can then use these images in the carrousel, as \"testimonial\" photos or as background images for some of the sections. You can add or remove sections from the home page by editing the config.toml file and changing the enable= parameter in the params. segment at the bottom.\n\n- You can also try to create a new blog entry by adding a new file in the content/blog folder. This file will have a .md extension and will be written in markdown format.\n\n## Customizing a theme\n\n## Basics of HTML\n\nCore structure of an HTML page\n\n``` html\n\n\n\nThis is my great website\n\n\n\n

Main title

\n
Main content goes here
\n\n\n```\n\n### A divider, used to organize content into blocks\n\n``` html\n
\n```\n\n### A span, used to organize content or text into sections with different styles. Usually on the same line.\n\n``` html\n\n```\n\n### A paragraph\n\n``` html\n

\n```\n\n### Headings at different levels\n\n``` html\n

Main title

\n

Second level

\n

Third level

\n```\n\n### An image\n\n``` html\n\n```\n\n### A link\n\n``` html\nGreat website here!\n```\n\n## Link between HTML and CSS\n\n### In html\n\nid is always unique. Class is not.\n\n``` html\n
\nOne great div!\n
\n```\n\n### In CSS\n\n\"\\#\" is applied to id and \".\" is applied to class. When nothing is specified, applies to tag.\n\n``` css\n#this-div-only{\n font-size:24px;\n}\n\n.this-type-of-div{\n color: #bb0000;\n}\n\ndiv{\n display:block;\n}\n```\n\n## Basics of CSS\n\n[W3 Schools CSS reference](https://www.w3schools.com/cssref/)\n\n| Property | Description | Example |\n|------------------------|------------------------|------------------------|\n| width, height | width of item | 200px, 200pt, 100%, 100vw/vh |\n| min-width, min-height | minimum size of item | 200px, 200pt, 100%, 100vw |\n| color | font color | #aa0000, red or rgb(255,0,0) |\n| background-color | color of background | #aa0000, red or rgb(255,0,0) |\n| border-color | color of border | #aa0000, red or rgb(255,0,0) |\n| border | size, type and color of border | 1px solid black |\n| margin | margin around item (top right bottom left) | 1px, or 1px 2px 2px 1px |\n| padding | padding within item, inside div for example | 10px |\n| font-family | name of font | Verdana, Arial |\n| font-size | size of text | 14px, 2em |\n| display | should item be on the same line, or in a separate block? | inline, block, inline-block, flex, ... |\n\n### Exercise 2\n\n- Create a file named custom.css under template-site/my-site/static/css/.\n\n- Right-click on elements on the web page that you want to modify, then click on Inspect element and try to find CSS properties that you could modify to improve the look of the page. Then, choosing the proper class, add entries in the custom.css file that start with a dot (.) followed by the proper class names.\n\n``` css\n.this-class {\n font-size:28px;\n}\n```\n\n## Partials\n\nPartials are snippets of HTML code that could be reused on different places on the website. For example, you will see that the layouts/index.html file in the template-site folder lists all the partials that create the home page.\n\nAn important point to remember is that Hugo will look for files first in the site's folders, and if it doesn't find the files there, it will look for them in the theme's folder. So site folder layouts and CSS take priority over the theme folder.\n\n### Exercise 3\n\n- Create a new folder template-site/my-site/layouts. In this folder, create a new file named index.html and copy the content of the template-site/layouts/index.html file into it. Remove the testimonials section from the newly created file.\n\n- Create a new folder template-site/my-site/layouts/partials. In this folder, create a new file named featured-species.html put the following content into it, replacing the information with the species you selected.\n\n``` html\n
\n\"\"\n
\n

Red-Eyed Tree Frog

\n

This frog can be found in the tropical rain forests of Costa Rica.

\n
\n
\n```\n\n- Then, add this section to the index.html file created above.\n\n\n\n {{ partial \"featured_species.html\" . }}\n\n- You will probably need to restart the Hugo server to see the changes appear on the site.\n\n- Now, you need to edit the CSS! In your custom.css file, add the following lines.\n\n``` css\n\n.featured-species{\n height:300px;\n background-color: #1d1f20;\n color:white;\n}\n\n.species-image{\n height:300px;\n float:left;\n}\n\n.featured-species h3{\n color:white;\n font-size:1.5em;\n}\n\n.species-description{\n float:left;\n padding:20px;\n font-size:2em;\n}\n```\n\nModify this as you see fit!\n\n## Now a bit of GO lang to make the featured species different.\n\n[Introduction to Hugo templating](https://gohugo.io/templates/introduction/)\n\n### Exercise 4\n\n- Replace your partial featured-species.html content with this one\n\n``` html\n{{ range .Site.Data.species }}\n {{ if eq (.enable) true }}\n
\n \"\"\n
\n

{{ .name }}

\n

{{ .description }}

\n
\n
\n {{end}}\n{{end}}\n```\n\n- Now, create a new folder /template-site/my-site/data/species.\n\n- In this folder, create new file named frog.yaml with the following content.\n\n``` yaml\nenable: true\nname: \"Red-eyed tree frog\"\ndescription: \"This frog can be found in the forests of Costa Rica\"\nimage: \"frog.jpg\"\n```\n\n- Find other species photos and add them to the img folder. Then you can add new .yaml files in the data/species folder for each species.\n\n## iFrames\n\nAn iFrame is a HTML tag that essentially allows you to embed another web page inside of your site.\n\n### Exercise 5\n\nFind a Youtube video and click on the share option below the video. Find the Embed option and copy the code that starts with `\n\n```\n\nEdit the custom.css file and add this section\n\n``` css\n.video{\n width:100%;\n background-color:black;\n text-align:center;\n}\n```\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Making Websites with HUGO","description":"This workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n","author":[{"name":"Dominique Gravel"},{"name":"Guillaume Larocque"}],"image":"image.jpg","categories":["Technical","Transversal competencies","EN"],"date":"12-07-2020","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file diff --git a/.quarto/idx/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd.json b/.quarto/idx/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd.json index 18eda37..75a4125 100644 --- a/.quarto/idx/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd.json +++ b/.quarto/idx/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd.json @@ -1 +1 @@ -{"title":"4-Day Training in Spatial Statistics with Philippe Marchand","markdown":{"yaml":{"title":"4-Day Training in Spatial Statistics with Philippe Marchand","description":"Training session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). |\nSession de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n","author":"Philippe Marchand","categories":["FR","EN","Technical"],"date":"2021-01-12","image":"image.jpg","toc":true,"number-sections":true,"number-depth":1,"execute":{"freeze":true,"cache":true}},"headingText":"Spatial statistics in ecology","containsRefs":false,"markdown":"\n\nVersion en français [à la suite](#statistiques-spatiales-en-écologie).\n\n\nBIOS² hosted an online training session about statistical analysis of spatial data in ecology, led by Pr. Philippe Marchand (UQAT). This 12-hour training was conducted in 4 sessions: January 12, 14, 19 & 21 (2021) from 1:00 to 4:00 pm EST.\n\nThe content included three types of spatial statistical analyses and their applications to ecology: (1) point pattern analysis to study the distribution of individuals or events in space; (2) geostatistical models to represent the spatial correlation of variables sampled at geolocated points; and (3) areal data models, which apply to measurements taken on areas in space and model spatial relationships as networks of neighbouring regions. The training also included practical exercises using the R statistical programming environment.\n\n[Philippe Marchand](https://github.com/pmarchand1) is a professor in ecology and biostatistics at Institut de recherche sur les forêts, Université du Québec en Abitibi-Témiscamingue (UQAT) and BIOS² academic member. His research focuses on modeling processes that influence the spatial distribution of populations, including: seed dispersal and seedling establishment, animal movement, and the spread of forest diseases.\n\n**If you wish to consult the lesson materials and follow the exercises at your own pace, you can access them through [this link](https://bios2.github.io/Marchand.html#category:EN). Basic knowledge of linear regression models and experience fitting them in R is recommended. Original repository can be found [here](https://github.com/pmarchand1/BIOS2-spatial-stats).**\n\n## Course outline\n\n| Day | Topics (EN) |\n|-----------------|:--------------------------|\n| 1 | • [Introduction to spatial statistics](#introduction)
• [Point pattern analysis](#point-pattern)
|\n| 2 | • [Spatial correlation](#spatial-correlation)
• [Geostatistical models](#geostat-models) |\n| 3 | • [Areal data](#areal-data)
• [Moran's I](#moran-i)
• [Spatial autoregression models](#spatial-autoreg)
• [Analysis of areal data in R](#analysis-areal) |\n| 4 | • [GLMM with spatial Gaussian process](#glmm-spatial-gaussian)
• [GLMM with spatial autoregression](#glmm-spatial-autoreg) |\n\n\n# Introduction to spatial statistics {#introduction}\n\n## Types of spatial analyses\n\nIn this training, we will discuss three types of spatial analyses: point pattern analysis, geostatistical models and models for areal data.\n\nIn **point pattern analysis**, we have point data representing the position of individuals or events in a study area and we assume that all individuals or events have been identified in that area. That analysis focuses on the distribution of the positions of the points themselves. Here are some typical questions for the analysis of point patterns:\n\n- Are the points randomly arranged or clustered?\n\n- Are two types of points arranged independently?\n\n**Geostatistical models** represent the spatial distribution of continuous variables that are measured at certain sampling points. They assume that measurements of those variables at different points are correlated as a function of the distance between the points. Applications of geostatistical models include the smoothing of spatial data (e.g., producing a map of a variable over an entire region based on point measurements) and the prediction of those variables for non-sampled points.\n\n**Areal data** are measurements taken not at points, but for regions of space represented by polygons (e.g. administrative divisions, grid cells). Models representing these types of data define a network linking each region to its neighbours and include correlations in the variable of interest between neighbouring regions.\n\n## Stationarity and isotropy\n\nSeveral spatial analyses assume that the variables are **stationary** in space. As with stationarity in the time domain, this property means that summary statistics (mean, variance and correlations between measures of a variable) do not vary with translation in space. For example, the spatial correlation between two points may depend on the distance between them, but not on their absolute position.\n\nIn particular, there cannot be a large-scale trend (often called *gradient* in a spatial context), or this trend must be taken into account before modelling the spatial correlation of residuals.\n\nIn the case of point pattern analysis, stationarity (also called homogeneity) means that point density does not follow a large-scale trend.\n\nIn a **isotropic** statistical model, the spatial correlations between measurements at two points depend only on the distance between the points, not on the direction. In this case, the summary statistics do not change under a spatial rotation of the data.\n\n## Georeferenced data\n\nEnvironmental studies increasingly use data from geospatial data sources, i.e. variables measured over a large part of the globe (e.g. climate, remote sensing). The processing of these data requires concepts related to Geographic Information Systems (GIS), which are not covered in this workshop, where we focus on the statistical aspects of spatially varying data.\n\nThe use of geospatial data does not necessarily mean that spatial statistics are required. For example, we will often extract values of geographic variables at study points to explain a biological response observed in the field. In this case, the use of spatial statistics is only necessary when there is a spatial correlation in the residuals, after controlling for the effect of the predictors.\n\n# Point pattern analysis {#point-pattern}\n\n## Point pattern and point process\n\nA *point pattern* describes the spatial position (most often in 2D) of individuals or events, represented by points, in a given study area, often called the observation \"window\".\n\nIt is assumed that each point has a negligible spatial extent relative to the distances between the points. More complex methods exist to deal with spatial patterns of objects that have a non-negligible width, but this topic is beyond the scope of this workshop.\n\nA *point process* is a statistical model that can be used to simulate point patterns or explain an observed point pattern.\n\n## Complete spatial randomness\n\nComplete spatial randomness (CSR) is one of the simplest point patterns, which serves as a null model for evaluating the characteristics of real point patterns. In this pattern, the presence of a point at a given position is independent of the presence of points in a neighbourhood.\n\nThe process creating this pattern is a homogeneous Poisson process. According to this model, the number of points in any area $A$ follows a Poisson distribution: $N(A) \\sim \\text{Pois}(\\lambda A)$, where $\\lambda$ is the *intensity* of the process (i.e. the density of points per unit area). $N$ is independent between two disjoint regions, no matter how those regions are defined.\n\nIn the graph below, only the pattern on the right is completely random. The pattern on the left shows point aggregation (higher probability of observing a point close to another point), while the pattern in the center shows repulsion (low probability of observing a point very close to another).\n\n```{r, include = FALSE}\nlibrary(spatstat)\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\nset.seed(82)\ncsrp <- rpoispp(lambda = 100)\naggp <- rMatClust(20, 0.1, 5)\nevenp <- rMaternII(150, 0.05)\npar(mfrow = c(1, 3))\nplot(aggp, main = \"Aggregation\", pch = 19)\nplot(evenp, main = \"Repulsion\", pch = 19)\nplot(csrp, main = \"Random\", pch = 19)\n```\n\n## Exploratory or inferential analysis for a point pattern\n\nSeveral summary statistics are used to describe the characteristics of a point pattern. The simplest is the intensity $\\lambda$, which as mentioned above represents the density of points per unit area. If the point pattern is heterogeneous, the intensity is not constant, but depends on the position: $\\lambda(x, y)$.\n\nCompared to intensity, which is a first-order statistic, second-order statistics describe how the probability of the presence of a point in a region depends on the presence of other points. The Ripley's $K$ function presented in the next section is an example of a second-order summary statistic.\n\nStatistical inferences on point patterns usually consist of testing the hypothesis that the point pattern corresponds to a given null model, such as CSR or a more complex null model. Even for the simplest null models, we rarely know the theoretical distribution for a summary statistic of the point pattern under the null model. Hypothesis tests on point patterns are therefore performed by simulation: a large number of point patterns are simulated from the null model and the distribution of the summary statistics of interest for these simulations is compared to their values for the observed point pattern.\n\n## Ripley's K function\n\nRipley's K function $K(r)$ is defined as the mean number of points within a circle of radius $r$ around a point in the pattern, standardized by the intensity $\\lambda$.\n\nUnder the CSR null model, the mean number of points in any circle of radius $r$ is $\\lambda \\pi r^2$, thus in theory $K(r) = \\pi r^2$ for that model. A higher value of $K(r)$ means that there is an aggregation of points at the scale $r$, whereas a lower value means that there is repulsion.\n\nIn practice, $K(r)$ is estimated for a specific point pattern by the equation:\n\n$$ K(r) = \\frac{A}{n(n-1)} \\sum_i \\sum_{j > i} I \\left( d_{ij} \\le r \\right) w_{ij}$$\n\nwhere $A$ is the area of the observation window and $n$ is the number of points in the pattern, so $n(n-1)$ is the number of distinct pairs of points. We take the sum for all pairs of points of the indicator function $I$, which takes a value of 1 if the distance between points $i$ and $j$ is less than or equal to $r$. Finally, the term $w_{ij}$ is used to give extra weight to certain pairs of points to account for edge effects, as discussed in the next section.\n\nFor example, the graphs below show the estimated $K(r)$ function for the patterns shown above, for values of $r$ up to 1/4 of the window width. The red dashed curve shows the theoretical value for CSR and the gray area is an \"envelope\" produced by 99 simulations of that null pattern. The aggregated pattern shows an excess of neighbours up to $r = 0.25$ and the pattern with repulsion shows a significant deficit of neighbours for small values of $r$.\n\n```{r, include = FALSE}\nkagg <- envelope(aggp, Kest, correction = \"iso\") \nkeven <- envelope(evenp, Kest, correction = \"iso\")\nkcsr <- envelope(csrp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\npar(mfrow = c(1, 3))\nplot(kagg, main = \"Aggregation\", legend = FALSE)\nplot(keven, main = \"Repulsion\", legend = FALSE)\nplot(kcsr, main = \"Random\", legend = FALSE)\n```\n\nIn addition to $K$, there are other statistics to describe the second-order properties of point patterns, such as the mean distance between a point and its nearest $N$ neighbours. You can refer to the Wiegand and Moloney (2013) textbook in the references to learn more about different summary statistics for point patterns.\n\n## Edge effects\n\nIn the context of point pattern analysis, edge effects are due to the fact that we have incomplete knowledge of the neighbourhood of points near the edge of the observation window, which can induce a bias in the calculation of statistics such as Ripley's $K$.\n\nDifferent methods have been developed to correct the bias due to edge effects. In Ripley's edge correction method, the contribution of a neighbour $j$ located at a distance $r$ from a point $i$ receives a weight $w_{ij} = 1/\\phi_i(r)$, where $\\phi_i(r)$ is the fraction of the circle of radius $r$ around $i$ contained in the observation window. For example, if 2/3 of the circle is in the window, this neighbour counts as 3/2 neighbours in the calculation of a statistic like $K$.\n\n![](images/ripley_edge.png)\n\nRipley's method is one of the simplest to correct for edge effects, but is not necessarily the most efficient; in particular, larger weights given to certain pairs of points tend to increase the variance of the calculated statistic. Other correction methods are presented in specialized textbooks, such as Wiegand and Moloney (2013).\n\n## Example\n\nFor this example, we use the dataset [semis_xy.csv](data/semis_xy.csv), which represents the $(x, y)$ coordinates for seedlings of two species (*sp*, B = birch and P = poplar) in a 15 x 15 m plot.\n\n```{r}\nsemis <- read.csv(\"data/semis_xy.csv\")\nhead(semis)\n```\n\nThe *spatstat* package provides tools for point pattern analysis in R. The first step consists in transforming our data frame into a `ppp` object (point pattern) with the function of the same name. In this function, we specify which columns contain the coordinates *x* and *y* as well as the *marks*, which here will be the species codes. We also need to specify an observation window (`window`) using the `owin` function, where we provide the plot limits in *x* and *y*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spatstat)\n\nsemis <- ppp(x = semis$x, y = semis$y, marks = as.factor(semis$sp),\n window = owin(xrange = c(0, 15), yrange = c(0, 15)))\nsemis\n```\n\nMarks can be numeric or categorical. Note that for categorical marks as is the case here, the variable must be explicitly converted to a factor.\n\nThe `plot` function applied to a point pattern shows a diagram of the pattern.\n\n```{r}\nplot(semis)\n```\n\nThe `intensity` function calculates the density of points of each species by unit area (here, by $m^2$).\n\n```{r}\nintensity(semis)\n```\n\nTo first analyze the distribution of each species separately, we split the pattern with `split`. Since the pattern contains categorical marks, it is automatically split according to the values of those marks. The result is a list of two point patterns.\n\n```{r}\nsemis_split <- split(semis)\nplot(semis_split)\n```\n\nThe `Kest` function calculates Ripley's $K$ for a series of distances up to (by default) 1/4 of the width of the window. Here we apply it to the first pattern (birch) by choosing `semis_split[[1]]`. Note that double square brackets are necessary to choose an item from a list in R.\n\nThe argument `correction = \"iso\"` tells the function to apply Ripley's correction for edge effects.\n\n```{r}\nk <- Kest(semis_split[[1]], correction = \"iso\")\nplot(k)\n```\n\nAccording to this graph, there seems to be an excess of neighbours for distances of 1 m and above. To check if this is a significant difference, we produce a simulation envelope with the `envelope` function. The first argument of `envelope` is a point pattern to which the simulations will be compared, the second one is a function to be computed (here, `Kest`) for each simulated pattern, then we add the arguments of the `Kest` function (here, only `correction`).\n\n```{r}\nplot(envelope(semis_split[[1]], Kest, correction = \"iso\"))\n```\n\nAs indicated by the message, by default the function performs 99 simulations of the null model corresponding to complete spatial randomness (CSR).\n\nThe observed curve falls outside the envelope of the 99 simulations near $r = 2$. We must be careful not to interpret too quickly a result that is outside the envelope. Although there is about a 1% probability of obtaining a more extreme result under the null hypothesis at a given distance, the envelope is calculated for a large number of values of $r$ and is not corrected for multiple comparisons. Thus, a significant difference for a very small range of values of $r$ may be simply due to chance.\n\n### Exercise 1\n\nLooking at the graph of the second point pattern (poplar seedlings), can you predict where Ripley's $K$ will be in relation to the null hypothesis of complete spatial randomness? Verify your prediction by calculating Ripley's $K$ for this point pattern in R.\n\n## Effect of heterogeneity\n\nThe graph below illustrates a *heterogeneous* point pattern, i.e. it shows an density gradient (more points on the left than on the right).\n\n```{r, include = FALSE}\nlam_gr <- function(x, y) ifelse(x < 0.5, 500*(1-x), 200*(1-x))\nhetp <- rpoispp(lam_gr)\nkhet <- envelope(hetp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nplot(hetp, pch = 19, main = \"\")\nplot(khet, main = \"\", legend = FALSE)\n```\n\nA density gradient can be confused with an aggregation of points, as can be seen on the graph of the corresponding Ripley's $K$. In theory, these are two different processes:\n\n- Heterogeneity: The density of points varies in the study area, for example due to the fact that certain local conditions are more favorable to the presence of the species of interest.\n\n- Aggregation: The mean density of points is homogeneous, but the presence of one point increases the presence of other points in its vicinity, for example due to positive interactions between individuals.\n\nHowever, it may be difficult to differentiate between the two in practice, especially since some patterns may be both heterogeneous and aggregated.\n\nLet's take the example of the poplar seedlings from the previous exercise. The `density` function applied to a point pattern performs a kernel density estimation of the density of the seedlings across the plot. By default, this function uses a Gaussian kernel with a standard deviation `sigma` specified in the function, which determines the scale at which density fluctuations are \"smoothed\". Here, we use a value of 2 m for `sigma` and we first represent the estimated density with `plot`, before overlaying the points (`add = TRUE` means that the points are added to the existing plot rather than creating a new plot).\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 2)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n```\n\nTo measure the aggregation or repulsion of points in a heterogeneous pattern, we must use the inhomogeneous version of the $K$ statistic (`Kinhom` in *spatstat*). This statistic is still equal to the mean number of neighbours within a radius $r$ of a point in the pattern, but rather than standardizing this number by the overall intensity of the pattern, it is standardized by the local estimated density. As above, we specify `sigma = 2` to control the level of smoothing for the varying density estimate.\n\n```{r}\nplot(Kinhom(semis_split[[2]], sigma = 2, correction = \"iso\"))\n```\n\nTaking into account the heterogeneity of the pattern at a scale `sigma` of 2 m, there seems to be a deficit of neighbours starting at a radius of about 1.5 m. We can now check whether this deviation is significant.\n\nAs before, we use `envelope` to simulate the `Kinhom` statistic under the null model. However, the null model here is not a homogeneous Poisson process (CSR). It is instead a heterogeneous Poisson process simulated by the function `rpoispp(dens_p)`, i.e. the points are independent of each other, but their density is heterogeneous and given by `dens_p`. The `simulate` argument of the `envelope` function specifies the function used for simulations under the null model; this function must have one argument, here `x`, even if it is not used.\n\nFinally, in addition to the arguments needed for `Kinhom`, i.e. `sigma` and `correction`, we also specify `nsim = 199` to perform 199 simulations and `nrank = 5` to eliminate the 5 most extreme results on each side of the envelope, i.e. the 10 most extreme results out of 199, to achieve an interval containing about 95% of the probability under the null hypothesis.\n\n```{r}\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 2, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\n*Note*: For a hypothesis test based on simulations of a null hypothesis, the $p$-value is estimated by $(m + 1)/(n + 1)$, where $n$ is the number of simulations and $m$ is the number of simulations where the value of the statistic is more extreme than that of the observed data. This is why the number of simulations is often chosen to be 99, 199, etc.\n\n### Exercise 2\n\nRepeat the heterogeneous density estimation and `Kinhom` calculation with a standard deviation `sigma` of 5 rather than 2. How does the smoothing level for the density estimation influence the conclusions?\n\nTo differentiate between a variation in the density of points from an interaction (aggregation or repulsion) between these points with this type of analysis, it is generally assumed that the two processes operate at different scales. Typically, we can test whether the points are aggregated at a small scale after accounting for a variation in density at a larger scale.\n\n## Relationship between two point patterns\n\nLet's consider a case where we have two point patterns, for example the position of trees of two species in a plot (orange and green points in the graph below). Each of the two patterns may or may not present an aggregation of points.\n\n```{r, echo = FALSE}\ndata(lansing)\nlansing <- subset(lansing, marks %in% c(\"maple\", \"redoak\"), drop = TRUE)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"\", legend = FALSE)\n```\n\nRegardless of whether points are aggregated at the species level, we want to determine whether the two species are arranged independently. In other words, does the probability of observing a tree of one species depend on the presence of a tree of the other species at a given distance?\n\nThe bivariate version of Ripley's $K$ allows us to answer this question. For two patterns noted 1 and 2, the function $K_{12}(r)$ calculates the mean number of points in pattern 2 within a radius $r$ from a point in pattern 1, standardized by the density of pattern 2.\n\nIn theory, this function is symmetrical, so $K_{12}(r) = K_{21}(r)$ and the result would be the same whether the points of pattern 1 or 2 are chosen as \"focal\" points for the analysis. However, the estimation of the two quantities for an observed pattern may differ, in particular because of edge effects. The variance of $K_{12}$ and $K_{21}$ between simulations of a null model may also differ, so the null hypothesis test may have more or less power depending on the choice of the focal species.\n\nThe choice of an appropriate null model is important here. In order to determine whether there is a significant attraction or repulsion between the two patterns, the position of one of the patterns must be randomly moved relative to that of the other pattern, while keeping the spatial structure of each pattern taken in isolation.\n\nOne way to do this randomization is to shift one of the two patterns horizontally and/or vertically by a random distance. The part of the pattern that \"comes out\" on one side of the window is attached to the other side. This method is called a toroidal shift, because by connecting the top and bottom as well as the left and right of a rectangular surface, we obtain the shape of a torus (a three-dimensional \"donut\").\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nset.seed(35)\nrsh <- rshift(lansing, which = 1, width = 0.5, height = 0)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Original\", legend = FALSE)\nrect(xleft = 1 - rsh$x[8], xright = 1, ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\nplot(rsh, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"After translation\", legend = FALSE)\nrect(xleft = 0, xright = rsh$x[8], ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\n```\n\nThe graph above shows a translation of the green pattern to the right, while the orange pattern remains in the same place. The green points in the shaded area are brought back on the other side. Note that while this method generally preserves the structure of each pattern while randomizing their relative position, it can have some drawbacks, such as dividing point clusters that are near the cutoff point.\n\nLet's now check whether the position of the two species (birch and poplar) is independent in our plot. The function `Kcross` calculates the bivariate $K_{ij}$, we must specify which type of point (mark) is considered as the focal species $i$ and the neighbouring species $j$.\n\n```{r}\nplot(Kcross(semis, i = \"P\", j = \"B\", correction = \"iso\"))\n```\n\nHere, the observed $K$ is lower than the theoretical value, indicating a possible repulsion between the two patterns.\n\nTo determine the envelope of the $K$ under the null hypothesis of independence of the two patterns, we must specify that the simulations are based on a translation of the patterns. We indicate that the simulations use the function `rshift` (random translation) with the argument `simulate = function(x) rshift(x, which = \"B\")`; here, the `x` argument in `simulate` corresponds to the original point pattern and the `which` argument indicates which of the patterns is translated. As in the previous case, the arguments needed for `Kcross`, i.e. `i`, `j` and `correction`, must be repeated in the `envelope` function.\n\n```{r}\nplot(envelope(semis, Kcross, i = \"P\", j = \"B\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = function(x) rshift(x, which = \"B\")))\n```\n\nHere, the observed curve is totally within the envelope, so we do not reject the null hypothesis of independence of the two patterns.\n\n### Questions\n\n1. What would be one reason for our choice to translate the points of the birch rather than poplar?\n\n2. Would the simulations generated by random translation be a good null model if the two patterns were heterogeneous?\n\n## Marked point patterns\n\nThe [fir.csv](data/fir.csv) dataset contains the $(x, y)$ coordinates of 822 fir trees in a 1 hectare plot and their status (A = alive, D = dead) following a spruce budworm outbreak.\n\n```{r}\nfir <- read.csv(\"data/fir.csv\")\nhead(fir)\n```\n\n```{r}\nfir <- ppp(x = fir$x, y = fir$y, marks = as.factor(fir$status),\n window = owin(xrange = c(0, 100), yrange = c(0, 100)))\nplot(fir)\n```\n\nSuppose that we want to check whether fir mortality is independent or correlated between neighbouring trees. How does this question differ from the previous example, where we wanted to know if the position of the points of two species was independent?\n\nIn the previous example, the independence or interaction between the species referred to the formation of the pattern itself (whether or not seedlings of one species establish near those of the other species). Here, the characteristic of interest (survival) occurs after the establishment of the pattern, assuming that all those trees were alive at first and that some died as a result of the outbreak. So we take the position of the trees as fixed and we want to know whether the distribution of status (dead, alive) among those trees is random or shows a spatial pattern.\n\nIn Wiegand and Moloney's textbook, the first situation (establishment of seedlings of two species) is called a bivariate pattern, so it is really two interacting patterns, while the second is a single pattern with a qualitative *mark*. The *spatstat* package in R does not differentiate between the two in terms of pattern definition (types of points are always represented by the `marks` argument), but the analysis methods applied to the two questions differ.\n\nIn the case of a pattern with a qualitative mark, we can define a *mark connection function* $p_{ij}(r)$. For two points separated by a distance $r$, this function gives the probability that the first point has the mark $i$ and the second the mark $j$. Under the null hypothesis where the marks are independent, this probability is equal to the product of the proportions of each mark in the entire pattern, $p_{ij}(r) = p_i p_j$ independently of $r$.\n\nIn *spatstat*, the mark connection function is computed with the `markconnect` function, where the marks $i$ and $j$ and the type of edge correction must be specified. In our example, we see that two closely spaced points are less likely to have a different status (A and D) than expected under the assumption of random and independent distribution of marks (red dotted line).\n\n```{r}\nplot(markconnect(fir, i = \"A\", j = \"D\", correction = \"iso\"))\n```\n\nIn this graph, the fluctuations in the function are due to the estimation error of a continuous $r$ function from a limited number of discrete point pairs.\n\nTo simulate the null model in this case, we use the `rlabel` function, which randomly reassigns the marks among the points of the pattern, keeping the points' positions fixed.\n\n```{r}\nplot(envelope(fir, markconnect, i = \"A\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nNote that since the `rlabel` function has only one required argument corresponding to the original point pattern, it was not necessary to specify: `simulate = function(x) rlabel(x)`.\n\nHere are the results for tree pairs of the same status A or D:\n\n```{r, fig.dim = c(10, 5)}\npar(mfrow = c(1, 2))\nplot(envelope(fir, markconnect, i = \"A\", j = \"A\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\nplot(envelope(fir, markconnect, i = \"D\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nIt therefore appears that fir mortality due to this outbreak is spatially aggregated, since trees located in close proximity to each other have a greater probability of sharing the same status than predicted by the null hypothesis.\n\n## References\n\nFortin, M.-J. and Dale, M.R.T. (2005) *Spatial Analysis: A Guide for Ecologists*. Cambridge University Press: Cambridge, UK.\n\nWiegand, T. and Moloney, K.A. (2013) *Handbook of Spatial Point-Pattern Analysis in Ecology*, CRC Press.\n\nThe dataset in the last example is a subet of the Lake Duparquet Research and Teaching Forest (LDRTF) data, available on Dryad [here](https://doi.org/10.5061/dryad.tqjq2bvwz).\n\n# Solutions\n\n### Exercise 1\n\n```{r}\nplot(envelope(semis_split[[2]], Kest, correction = \"iso\"))\n```\n\nPoplar seedlings seem to be significantly aggregated according to the $K$ function.\n\n### Exercise 2\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 5)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 5, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\nHere, as we estimate density variations at a larger scale, even after accounting for this variation, the poplar seedlings seem to be aggregated at a small scale.\n\n# Spatial correlation of a variable {#spatial-correlation}\n\n```{r setup-spatial, include=FALSE}\n# knitr::opts_chunk$set(echo = TRUE)\nlibrary(tidyverse)\nlibrary(cowplot)\ntheme_set(theme_cowplot())\n```\n\nCorrelation between measurements of a variable taken at nearby points often occurs in environmental data. This principle is sometimes referred to as the \"first law of geography\" and is expressed in the following quote from Waldo Tobler: \"Everything is related to everything else, but near things are more related than distant things\".\n\nIn statistics, we often refer to *autocorrelation* as the correlation between measurements of the same variable taken at different times (temporal autocorrelation) or places (spatial autocorrelation).\n\n## Intrinsic or induced dependence\n\nThere are two basic types of spatial dependence on a measured variable $y$: an *intrinsic* dependence on $y$, or a dependence *induced* by external variables influencing $y$, which are themselves spatially correlated.\n\nFor example, suppose that the abundance of a species is correlated between two sites located near each other:\n\n- this spatial dependence can be induced if it is due to a spatial correlation of habitat factors that are favorable or unfavorable to the species;\n\n- or it can be intrinsic if it is due to the dispersion of individuals to nearby sites.\n\nIn many cases, both types of dependence affect a given variable.\n\nIf the dependence is simply induced and the external variables that cause it are included in the model explaining $y$, then the model residuals will be independent and we can use all the methods already seen that ignore spatial correlation.\n\nHowever, if the dependence is intrinsic or due to unmeasured external factors, then the spatial correlation of the residuals in the model will have to be taken into account.\n\n## Different ways to model spatial effects\n\nIn this training, we will directly model the spatial correlations of our data. It is useful to compare this approach to other ways of including spatial aspects in a statistical model.\n\nFirst, we could include predictors in the model that represent position (e.g., longitude, latitude). Such predictors may be useful for detecting a systematic large-scale trend or gradient, whether or not the trend is linear (e.g., with a generalized additive model).\n\nIn contrast to this approach, the models we will see now serve to model a spatial correlation in the random fluctuations of a variable (i.e., in the residuals after removing any systematic effect).\n\nMixed models use random effects to represent the non-independence of data on the basis of their grouping, i.e., after accounting for systematic fixed effects, data from the same group are more similar (their residual variation is correlated) than data from different groups. These groups were sometimes defined according to spatial criteria (observations grouped into sites).\n\nHowever, in the context of a random group effect, all groups are as different from each other, e.g., two sites within 100 km of each other are no more or less similar than two sites 2 km apart.\n\nThe methods we will see here and in the next parts of the training therefore allow us to model non-independence on a continuous scale (closer = more correlated) rather than just discrete (hierarchy of groups).\n\n# Geostatistical models {#geostat-models}\n\nGeostatistics refers to a group of techniques that originated in the earth sciences. Geostatistics is concerned with variables that are continuously distributed in space and where a number of points are sampled to estimate this distribution. A classic example of these techniques comes from the mining field, where the aim was to create a map of the concentration of ore at a site from samples taken at different points on the site.\n\nFor these models, we will assume that $z(x, y)$ is a stationary spatial variable measured at points with coordinates $x$ and $y$.\n\n## Variogram\n\nA central aspect of geostatistics is the estimation of the variogram $\\gamma_z$ . The variogram is equal to half the mean square difference between the values of $z$ for two points $(x_i, y_i)$ and $(x_j, y_j)$ separated by a distance $h$.\n\n$$\\gamma_z(h) = \\frac{1}{2} \\text{E} \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h}$$\n\nIn this equation, the $\\text{E}$ function with the index $d_{ij}=h$ designates the statistical expectation (i.e., the mean) of the squared deviation between the values of $z$ for points separated by a distance $h$.\n\nIf we want instead to express the autocorrelation $\\rho_z(h)$ between measures of $z$ separated by a distance $h$, it is related to the variogram by the equation:\n\n$$\\gamma_z = \\sigma_z^2(1 - \\rho_z)$$ ,\n\nwhere $\\sigma_z^2$ is the global variance of $z$.\n\nNote that $\\gamma_z = \\sigma_z^2$ when we reach a distance where the measurements of $z$ are independent, so $\\rho_z = 0$. In this case, we can see that $\\gamma_z$ is similar to a variance, although it is sometimes called \"semivariogram\" or \"semivariance\" because of the 1/2 factor in the above equation.\n\n## Theoretical models for the variogram\n\nSeveral parametric models have been proposed to represent the spatial correlation as a function of the distance between sampling points. Let us first consider a correlation that decreases exponentially:\n\n$$\\rho_z(h) = e^{-h/r}$$\n\nHere, $\\rho_z = 1$ for $h = 0$ and the correlation is multiplied by $1/e \\approx 0.37$ each time the distance increases by $r$. In this context, $r$ is called the *range* of the correlation.\n\nFrom the above equation, we can calculate the corresponding variogram.\n\n$$\\gamma_z(h) = \\sigma_z^2 (1 - e^{-h/r})$$\n\nHere is a graphical representation of this variogram.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 5*(1-exp(-1)),\n yend = 5*(1-exp(-1))), \n arrow = arrow(length = unit(0.05, \"inches\"), ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 3.5, label = \"range\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"sill\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nBecause of the exponential function, the value of $\\gamma$ at large distances approaches the global variance $\\sigma_z^2$ without exactly reaching it. This asymptote is called a *sill* in the geostatistical context and is represented by the symbol $s$.\n\nFinally, it is sometimes unrealistic to assume a perfect correlation when the distance tends towards 0, because of a possible variation of $z$ at a very small scale. A *nugget* effect, denoted $n$, can be added to the model so that $\\gamma$ approaches $n$ (rather than 0) if $h$ tends towards 0. The term nugget comes from the mining origin of these techniques, where a nugget could be the source of a sudden small-scale variation in the concentration of a mineral.\n\nBy adding the nugget effect, the remainder of the variogram is \"compressed\" to keep the same sill, resulting in the following equation.\n\n$$\\gamma_z(h) = n + (s - n) (1 - e^{-h/r})$$\n\nIn the *gstat* package that we use below, the term $(s-n)$ is called a *partial sill* or `psill` for the exponential portion of the variogram.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 4 * (1 - exp(-x/3)) + 1,\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 4*(1-exp(-1)) + 1,\n yend = 4*(1-exp(-1)) + 1), \n arrow = arrow(length = unit(0.05, \"inches\"), \n ends = \"both\", type = \"closed\")) +\n geom_segment(aes(x = 0, xend = 0, y = 0, yend = 0.9),\n arrow = arrow(length = unit(0.05, \"inches\"),\n ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 4, label = \"range\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"sill\") +\n annotate(\"text\", x = 0.5, y = 0.5, label = \"nugget\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nIn addition to the exponential model, two other common theoretical models for the variogram are the Gaussian model (where the correlation follows a half-normal curve), and the spherical model (where the variogram increases linearly at the start and then curves and reaches the plateau at a distance equal to its range $r$). The spherical model thus allows the correlation to be exactly 0 at large distances, rather than gradually approaching zero in the case of the other models.\n\n| Model | $\\rho(h)$ | $\\gamma(h)$ |\n|------------------|-------------------------|-----------------------------|\n| Exponential | $\\exp\\left(-\\frac{h}{r}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h}{r}\\right)\\right)$ |\n| Gaussian | $\\exp\\left(-\\frac{h^2}{r^2}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h^2}{r^2}\\right)\\right)$ |\n| Spherical $(h < r)$ \\* | $1 - \\frac{3}{2}\\frac{h}{r} + \\frac{1}{2}\\frac{h^3}{r^3}$ | $s \\left(\\frac{3}{2}\\frac{h}{r} - \\frac{1}{2}\\frac{h^3}{r^3} \\right)$ |\n\n\\* For the spherical model, $\\rho = 0$ and $\\gamma = s$ if $h \\ge r$.\n\n```{r, echo = FALSE, fig.dim = c(9, 4)}\nvexp <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Exponential\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n \n\nvgau <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Gaussian\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x^2/4^2)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nvsph <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Spherical\") +\n stat_function(fun = function(x) ifelse(x < 8, 5 * (1.5*x/8 - 0.5*x^3/8^3), 5),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nplot_grid(vexp, vgau, vsph, nrow = 1)\n```\n\n## Empirical variogram\n\nTo estimate $\\gamma_z(h)$ from empirical data, we need to define distance classes, thus grouping different distances within a margin of $\\pm \\delta$ around a distance $h$, then calculating the mean square deviation for the pairs of points in that distance class.\n\n$$\\hat{\\gamma_z}(h) = \\frac{1}{2 N_{\\text{paires}}} \\sum \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h \\pm \\delta}$$\n\nWe will see in the next section how to estimate a variogram in R.\n\n## Regression model with spatial correlation\n\nThe following equation represents a multiple linear regression including residual spatial correlation:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nHere, $v$ designates the response variable and $u$ the predictors, to avoid confusion with the spatial coordinates $x$ and $y$.\n\nIn addition to the residual $\\epsilon$ that is independent between observations, the model includes a term $z$ that represents the spatially correlated portion of the residual variance.\n\nHere are suggested steps to apply this type of model:\n\n1. Fit the regression model without spatial correlation.\n\n2. Verify the presence of spatial correlation from the empirical variogram of the residuals.\n\n3. Fit one or more regression models with spatial correlation and select the one that shows the best fit to the data.\n\n# Geostatistical models in R\n\nThe *gstat* package contains functions related to geostatistics. For this example, we will use the `oxford` dataset from this package, which contains measurements of physical and chemical properties for 126 soil samples from a site, along with their coordinates `XCOORD` and `YCOORD`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gstat)\n\ndata(oxford)\nstr(oxford)\n```\n\nSuppose that we want to model the magnesium concentration (`MG1`), represented as a function of the spatial position in the following graph.\n\n```{r}\nlibrary(ggplot2)\nggplot(oxford, aes(x = YCOORD, y = XCOORD, size = MG1)) +\n geom_point() +\n coord_fixed()\n```\n\nNote that the $x$ and $y$ axes have been inverted to save space. The `coord_fixed()` function of *ggplot2* ensures that the scale is the same on both axes, which is useful for representing spatial data.\n\nWe can immediately see that these measurements were taken on a 100 m grid. It seems that the magnesium concentration is spatially correlated, although it may be a correlation induced by another variable. In particular, we know that the concentration of magnesium is negatively related to the soil pH (`PH1`).\n\n```{r}\nggplot(oxford, aes(x = PH1, y = MG1)) +\n geom_point()\n```\n\nThe `variogram` function of *gstat* is used to estimate a variogram from empirical data. Here is the result obtained for the variable `MG1`.\n\n```{r}\nvar_mg <- variogram(MG1 ~ 1, locations = ~ XCOORD + YCOORD, data = oxford)\nvar_mg\n```\n\nThe formula `MG1 ~ 1` indicates that no linear predictor is included in this model, while the argument `locations` indicates which variables in the data frame correspond to the spatial coordinates.\n\nIn the resulting table, `gamma` is the value of the variogram for the distance class centered on `dist`, while `np` is the number of pairs of points in that class. Here, since the points are located on a grid, we obtain regular distance classes (e.g.: 100 m for neighboring points on the grid, 141 m for diagonal neighbors, etc.).\n\nHere, we limit ourselves to the estimation of isotropic variograms, i.e. the variogram depends only on the distance between the two points and not on the direction. Although we do not have time to see it today, it is possible with *gstat* to estimate the variogram separately in different directions.\n\nWe can illustrate the variogram with `plot`.\n\n```{r}\nplot(var_mg, col = \"black\")\n```\n\nIf we want to estimate the residual spatial correlation of `MG1` after including the effect of `PH1`, we can add that predictor to the formula.\n\n```{r}\nvar_mg <- variogram(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford)\nplot(var_mg, col = \"black\")\n```\n\nIncluding the effect of pH, the range of the spatial correlation seems to decrease, while the plateau is reached around 300 m. It even seems that the variogram decreases beyond 400 m. In general, we assume that the variance between two points does not decrease with distance, unless there is a periodic spatial pattern.\n\nThe function `fit.variogram` accepts as arguments a variogram estimated from the data, as well as a theoretical model described in a `vgm` function, and then estimates the parameters of that model according to the data. The fitting is done by the method of least squares.\n\nFor example, `vgm(\"Exp\")` means we want to fit an exponential model.\n\n```{r}\nvfit <- fit.variogram(var_mg, vgm(\"Exp\"))\nvfit\n```\n\nThere is no nugget effect, because `psill = 0` for the `Nug` (nugget) part of the model. The exponential part has a sill at 1951 and a range of 95 m.\n\nTo compare different models, a vector of model names can be given to `vgm`. In the following example, we include the exponential, gaussian (\"Gau\") and spherical (\"Sph\") models.\n\n```{r, warning = FALSE, message = FALSE}\nvfit <- fit.variogram(var_mg, vgm(c(\"Exp\", \"Gau\", \"Sph\")))\nvfit\n```\n\nThe function gives us the result of the model with the best fit (lowest sum of squared deviations), which here is the same exponential model.\n\nFinally, we can superimpose the theoretical model and the empirical variogram on the same graph.\n\n```{r}\nplot(var_mg, vfit, col = \"black\")\n```\n\n## Regression with spatial correlation\n\nWe have seen above that the *gstat* package allows us to estimate the variogram of the residuals of a linear model. In our example, the magnesium concentration was modeled as a function of pH, with spatially correlated residuals.\n\nAnother tool to fit this same type of model is the `gls` function of the *nlme* package, which is included with the installation of R.\n\nThis function applies the *generalized least squares* method to fit linear regression models when the residuals are not independent or when the residual variance is not the same for all observations. Since the estimates of the coefficients depend on the estimated correlations between the residuals and the residuals themselves depend on the coefficients, the model is fitted by an iterative algorithm:\n\n1. A classical linear regression model (without correlation) is fitted to obtain residuals.\n\n2. The spatial correlation model (variogram) is fitted with those residuals.\n\n3. The regression coefficients are re-estimated, now taking into account the correlations.\n\nSteps 2 and 3 are repeated until the estimates are stable at a desired precision.\n\nHere is the application of this method to the same model for the magnesium concentration in the `oxford` dataset. In the `correlation` argument of `gls`, we specify an exponential correlation model as a function of our spatial coordinates and we include a possible nugget effect.\n\nIn addition to the exponential correlation `corExp`, the `gls` function can also estimate a Gaussian (`corGaus`) or spherical (`corSpher`) model.\n\n```{r}\nlibrary(nlme)\ngls_mg <- gls(MG1 ~ PH1, oxford, \n correlation = corExp(form = ~ XCOORD + YCOORD, nugget = TRUE))\nsummary(gls_mg)\n```\n\nTo compare this result with the adjusted variogram above, the parameters given by `gls` must be transformed. The range has the same meaning in both cases and corresponds to 478 m for the result of `gls`. The global variance of the residuals is the square of `Residual standard error`. The nugget effect here (0.294) is expressed as a fraction of that variance. Finally, to obtain the partial sill of the exponential part, the nugget effect must be subtracted from the total variance.\n\nAfter performing these calculations, we can give these parameters to the `vgm` function of *gstat* to superimpose this variogram estimated by `gls` on our variogram of the residuals of the classical linear model.\n\n```{r}\ngls_range <- 478\ngls_var <- 53.823^2\ngls_nugget <- 0.294 * gls_var\ngls_psill <- gls_var - gls_nugget\n\ngls_vgm <- vgm(\"Exp\", psill = gls_psill, range = gls_range, nugget = gls_nugget)\n\nplot(var_mg, gls_vgm, col = \"black\", ylim = c(0, 4000))\n```\n\nDoes the model fit the data less well here? In fact, this empirical variogram represented by the points was obtained from the residuals of the linear model ignoring the spatial correlation, so it is a biased estimate of the actual spatial correlations. The method is still adequate to quickly check if spatial correlations are present. However, to simultaneously fit the regression coefficients and the spatial correlation parameters, the generalized least squares (GLS) approach is preferable and will produce more accurate estimates.\n\nFinally, note that the result of the `gls` model also gives the AIC, which we can use to compare the fit of different models (with different predictors or different forms of spatial correlation).\n\n## Exercise\n\nThe [bryo_belg.csv](data/bryo_belg.csv) dataset is adapted from the data of this study:\n\n> Neyens, T., Diggle, P.J., Faes, C., Beenaerts, N., Artois, T. et Giorgi, E. (2019) Mapping species richness using opportunistic samples: a case study on ground-floor bryophyte species richness in the Belgian province of Limburg. *Scientific Reports* 9, 19122. https://doi.org/10.1038/s41598-019-55593-x\n\nThis data frame shows the specific richness of ground bryophytes (*richness*) for different sampling points in the Belgian province of Limburg, with their position *(x, y)* in km, in addition to information on the proportion of forest (*forest*) and wetlands (*wetland*) in a 1 km\\^2\\$ cell containing the sampling point.\n\n```{r}\nbryo_belg <- read.csv(\"data/bryo_belg.csv\")\nhead(bryo_belg)\n```\n\nFor this exercise, we will use the square root of the specific richness as the response variable. The square root transformation often allows to homogenize the variance of the count data in order to apply a linear regression.\n\na) Fit a linear model of the transformed species richness to the proportion of forest and wetlands, without taking into account spatial correlations. What is the effect of the two predictors in this model?\n\nb) Calculate the empirical variogram of the model residuals in (a). Does there appear to be a spatial correlation between the points?\n\n*Note*: The `cutoff` argument to the `variogram` function specifies the maximum distance at which the variogram is calculated. You can manually adjust this value to get a good view of the sill.\n\nc) Re-fit the linear model in (a) with the `gls` function in the *nlme* package, trying different types of spatial correlations (exponential, Gaussian, spherical). Compare the models (including the one without spatial correlation) with the AIC.\n\nd) What is the effect of the proportion of forests and wetlands according to the model in (c)? Explain the differences between the conclusions of this model and the model in (a).\n\n# Kriging\n\nAs mentioned before, a common application of geostatistical models is to predict the value of the response variable at unsampled locations, a form of spatial interpolation called kriging (pronounced with a hard \"g\").\n\nThere are three basic types of kriging based on the assumptions made about the response variable:\n\n- Ordinary kriging: Stationary variable with an unknown mean.\n\n- Simple kriging: Stationary variable with a known mean.\n\n- Universal kriging: Variable with a trend given by a linear or non-linear model.\n\nFor all kriging methods, the predictions at a new point are a weighted mean of the values at known points. These weights are chosen so that kriging provides the best linear unbiased prediction of the response variable, if the model assumptions (in particular the variogram) are correct. That is, among all possible unbiased predictions, the weights are chosen to give the minimum mean square error. Kriging also provides an estimate of the uncertainty of each prediction.\n\nWhile we will not present the detailed kriging equations here, the weights depend on both the correlations (estimated by the variogram) between the sampled points and the new point, as well of the correlations between the sampled points themselves. In other words, sampled points near the new point are given more weight, but isolated sampled points are also given more weight, because sample points close to each other provide redundant information.\n\nKriging is an interpolation method, so the prediction at a sampled point will always be equal to the measured value (the measurement is supposed to have no error, just spatial variation). However, in the presence of a nugget effect, any small displacement from the sampled location will show variability according to the nugget.\n\nIn the example below, we generate a new dataset composed of randomly-generated (x, y) coordinates within the study area as well as randomly-generated pH values based on the `oxford` data. We then apply the function `krige` to predict the magnesium values at these new points. Note that we specify the variogram derived from the GLS results in the `model` argument to `krige`.\n\n```{r}\nset.seed(14)\nnew_points <- data.frame(\n XCOORD = runif(100, min(oxford$XCOORD), max(oxford$XCOORD)),\n YCOORD = runif(100, min(oxford$YCOORD), max(oxford$YCOORD)),\n PH1 = rnorm(100, mean(oxford$PH1), sd(oxford$PH1))\n)\n\npred <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm)\nhead(pred)\n```\n\nThe result of `krige` includes the new point coordinates, the prediction of the variable `var1.pred` along with its estimated variance `var1.var`. In the graph below, we show the mean MG1 predictions from kriging (triangles) along with the measurements (circles).\n\n```{r}\npred$MG1 <- pred$var1.pred\n\nggplot(oxford, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n geom_point(data = pred, shape = 17, size = 2) +\n coord_fixed()\n```\n\nThe estimated mean and variance from kriging can be used to simulate possible values of the variable at each new point, conditional on the sampled values. In the example below, we performed 4 conditional simulations by adding the argument `nsim = 4` to the same `krige` instruction.\n\n```{r}\nsim_mg <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm, nsim = 4)\nhead(sim_mg)\n```\n\n```{r, message = FALSE, warning = FALSE, fig.dim = c(10, 5)}\nlibrary(tidyr)\nsim_mg <- pivot_longer(sim_mg, cols = c(sim1, sim2, sim3, sim4), \n names_to = \"sim\", values_to = \"MG1\")\nggplot(sim_mg, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n coord_fixed() +\n facet_wrap(~ sim)\n```\n\n# Solutions\n\n```{r}\nbryo_lm <- lm(sqrt(richness) ~ forest + wetland, data = bryo_belg)\nsummary(bryo_lm)\n```\n\nThe proportion of forest has a significant positive effect and the proportion of wetlands has a significant negative effect on bryophyte richness.\n\n```{r}\nplot(variogram(sqrt(richness) ~ forest + wetland, locations = ~ x + y,\n data = bryo_belg, cutoff = 50), col = \"black\")\n```\n\nThe variogram is increasing from 0 to at least 40 km, so there appears to be spatial correlations in the model residuals.\n\n```{r}\nbryo_exp <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corExp(form = ~ x + y, nugget = TRUE))\nbryo_gaus <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corGaus(form = ~ x + y, nugget = TRUE))\nbryo_spher <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corSpher(form = ~ x + y, nugget = TRUE))\n```\n\n```{r}\nAIC(bryo_lm)\nAIC(bryo_exp)\nAIC(bryo_gaus)\nAIC(bryo_spher)\n```\n\nThe spherical model has the smallest AIC.\n\n```{r}\nsummary(bryo_spher)\n```\n\nBoth effects are less important in magnitude and the effect of wetlands is not significant anymore. As is the case for other types of non-independent residuals, the \"effective sample size\" here is less than the number of points, since points close to each other provide redundant information. Therefore, the relationship between predictors and response is less clear than given by the model assuming all these points were independent.\n\nNote that the results for all three `gls` models are quite similar, so the choice to include spatial correlations was more important than the exact shape assumed for the variogram.\n\n\n# Areal data {#areal-data}\n\nAreal data are variables measured for regions of space, defined by polygons. This type of data is more common in the social sciences, human geography and epidemiology, where data is often available at the scale of administrative divisions.\n\nThis type of data also appears frequently in natural resource management. For example, the following map shows the forest management units of the Ministère de la Forêt, de la Faune et des Parcs du Québec.\n\n![](images/cartes_unites.png)\n\nSuppose that a variable is available at the level of these management units. How can we model the spatial correlation between units that are spatially close together?\n\nOne option would be to apply the geostatistical methods seen before, for example by calculating the distance between the centers of the polygons.\n\nAnother option, which is more adapted for areal data, is to define a network where each region is connected to neighbouring regions by a link. It is then assumed that the variables are directly correlated between neighbouring regions only. (Note, however, that direct correlations between immediate neighbours also generate indirect correlations for a chain of neighbours).\n\nIn this type of model, the correlation is not necessarily the same from one link to another. In this case, each link in the network can be associated with a *weight* representing its importance for the spatial correlation. We represent these weights by a matrix $W$ where $w_{ij}$ is the weight of the link between regions $i$ and $j$. A region has no link with itself, so $w_{ii} = 0$.\n\nA simple choice for $W$ is to assign a weight equal to 1 if the regions are neighbours, otherwise 0 (binary weight).\n\nIn addition to land divisions represented by polygons, another example of areal data consists of a grid where the variable is calculated for each cell of the grid. In this case, a cell generally has 4 or 8 neighbouring cells, depending on whether diagonals are included or not.\n\n# Moran's I {#moran-i}\n\nBefore discussing spatial autocorrelation models, we present Moran's $I$ statistic, which allows us to test whether a significant correlation is present between neighbouring regions.\n\nMoran's $I$ is a spatial autocorrelation coefficient of $z$, weighted by the $w_{ij}$. It therefore takes values between -1 and 1.\n\n$$I = \\frac{N}{\\sum_i \\sum_j w_{ij}} \\frac{\\sum_i \\sum_j w_{ij} (z_i - \\bar{z}) (z_j - \\bar{z})}{\\sum_i (z_i - \\bar{z})^2}$$\n\nIn this equation, we recognize the expression of a correlation, which is the product of the deviations from the mean for two variables $z_i$ and $z_j$, divided by the product of their standard deviations (it is the same variable here, so we get the variance). The contribution of each pair $(i, j)$ is multiplied by its weight $w_{ij}$ and the term on the left (the number of regions $N$ divided by the sum of the weights) ensures that the result is bounded between -1 and 1.\n\nSince the distribution of $I$ is known in the absence of spatial autocorrelation, this statistic serves to test the null hypothesis that there is no spatial correlation between neighbouring regions.\n\nAlthough we will not see an example in this course, Moran's $I$ can also be applied to point data. In this case, we divide the pairs of points into distance classes and calculate $I$ for each distance class; the weight $w_{ij} = 1$ if the distance between $i$ and $j$ is in the desired distance class, otherwise 0.\n\n# Spatial autoregression models {#spatial-autoreg}\n\nLet us recall the formula for a linear regression with spatial dependence:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nwhere $z$ is the portion of the residual variance that is spatially correlated.\n\nThere are two main types of autoregressive models to represent the spatial dependence of $z$: conditional autoregression (CAR) and simultaneous autoregressive (SAR).\n\n## Conditional autoregressive (CAR) model\n\nIn the conditional autoregressive model, the value of $z_i$ for the region $i$ follows a normal distribution: its mean depends on the value $z_j$ of neighbouring regions, multiplied by the weight $w_{ij}$ and a correlation coefficient $\\rho$; its standard deviation $\\sigma_{z_i}$ may vary from one region to another.\n\n$$z_i \\sim \\text{N}\\left(\\sum_j \\rho w_{ij} z_j,\\sigma_{z_i} \\right)$$\n\nIn this model, if $w_{ij}$ is a binary matrix (0 for non-neighbours, 1 for neighbours), then $\\rho$ is the coefficient of partial correlation between neighbouring regions. This is similar to a first-order autoregressive model in the context of time series, where the autoregression coefficient indicates the partial correlation.\n\n## Simultaneous autoregressive (SAR) model\n\nIn the simultaneous autoregressive model, the value of $z_i$ is given directly by the sum of contributions from neighbouring values $z_j$, multiplied by $\\rho w_{ij}$, with an independent residual $\\nu_i$ of standard deviation $\\sigma_z$.\n\n$$z_i = \\sum_j \\rho w_{ij} z_j + \\nu_i$$\n\nAt first glance, this looks like a temporal autoregressive model. However, there is an important conceptual difference. For temporal models, the causal influence is directed in only one direction: $v(t-2)$ affects $v(t-1)$ which then affects $v(t)$. For a spatial model, each $z_j$ that affects $z_i$ depends in turn on $z_i$. Thus, to determine the joint distribution of $z$, a system of equations must be solved simultaneously (hence the name of the model).\n\nFor this reason, although this model resembles the formula of CAR model, the solutions of the two models differ and in the case of SAR, the coefficient $\\rho$ is not directly equal to the partial correlation due to each neighbouring region.\n\nFor more details on the mathematical aspects of these models, see the article by Ver Hoef et al. (2018) suggested in reference.\n\nFor the moment, we will consider SAR and CAR as two types of possible models to represent a spatial correlation on a network. We can always fit several models and compare them with the AIC to choose the best form of correlation or the best weight matrix.\n\nThe CAR and SAR models share an advantage over geostatistical models in terms of efficiency. In a geostatistical model, spatial correlations are defined between each pair of points, although they become negligible as distance increases. For a CAR or SAR model, only neighbouring regions contribute and most weights are equal to 0, making these models faster to fit than a geostatistical model when the data are massive.\n\n# Analysis of areal data in R {#analysis-areal}\n\nTo illustrate the analysis of areal data in R, we load the packages *sf* (to read geospatial data), *spdep* (to define spatial networks and calculate Moran's $I$) and *spatialreg* (for SAR and CAR models).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nlibrary(spdep)\nlibrary(spatialreg)\n```\n\nAs an example, we will use a dataset that presents some of the results of the 2018 provincial election in Quebec, with population characteristics of each riding. This data is included in a *shapefile* (.shp) file type, which we can read with the `read_sf` function of the *sf* package.\n\n```{r}\nelect2018 <- read_sf(\"data/elect2018.shp\")\nhead(elect2018)\n```\n\n*Note*: The dataset is actually composed of 4 files with the extensions .dbf, .prj, .shp and .shx, but it is sufficient to write the name of the .shp file in `read_sf`.\n\nThe columns of the dataset are, in order:\n\n- the name of the electoral riding (`circ`);\n- four characteristics of the population (`age_moy` = mean age, `pct_frn` = fraction of the population that speaks mainly French at home, `pct_prp` = fraction of households that own their home, `rev_med` = median income);\n- four columns showing the fraction of votes obtained by the main parties (CAQ, PQ, PLQ, QS);\n- a `geometry` column that contains the geometric object (multipolygon) corresponding to the riding.\n\nTo illustrate one of the variables on a map, we call the `plot` function with the name of the column in square brackets and quotation marks.\n\n```{r}\nplot(elect2018[\"rev_med\"])\n```\n\nIn this example, we want to model the fraction of votes obtained by the CAQ based on the characteristics of the population in each riding and taking into account the spatial correlations between neighbouring ridings.\n\n## Definition of the neighbourhood network\n\nThe `poly2nb` function of the *spdep* package defines a neighbourhood network from polygons. The result `vois` is a list of 125 elements where each element contains the indices of the neighbouring (bordering) polygons of a given polygon.\n\n```{r}\nvois <- poly2nb(elect2018)\nvois[[1]]\n```\n\nThus, the first riding (Abitibi-Est) has 6 neighbouring ridings, for which the names can be found as follows:\n\n```{r}\nelect2018$circ[vois[[1]]]\n```\n\nWe can illustrate this network by extracting the coordinates of the center of each district, creating a blank map with `plot(elect2018[\"geometry\"])`, then adding the network as an additional layer with `plot(vois, add = TRUE, coords = coords)`.\n\n```{r, message = FALSE, warning = FALSE}\ncoords <- st_centroid(elect2018) %>%\n st_coordinates()\nplot(elect2018[\"geometry\"])\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nWe can \"zoom\" on southern Québec by choosing the limits `xlim` and `ylim`.\n\n```{r}\nplot(elect2018[\"geometry\"], \n xlim = c(400000, 800000), ylim = c(100000, 500000))\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nWe still have to add weights to each network link with the `nb2listw` function. The style of weights \"B\" corresponds to binary weights, i.e. 1 for the presence of link and 0 for the absence of link between two ridings.\n\nOnce these weights are defined, we can verify with Moran's test whether there is a significant autocorrelation of votes obtained by the CAQ between neighbouring ridings.\n\n```{r}\npoids <- nb2listw(vois, style = \"B\")\n\nmoran.test(elect2018$propCAQ, poids)\n```\n\nThe value $I = 0.68$ is very significant judging by the $p$-value of the test.\n\nLet's verify if the spatial correlation persists after taking into account the four characteristics of the population, therefore by inspecting the residuals of a linear model including these four predictors.\n\n```{r}\nelect_lm <- lm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, data = elect2018)\nsummary(elect_lm)\nmoran.test(residuals(elect_lm), poids)\n```\n\nMoran's $I$ has decreased but remains significant, so some of the previous correlation was induced by these predictors, but there remains a spatial correlation due to other factors.\n\n## Spatial autoregression models\n\nFinally, we fit SAR and CAR models to these data with the `spautolm` (*spatial autoregressive linear model*) function of *spatialreg*. Here is the code for a SAR model including the effect of the same four predictors.\n\n```{r}\nelect_sar <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids)\nsummary(elect_sar)\n```\n\nThe value given by `Lambda` in the summary corresponds to the coefficient $\\rho$ in our description of the model. The likelihood-ratio test (`LR test`) confirms that this residual spatial correlation (after controlling for the effect of predictors) is significant.\n\nThe estimated effects for the predictors are similar to those of the linear model without spatial correlation. The effects of mean age, fraction of francophones and fraction of homeowners remain significant, although their magnitude has decreased somewhat.\n\nTo fit a CAR rather than SAR model, we must specify `family = \"CAR\"`.\n\n```{r}\nelect_car <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids, family = \"CAR\")\nsummary(elect_car)\n```\n\nFor a CAR model with binary weights, the value of `Lambda` (which we called $\\rho$) directly gives the partial correlation coefficient between neighbouring districts. Note that the AIC here is slightly higher than the SAR model, so the latter gave a better fit.\n\n## Exercise\n\nThe `rls_covid` dataset, in *shapefile* format, contains data on detected COVID-19 cases (`cas`), number of cases per 1000 people (`taux_1k`) and the population density (`dens_pop`) in each of Quebec's local health service networks (RLS) (Source: Data downloaded from the Institut national de santé publique du Québec as of January 17, 2021).\n\n```{r}\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nhead(rls_covid)\n```\n\nFit a linear model of the number of cases per 1000 as a function of population density (it is suggested to apply a logarithmic transform to the latter). Check whether the model residuals are correlated between bordering RLS with a Moran's test and then model the same data with a conditional autoregressive model.\n\n## Reference\n\nVer Hoef, J.M., Peterson, E.E., Hooten, M.B., Hanks, E.M. and Fortin, M.-J. (2018) Spatial autoregressive models for statistical inference from ecological data. *Ecological Monographs* 88: 36-59.\n\n```{r setup, include=FALSE}\nset.seed(82)\n```\n\n# GLMM with spatial Gaussian process {#glmm-spatial-gaussian}\n\n## Data\n\nThe `gambia` dataset found in the *geoR* package presents the results of a study of malaria prevalence among children of 65 villages in The Gambia. We will use a slightly transformed version of the data found in the file [gambia.csv](data/gambia.csv).\n\n```{r, warning = FALSE, message = FALSE}\nlibrary(geoR)\n\ngambia <- read.csv(\"data/gambia.csv\")\nhead(gambia)\n```\n\nHere are the fields in that dataset:\n\n- *id_village*: Identifier of the village.\n- *x* and *y*: Spatial coordinates of the village (in kilometers, based on UTM coordinates).\n- *pos*: Binary response, whether the child tested positive for malaria.\n- *age*: Age of the child in days.\n- *netuse*: Whether or not the child sleeps under a bed net.\n- *treated*: Whether or not the bed net is treated.\n- *green*: Remote sensing based measure of greenness of vegetation (measured at the village level).\n- *phc*: Presence or absence of a public health centre for the village.\n\nWe can count the number of positive cases and total children tested by village to map the fraction of positive cases (or prevalence, *prev*).\n\n```{r}\n# Create village-level dataset\ngambia_agg <- group_by(gambia, id_village, x, y, green, phc) %>%\n summarize(pos = sum(pos), total = n()) %>%\n mutate(prev = pos / total) %>%\n ungroup()\nhead(gambia_agg)\n```\n\n```{r, message = FALSE, warning = FALSE}\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nWe use the `gambia.borders` dataset from the *geoR* package to trace the country boundaries with `geom_path`. Since those boundaries are in meters, we divide by 1000 to get the same scale as our points. We also use `coord_fixed` to ensure a 1:1 aspect ratio between the axes and use the `viridis` color scale, which makes it easier to visualize a continuous variable compared with the default gradient scale in *ggplot2*.\n\nBased on this map, there seems to be spatial correlation in malaria prevalence, with the eastern cluster of villages showing more high prevalence values (yellow-green) and the middle cluster showing more low prevalence values (purple).\n\n## Non-spatial GLMM\n\nFor this first example, we will ignore the spatial aspect of the data and model the presence of malaria (*pos*) as a function of the use of a bed net (*netuse*) and the presence of a public health centre (*phc*). Since we have a binary response, we need to use a logistic regression model (a GLM). Since we have predictors at both the individual and village level, and we expect that children of the same village have more similar probabilities of having malaria even after accounting for those predictors, we need to add a random effect of the village. The result is a GLMM that we fit using the `glmer` function in the *lme4* package.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(lme4)\n\nmod_glmm <- glmer(pos ~ netuse + phc + (1 | id_village), \n data = gambia, family = binomial)\nsummary(mod_glmm)\n```\n\nAccording to these results, both *netuse* and *phc* result in a decrease of malaria prevalence, although the effect of *phc* is not significant at a threshold $\\alpha = 0.05$. The intercept (0.149) is the logit of the probability of malaria presence for a child with no bednet and no public health centre, but it is the mean intercept across all villages, and there is a lot of variation between villages, based on the random effect standard deviation of 0.90. We can get the estimated intercept for each village with the function `coef`:\n\n```{r}\nhead(coef(mod_glmm)$id_village)\n```\n\nSo for example, the intercept for village 1 is around 0.94, equivalent to a probability of 72%:\n\n```{r}\nplogis(0.937)\n```\n\nwhile the intercept in village 2 is equivalent to a probability of 52%:\n\n```{r}\nplogis(0.092)\n```\n\nThe [DHARMa package](https://cran.r-project.org/web/packages/DHARMa/vignettes/DHARMa.html) provides a general method for checking whether the residuals of a GLMM are distributed according to the specified model and whether there is any residual trend. The package works by simulating replicates of each observation according to the fitted model and then determining a \"standardized residual\", which is the relative position of the observed value with respect to the simulated values, e.g. 0 if the observation is smaller than all the simulations, 0.5 if it is in the middle, etc. If the model represents the data well, each value of the standardized residual between 0 and 1 should be equally likely, so the standardized residuals should produce a uniform distribution between 0 and 1.\n\nThe `simulateResiduals` function performs the calculation of the standardized residuals, then the `plot` function plots the diagnostic graphs with the results of certain tests.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(DHARMa)\nres_glmm <- simulateResiduals(mod_glmm)\nplot(res_glmm)\n```\n\nThe graph on the left is a quantile-quantile plot of standardized residuals. The results of three statistical tests also also shown: a Kolmogorov-Smirnov (*KS*) test which checks whether there is a deviation from the theoretical distribution, a dispersion test that checks whether there is underdispersion or overdispersion, and an outlier test based on the number of residuals that are more extreme than all the simulations. Here, we get a significant result for the outliers, though the message indicates that this result might have an inflated type I error rate in this case.\n\nOn the right, we generally get a graph of standardized residuals (in *y*) as a function of the rank of the predicted values, in order to check for any leftover trend in the residual. Here, the predictions are binned by quartile, so it might be better to instead aggregate the predictions and residuals by village, which we can do with the `recalculateResiduals` function.\n\n```{r}\nplot(recalculateResiduals(res_glmm, group = gambia$id_village))\n```\n\nThe plot to the right now shows individual points, along with a quantile regression for the 1st quartile, the median and the 3rd quartile. In theory, these three curves should be horizontal straight lines (no leftover trend in the residuals vs. predictions). The curve for the 3rd quartile (in red) is significantly different from a horizontal line, which could indicate some systematic effect that is missing from the model.\n\n## Spatial GLMM with spaMM\n\nThe *spaMM* (spatial mixed models) package is a relatively new R package that can perform approximate maximum likelihood estimation of parameters for GLMM with spatial dependence, modelled either as a Gaussian process or with a CAR (we will see the latter in the last section). The package implements different algorithms, but there is a single `fitme` function that chooses the appropriate algorithm for each model type. For example, here is the same (non-spatial) model as above fit with *spaMM*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spaMM)\n\nmod_spamm_glmm <- fitme(pos ~ netuse + phc + (1 | id_village),\n data = gambia, family = binomial)\nsummary(mod_spamm_glmm)\n```\n\nNote that the estimates of the fixed effects as well as the variance of random effects are nearly identical to those obtained by `glmer` above.\n\nWe can now use *spaMM* to fit the same model with the addition of spatial correlations between villages. In the formula of the model, this is represented as a random effect `Matern(1 | x + y)`, which means that the intercepts are spatially correlated between villages following a Matérn correlation function of coordinates (*x, y*). The Matérn function is a flexible function for spatial correlation that includes a shape parameter $\\nu$ (`nu`), so that when $\\nu = 0.5$ it is equivalent to the exponential correlation but as $\\nu$ grows to large values, it approaches a Gaussian correlation. We could let the function estimate $\\nu$, but here we will fix it to 0.5 with the `fixed` argument of `fitme`.\n\n```{r}\nmod_spamm <- fitme(pos ~ netuse + phc + Matern(1 | x + y) + (1 | id_village),\n data = gambia, family = binomial, fixed = list(nu = 0.5))\nsummary(mod_spamm)\n```\n\nLet's first check the random effects of the model. The spatial correlation function has a parameter `rho` equal to 0.0513. This parameter in *spaMM* is the inverse of the range, so here the range of exponential correlation is 1/0.0513 or around 19.5 km. There are now two variance prameters, the one identified as `x + y` is the long-range variance (i.e. sill) for the exponential correlation model whereas the one identified as `id_village` shows the non-spatially correlated portion of the variation between villages.\n\nIn fact, while we left the random effects `(1 | id_village)` in the formula to represent the non-spatial portion of variation between villages, we could also represent this with a nugget effect in the geostatistical model. In both cases, it would represent the idea that even two villages very close to each other would have different baseline prevalences in the model.\n\nBy default, the `Matern` function has no nugget effect, but we can add one by specifying a non-zero `Nugget` in the initial parameter list `init`.\n\n```{r}\nmod_spamm2 <- fitme(pos ~ netuse + phc + Matern(1 | x + y),\n data = gambia, family = binomial, fixed = list(nu = 0.5),\n init = list(Nugget = 0.1))\nsummary(mod_spamm2)\n```\n\nAs you can see, all estimates are the same, except that the variance of the spatial portion (sill) is now 0.84 and the nugget is equal to a fraction 0.235 of that sill, so a variance of 0.197, which is the same as the `id_village` random effect in the version above. Thus the two formulations are equivalent.\n\nNow, recall the coefficients we obtained for the non-spatial GLMM:\n\n```{r}\nsummary(mod_glmm)$coefficients\n```\n\nIn the spatial version, both fixed effects have moved slightly towards zero, but the standard error of the effect of `phc` has decreased. It is interesting that the inclusion of spatial dependence has allowed us to estimate more precisely the effect of having a public health centre in the village. This would not always be the case: for a predictor that is also strongly correlated in space, spatial correlation in the response makes it harder to estimate the effect of this predictor, since it is confounded with the spatial effect. However, for a predictor that is not correlated in space, including the spatial effect reduces the residual (non-spatial) variance and may thus increase the precision of the predictor's effect.\n\nThe *spaMM* package is also compatible with *DHARMa* for residual diagnostics. (You can in fact ignore the warning that it is not in the class of supported models, this is due to using the `fitme` function rather than a specific algorithm function in *spaMM*.)\n\n```{r}\nres_spamm <- simulateResiduals(mod_spamm2)\nplot(res_spamm)\nplot(recalculateResiduals(res_spamm, group = gambia$id_village))\n```\n\nFinally, while we will show how to make and visualize spatial predictions below, we can produce a quick map of the estimated spatial effects in a *spaMM* model with the `filled.mapMM` function.\n\n```{r}\nfilled.mapMM(mod_spamm2)\n```\n\n## Gaussian process models vs. smoothing splines\n\nIf you are familiar with generalized additive models (GAM), you might think that the spatial variation in malaria prevalence (as shown in the map above) could be represented by a 2D smoothing spline (as a function of $x$ and $y$) within a GAM.\n\nThe code below fits the GAM equivalent of our Gaussian process GLMM above with the `gam` function in the *mgcv* package. The spatial effect is represented by the 2D spline `s(x, y)` whereas the non-spatial random effect of village is represented by `s(id_village, bs = \"re\")`, which is the same as `(1 | id_village)` in the previous models. Note that for the `gam` function, categorical variables must be explicitly converted to factors.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(mgcv)\ngambia$id_village <- as.factor(gambia$id_village)\nmod_gam <- gam(pos ~ netuse + phc + s(id_village, bs = \"re\") + s(x, y), \n data = gambia, family = binomial)\n```\n\nTo visualize the 2D spline, we will use the [*gratia* package](https://fromthebottomoftheheap.net/2018/10/23/introducing-gratia/).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gratia)\ndraw(mod_gam)\n```\n\nNote that the plot of the spline `s(x, y)` (top right) does not extend too far from the locations of the data (other areas are blank). In this graph, we can also see that the village random effects follow the expected Gaussian distribution (top left).\n\nNext, we will use both the spatial GLMM from the previous section and this GAMM to predict the mean prevalence on a spatial grid of points contained in the file [gambia_pred.csv](data/gambia_pred.csv). The graph below adds those prediction points (in black) on the previous map of the data points.\n\n```{r, message = FALSE, warning = FALSE}\ngambia_pred <- read.csv(\"data/gambia_pred.csv\")\n\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(data = gambia_pred) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nTo make predictions from the GAMM model at those points, the code below goes through the following steps:\n\n- All predictors in the model must be in the prediction data frame, so we add constant values of *netuse* and *phc* (both equal to 1) for all points. Thus, we will make predictions of malaria prevalence in the case where a net is used and a public health centre is present. We also add a constant *id_village*, although it will not be used in predictions (see below).\n\n- We call the `predict` function on the output of `gam` to produce predictions at the new data points (argument `newdata`), including standard errors (`se.fit = TRUE`) and excluding the village random effects, so the prediction is made for an \"average village\". The resulting object `gam_pred` will have columns `fit` (mean prediction) and `se.fit` (standard error). Those predictions and standard errors are on the link (logit) scale.\n\n- We add the original prediction data frame to `gam_pred` with `cbind`.\n\n- We add columns for the mean prediction and 50% confidence interval boundaries (mean $\\pm$ 0.674 standard error), converted from the logit scale to the probability scale with `plogis`. We choose a 50% interval since a 95% interval may be too wide here to contrast the different predictions on the map at the end of this section.\n\n```{r}\ngambia_pred <- mutate(gambia_pred, netuse = 1, phc = 1, id_village = 1)\n\ngam_pred <- predict(mod_gam, newdata = gambia_pred, se.fit = TRUE, \n exclude = \"s(id_village)\")\ngam_pred <- cbind(gambia_pred, as.data.frame(gam_pred))\ngam_pred <- mutate(gam_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit), # 50% CI\n hi = plogis(fit + 0.674 * se.fit))\n```\n\n*Note*: The reason we do not make predictions directly on the probability (response) scale is that the normal formula for confidence intervals applies more accurately on the logit scale. Adding a certain number of standard errors around the mean on the probability scale would lead to less accurate intervals and maybe even confidence intervals outside the possible range (0, 1) for a probability.\n\nWe apply the same strategy to make predictions from the *spaMM* spatial GLMM model. There are a few differences in the `predict` method compared with the GAMM case.\n\n- The argument `binding = \"fit\"` means that mean predictions (`fit` column) will be attached to the prediction dataset and returned as `spamm_pred`.\n\n- The `variances = list(linPred = TRUE)` tells `predict` to calculate the variance of the linear predictor (so the square of the standard error). However, it appears as an attribute `predVar` in the output data frame rather than a `se.fit` column, so we move it to a column on the next line.\n\n```{r}\nspamm_pred <- predict(mod_spamm, newdata = gambia_pred, type = \"link\",\n binding = \"fit\", variances = list(linPred = TRUE))\nspamm_pred$se.fit <- sqrt(attr(spamm_pred, \"predVar\"))\nspamm_pred <- mutate(spamm_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit),\n hi = plogis(fit + 0.674 * se.fit))\n```\n\nFinally, we combine both sets of predictions as different rows of a `pred_all` dataset with `bind_rows`. The name of the dataset each prediction originates from (`gam` or `spamm`) will appear in the \"model\" column (argument `.id`). To simplify production of the next plot, we then use `pivot_longer` in the *tidyr* package to change the three columns \"pred\", \"lo\" and \"hi\" to two columns, \"stat\" and \"value\" (`pred_tall` has thus three rows for every row in `pred_all`).\n\n```{r}\npred_all <- bind_rows(gam = gam_pred, spamm = spamm_pred, .id = \"model\")\n\nlibrary(tidyr)\npred_tall <- pivot_longer(pred_all, c(pred, lo, hi), names_to = \"stat\",\n values_to = \"value\")\n```\n\nHaving done these steps, we can finally look at the prediction maps (mean, lower and upper bounds of the 50% confidence interval) with `ggplot`. The original data points are shown in red.\n\n```{r}\nggplot(pred_tall, aes(x = x, y = y)) +\n geom_point(aes(color = value)) +\n geom_point(data = gambia_agg, color = \"red\", size = 0) +\n coord_fixed() +\n facet_grid(stat~model) +\n scale_color_viridis_c() +\n theme_minimal()\n```\n\nWhile both models agree that there is a higher prevalence near the eastern cluster of villages, the GAMM also estimates a higher prevalence at a few points (western edge and around the center) where there is no data. This is an artifact of the shape of the spline fit around the data points, since a spline is meant to fit a global, although nonlinear, trend. In contrast, the geostatistical model represents the spatial effect as local correlations and reverts to the overall mean prevalence when far from any data points, which is a safer assumption. This is one reason to choose a geostatistical / Gaussian process model in this case.\n\n## Bayesian methods for GLMMs with Gaussian processes\n\nBayesian models provide a flexible framework to express models with complex dependence structure among the data, including spatial dependence. However, fitting a Gaussian process model with a fully Bayesian approach can be slow, due the need to compute a spatial covariance matrix between all point pairs at each iteration.\n\nThe INLA (integrated nested Laplace approximation) method performs an approximate calculation of the Bayesian posterior distribution, which makes it suitable for spatial regression problems. We do not cover it in this course, but I recommend the textbook by Paula Moraga (in the references section below) that provides worked examples of using INLA for various geostatistical and areal data models, in the context of epidemiology, including models with both space and time dependence. The book presents the same Gambia malaria data as an example of a geostatistical dataset, which inspired its use in this course.\n\n# GLMM with spatial autoregression {#glmm-spatial-autoreg}\n\nWe return to the last example of the previous part, where we modelled the rate of COVID-19 cases (cases / 1000) for administrative health network divisions (RLS) in Quebec as a function of their population density. The rate is given by the \"taux_1k\" column in the `rls_covid` shapefile.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nrls_covid <- rls_covid[!is.na(rls_covid$dens_pop), ]\nplot(rls_covid[\"taux_1k\"])\n```\n\nPreviously, we modelled the logarithm of this rate as a linear function of the logarithm of population density, with the residual variance correlated among neighbouring units via a CAR (conditional autoregression) structure, as shown in the code below.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spdep)\nlibrary(spatialreg)\n\nrls_nb <- poly2nb(rls_covid)\nrls_w <- nb2listw(rls_nb, style = \"B\")\n\ncar_lm <- spautolm(log(taux_1k) ~ log(dens_pop), data = rls_covid,\n listw = rls_w, family = \"CAR\")\nsummary(car_lm)\n```\n\nAs a reminder, the `poly2nb` function in the *spdep* package creates a list of neighbours based on bordering polygons in a shapefile, then the `nb2listw` converts it to a list of weights, here binary weights (`style = \"B\"`) so that each bordering region receives the same weight of 1 in the autoregressive model.\n\nInstead of using the rates, it would be possible to model the cases directly (column \"cas\" in the dataset) with a Poisson regression, which is appropriate for count data. To account for the fact that if the risk per person were equal, cases would be proportional to population, we can add the unit's population `pop` as an *offset* in the Poisson regression. Therefore, the model would look like: `cas ~ log(dens_pop) + offset(log(pop))`. Note that since the Poisson regression uses a logarithmic link, that model with `log(pop)` as an offset assumes that `log(cas / pop)` (so the log rate) is proportional to `log(dens_pop)`, just like the linear model above, but it has the advantage of modelling the stochasticity of the raw data (the number of cases) directly with a Poisson distribution.\n\nWe do not have the population in this data, but we can estimate it from the cases and the rate (cases / 1000) as follows:\n\n```{r}\nrls_covid$pop <- rls_covid$cas / rls_covid$taux_1k * 1000\n```\n\nTo define a CAR model in *spaMM*, we need a weights matrix rather than a list of weights as in the *spatialreg* package. Fortunately, the *spdep* package also includes a function `nb2mat` to convert the neighbours list to a matrix of weights, here again using binary weights. To avoid a warning, we specify the row and column names of that matrix to be equal to the IDs associated with each unit (`RLS_code`). Then, we add a term `adjacency(1 | RLS_code)` to the model to specify that the residual variation between different groups defined by `RLS_code` is spatially correlated with a CAR structure (here, each group has only one observation since we have one data point by RLS unit).\n\n```{r}\nlibrary(spaMM)\n\nrls_mat <- nb2mat(rls_nb, style = \"B\")\nrownames(rls_mat) <- rls_covid$RLS_code\ncolnames(rls_mat) <- rls_covid$RLS_code\n\nrls_spamm <- fitme(cas ~ log(dens_pop) + offset(log(pop)) + adjacency(1 | RLS_code),\n data = rls_covid, adjMatrix = rls_mat, family = poisson)\nsummary(rls_spamm)\n```\n\nNote that the spatial correlation coefficient `rho` (0.158) is similar to the equivalent quantity in the `spautolm` model above, where it was called `Lambda`. The effect of `log(dens_pop)` is also approximately 0.2 in both models.\n\n## Reference\n\nMoraga, Paula (2019) Geospatial Health Data: Modeling and Visualization with R-INLA and Shiny. Chapman & Hall/CRC Biostatistics Series. Available online at .\n\n------------------------------------------------------------------------\n\n# Statistiques spatiales en écologie {#statistiques-spatiales-en-écologie}\n\nBIOS² a organisé une session de formation en ligne sur l'analyse statistique des données spatiales en écologie, animée par le Pr. Philippe Marchand (UQAT). Cette formation de 12 heures s'est déroulée en 4 sessions : 12, 14, 19 & 21 janvier (2021) de 13h00 à 16h00 HNE.\n\nLe contenu comprenait trois types d'analyses statistiques spatiales et leurs applications en écologie : (1) l'analyse des patrons de points qui permet d'étudier la distribution d'individus ou d'événements dans l'espace; (2) les modèles géostatistiques qui représentent la corrélation spatiale de variables échantillonnées à des points géoréférencés; et (3) les modèles de données aréales, qui s'appliquent aux mesures prises sur des régions de l'espace et qui représentent les liens spatiaux par le biais de réseaux de voisinage. La formation comprenait également des exercices pratiques utilisant l'environnement de programmation statistique R.\n\n[Philippe Marchand](https://github.com/pmarchand1) est professeur d'écologie et de biostatistique à l'Institut de recherche sur les forêts, Université du Québec en Abitibi-Témiscamingue (UQAT) et membre académique de BIOS². Ses travaux de recherche portent sur la modélisation de processus qui influencent la distribution spatiale des populations, incluant: la dispersion des graines et l'établissement des semis, le mouvement des animaux, et la propagation des épidémies forestières.\n\n**Si vous souhaitez consulter le matériel pédagogique et suivre les exercices à votre propre rythme, vous pouvez y accéder par [ce lien](https://bios2.github.io/Marchand.html#category:FR). Une connaissance de base des modèles de régression linéaire et une expérience de l'ajustement de ces modèles dans R sont recommandées. Le repositoire original se trouve [ici](https://github.com/pmarchand1/BIOS2-spatial-stats).**\n\n## Plan du cours\n\n| Jour | Sujets | \n|-----------------|:--------------------------|\n| 1 | • [Introduction aux statistiques spatiales](#introduction-fr)
• [Analyse des patrons de points](#point-pattern-fr)
|\n| 2 | • [Corrélation spatiale d'une variable](#spatial-correlation-fr)
• [Modèles géostatistiques](#geostat-models-fr) | \n| 3 | • [Données aréales](#areal-data-fr)
• [Indice de Moran](#moran-i-fr)
• [Modèles d'autorégression spatiale](#spatial-autoreg-fr)
• [Analyse des données aréales dans R](#analysis-areal-fr) |\n| 4 | • [GLMM avec processus spatial gaussien](#glmm-spatial-gaussian-fr)
• [GLMM avec autorégression spatiale](#glmm-spatial-autoreg-fr)| \n\n# Introduction aux statistiques spatiales {#introduction-fr}\n\n## Types d'analyses spatiales\n\nDans le cadre de cette formation, nous discuterons de trois types d'analyses spatiales: l'analyse des patrons de points, les modèles géostatistiques et les modèles de données aréales.\n\nDans l'**analyse des patrons de points**, nous avons des données ponctuelles représentant la position d'individus ou d'événements dans une région d'étude et nous supposons que tous les individus ou événements ont été recensés dans cette région. Cette analyse s'intéresse à la distribution des positions des points eux-mêmes. Voici quelques questions typiques de l'analyse des patrons de points:\n\n- Les points sont-ils disposés aléatoirement ou agglomérés?\n\n- Deux types de points sont-ils disposés indépendamment?\n\nLes **modèles géostatistiques** visent à représenter la distribution spatiale de variables continues qui sont mesurés à certains points d'échantillonnage. Ils supposent que les mesures de ces variables à différents points sont corrélées en fonction de la distance entre ces points. Parmi les applications des modèles géostatistiques, notons le lissage des données spatiales (ex.: produire une carte d'une variable sur l'ensemble d'une région en fonction des mesures ponctuelles) et la prédiction de ces variables pour des points non-échantillonnés.\n\nLes **données aréales** sont des mesures prises non pas à des points, mais pour des régions de l'espace représentées par des polygones (ex.: divisions du territoire, cellules d'une grille). Les modèles représentant ces types de données définissent un réseau de voisinage reliant les régions et incluent une corrélation spatiale entre régions voisines. \n\n## Stationnarité et isotropie\n\nPlusieurs analyses spatiales supposent que les variables sont **stationnaires** dans l'espace. Comme pour la stationnarité dans le domaine temporel, cette propriété signifie que les statistiques sommaires (moyenne, variance et corrélations entre mesures d'une variable) ne varient pas avec une translation dans l'espace. Par exemple, la corrélation spatiale entre deux points peut dépendre de la distance les séparant, mais pas de leur position absolue.\n\nEn particulier, il ne peut pas y avoir de tendance à grande échelle (souvent appelée *gradient* dans un contexte spatial), ou bien cette tendance doit être prise en compte afin de modéliser la corrélation spatiale des résidus.\n\nDans le cas de l'analyse des patrons de points, la stationnarité (aussi appelée homogénéité dans ce contexte) signifie que la densité des points ne suit pas de tendance à grande échelle.\n\nDans un modèle statistique **isotropique**, les corrélations spatiales entre les mesures à deux points dépendent seulement de la distance entre ces points, pas de la direction. Dans ce cas, les statistiques sommaires ne varient pas si on effectue une rotation dans l'espace.\n\n## Données géoréférencées\n\nLes études environnementales utilisent de plus en plus de données provenant de sources de données géospatiales, c'est-à-dire des variables mesurées sur une grande partie du globe (ex.: climat, télédétection). Le traitement de ces données requiert des concepts liés aux systèmes d'information géographique (SIG), qui ne sont pas couverts dans cet atelier, alors que nous nous concentrons sur les aspects statistiques de données variant dans l'espace.\n\nL'utilisation de données géospatiales ne signifie pas nécessairement qu'il faut avoir recours à des statistiques spatiales. Par exemple, il est courant d'extraire les valeurs de ces variables géographiques à des points d'étude pour expliquer une réponse biologique observée sur le terrain. Dans ce cas, l'utilisation de statistiques spatiales est seulement nécessaire en présence d'une corrélation spatiale dans les résidus, après avoir tenu compte de l'effet des prédicteurs.\n\n\n# Analyse des patrons de points {#point-pattern-fr}\n\n## Patron de points et processus ponctuel\n\nUn patron de points (*point pattern*) décrit la position spatiale (le plus souvent en 2D) d'individus ou d'événements, représentés par des points, dans une aire d'étude donnée, souvent appelée la *fenêtre* d'observation. \n\nOn suppose que chaque point a une étendue spatiale négligeable par rapport aux distances entre les points. Des méthodes plus complexes existent pour traiter des patrons spatiaux d'objets qui ont une largeur non-néligeable, mais ce sujet dépasse la portée de cet atelier.\n\nUn processus ponctuel (*point process*) est un modèle statistique qui peut être utilisé pour simuler des patrons de points ou expliquer un patron de points observé.\n\n## Structure spatiale totalement aléatoire\n\nUne structure spatiale totalement aléatoire (*complete spatial randomness*) est un des patrons les plus simples, qui sert de modèle nul pour évaluer les caractéristiques de patrons de points réels. Dans ce patron, la présence d'un point à une position donnée est indépendante de la présence de points dans un voisinage. \n\nLe processus créant ce patron est un processus de Poisson homogène. Selon ce modèle, le nombre de points dans toute région de superficie $A$ suit une distribution de Poisson: $N(A) \\sim \\text{Pois}(\\lambda A)$, où $\\lambda$ est l'*intensité* du processus (i.e. la densité de points). $N$ est indépendant entre deux régions disjointes, peu importe comment ces régions sont définies.\n\nDans le graphique ci-dessous, seul le patron à droite est totalement aléatoire. Le patron à gauche montre une agrégation des points (probabilité plus grande d'observer un point si on est à proximité d'un autre point), tandis que le patron du centre montre une répulsion (faible probabilité d'observer un point très près d'un autre).\n\n```{r, include = FALSE}\nlibrary(spatstat)\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\nset.seed(82)\ncsrp <- rpoispp(lambda = 100)\naggp <- rMatClust(20, 0.1, 5)\nevenp <- rMaternII(150, 0.05)\npar(mfrow = c(1, 3))\nplot(aggp, main = \"Agrégation\", pch = 19)\nplot(evenp, main = \"Répulsion\", pch = 19)\nplot(csrp, main = \"Aléatoire\", pch = 19)\n```\n\n## Analyse exploratoire ou inférentielle pour un patron de points\n\nPlusieurs statistiques sommaires sont utilisées pour décrire les caractéristiques un patron de points. La plus simple est l'**intensité** $\\lambda$, qui comme mentionné plus haut représente la densité de points par unité de surface. Si le patron de points est hétérogène, l'intensité n'est pas constante, mais dépend de la position: $\\lambda(x, y)$.\n\nPar rapport à l'intensité qui est une statistique dite de premier ordre, les statistiques de second ordre décrivent comment la probabilité de présence d'un point dans une région dépend de la présence d'autres points. L'indice $K$ de Ripley présenté dans la prochaine section est un exemple de statistique sommaire de second ordre.\n\nLes inférences statistiques réalisées sur des patrons de points consistent habituellement à tester l'hypothèse que le patron de points correspond à un modèle nul donné, par exemple une structure spatiale totalement aléatoire, ou un modèle nul plus complexe. Même pour les modèles nuls les plus simples, nous connaissons rarement la distribution théorique pour une statistique sommaire du patron de points sous le modèle nul. Les tests d'hypothèses sur les patrons de points sont donc réalisés par simulation: on simule un grand nombre de patrons de points à partir du modèle nul et on compare la distribution des statistiques sommaires qui nous intéressent pour ces simulations à la valeur des statistiques pour le patron de points observé.\n\n## Indice $K$ de Ripley\n\nL'indice de Ripley $K(r)$ est défini comme le nombre moyen de points se trouvant dans un cercle de rayon $r$ donné autour d'un point du patron, normalisé par l'intensité $\\lambda$. \n\nPour un patron totalement aléatoire, le nombre moyen de points dans un cercle de rayon $r$ est $\\lambda \\pi r^2$, donc en théorie $K(r) = \\pi r^2$ pour ce modèle nul. Une valeur de $K(r)$ supérieure signifie qu'il y a agrégation des points à l'échelle $r$, tandis qu'une valeur inférieure signifie qu'il y a une répulsion.\n\nEn pratique, $K(r)$ est estimé pour un patron de points donné par l'équation:\n\n$$ K(r) = \\frac{A}{n(n-1)} \\sum_i \\sum_{j > i} I \\left( d_{ij} \\le r \\right) w_{ij}$$\n\noù $A$ est l'aire de la fenêtre d'observation et $n$ est le nombre de points du patron, donc $n(n-1)$ est le nombre de paires de points distinctes. On fait la somme pour toutes les paires de points de la fonction indicatrice $I$, qui prend une valeur de 1 si la distance entre les points $i$ et $j$ est inférieure ou égale à $r$. Finalement, le terme $w_{ij}$ permet de donner un poids supplémentaire à certaines paires de points pour tenir compte des effets de bordure, tel que discuté dans la section suivante.\n\nPar exemple, les graphiques ci-dessous présentent la fonction estimée $K(r)$ pour les patrons illustrés ci-dessus, pour des valeurs de $r$ allant jusqu'à 1/4 de la largeur de la fenêtre. La courbe pointillée rouge indique la valeur théorique pour une structure spatiale totalement aléatoire et la zone grise est une \"enveloppe\" produite par 99 simulations de ce modèle nul. Le patron agrégé montre un excès de voisins jusqu'à $r = 0.25$ et le patron avec répulsion montre un déficit significatif de voisins pour les petites valeurs de $r$. \n\n```{r, include = FALSE}\nkagg <- envelope(aggp, Kest, correction = \"iso\") \nkeven <- envelope(evenp, Kest, correction = \"iso\")\nkcsr <- envelope(csrp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\npar(mfrow = c(1, 3))\nplot(kagg, main = \"Agrégation\", legend = FALSE)\nplot(keven, main = \"Répulsion\", legend = FALSE)\nplot(kcsr, main = \"Aléatoire\", legend = FALSE)\n```\n\nOutre le $K$, il existe d'autres statistiques pour décrire les propriétés de second ordre du patron, par exemple la distance moyenne entre un point et ses $N$ plus proches voisins. Vous pouvez consulter le manuel de Wiegand et Moloney (2013) suggéré en référence pour en apprendre plus sur différentes statistiques sommaires des patrons de points.\n\n## Effets de bordure\n\nDans le contexte de l'analyse de patrons de points, l'effet de bordure (\"edge effect\") est dû au fait que nous avons une connaissance incomplète du voisinage des points près du bord de la fenêtre d'observation, ce qui peut induire un biais dans le calcul des statistiques comme le $K$ de Ripley. \n\nDifférentes méthodes ont été développées pour corriger le biais dû aux effets de bordure. Selon la méthode de Ripley, la contribution d'un voisin $j$ situé à une distance $r$ d'un point $i$ reçoit un poids $w_{ij} = 1/\\phi_i(r)$, où $\\phi_i(r)$ est la fraction du cercle de rayon $r$ autour de $i$ contenu dans la fenêtre d'observation. Par exemple, si 2/3 du cercle se trouve dans la fenêtre, ce voisin compte pour 3/2 voisins dans le calcul d'une statistique comme $K$.\n\n![](images/ripley_edge.png)\n\nLa méthode de Ripley est une des plus simples pour corriger les effets de bordure, mais n'est pas nécessairement la plus efficace; notamment, les poids plus grands donnés à certaines paires de points tend à accroître la variance du calcul de la statistique. D'autres méthodes de correction sont présentées dans les manuels spécialisés, comme celui de Wiegand et Moloney (2013) en référence.\n\n## Exemple\n\nPour cet exemple, nous utilisons le jeu de données [semis_xy.csv](data/semis_xy.csv), qui représente les coordonnées $(x, y)$ de semis de deux espèces (*sp*, B = bouleau et P = peuplier) dans une placette de 15 x 15 m.\n\n```{r}\nsemis <- read.csv(\"data/semis_xy.csv\")\nhead(semis)\n```\n\nLe package *spatstat* permet d'effectuer des analyses de patrons de point dans R. La première étape consiste à transformer notre tableau de données en objet `ppp` (patron de points) avec la fonction du même nom. Dans cette fonction, nous spécifions quelles colonnes contiennent les coordonnées *x* et *y* ainsi que les marques (`marks`), qui seront ici les codes d'espèce. Il faut aussi spécifier une fenêtre d'observation (`window`) à l'aide de la fonction `owin`, à laquelle nous indiquons les limites de la placette en *x* et *y*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spatstat)\n\nsemis <- ppp(x = semis$x, y = semis$y, marks = as.factor(semis$sp),\n window = owin(xrange = c(0, 15), yrange = c(0, 15)))\nsemis\n```\n\nLes marques peuvent être numériques ou catégorielles. Notez que pour des marques catégorielles comme c'est le cas ici, il faut convertir explicitement la variable en facteur.\n\nLa fonction `plot` appliquée à un patron de points montre un diagramme du patron.\n\n```{r}\nplot(semis)\n```\n\nLa fonction `intensity` calcule la densité des points de chaque espèce par unité de surface, ici en $m^2$.\n\n```{r}\nintensity(semis)\n```\n\nPour analyser d'abord séparément la distribution de chaque espèce, nous séparons le patron avec `split`. Puisque le patron contient des marques catégorielles, la séparation se fait automatiquement en fonction de la valeur des marques. Le résultat est une liste de deux patrons de points.\n\n```{r}\nsemis_split <- split(semis)\nplot(semis_split)\n```\n\nLa fonction `Kest` calcule le $K$ de Ripley pour une série de distances allant (par défaut) jusqu'à 1/4 de la largeur de la fenêtre. Ici, nous l'appliquons au premier patron (bouleau) en choisissant `semis_split[[1]]`. Notez que les doubles crochets sont nécessaires pour choisir un élément d'une liste dans R.\n\nL'argument `correction = \"iso\"` indique d'appliquer la méthode de Ripley pour corriger les effets de bordure.\n\n```{r}\nk <- Kest(semis_split[[1]], correction = \"iso\")\nplot(k)\n```\n\nSelon ce graphique, il semble y avoir une excès de voisins à partir d'un rayon de 1 m. Pour vérifier s'il s'agit d'un écart significatif, nous produisons une enveloppe de simulation avec la fonction `envelope`. Le permier argument d'`envelope` est un patron de point auquel les simulations seront comparées, le deuxième une fonction à calculer (ici, `Kest`) pour chaque patron simulé, puis on y ajoute les arguments de la fonction `Kest` (ici, seulement `correction`).\n\n```{r}\nplot(envelope(semis_split[[1]], Kest, correction = \"iso\"))\n```\n\nTel qu'indiqué par le message, cette fonction effectue par défaut 99 simulations de l'hypothèse nulle correspondant à une structure spatiale totalement aléatoire (CSR, pour *complete spatial randomness*).\n\nLa courbe observée sort de l'enveloppe des 99 simulations près de $r = 2$. Il faut être prudent de ne pas interpréter trop rapidement un résultat sortant de l'enveloppe. Même s'il y a environ une probabilité de 1% d'obtenir un résultat plus extrême selon l'hypothèse nulle à une distance donnée, l'enveloppe est calculée pour un grand nombre de valeurs de la distance et nous n'effectuons pas de correction pour les comparaisons multiples. Ainsi, un écart significatif pour une très petite plage de valeurs de $r$ peut être simplement dû au hasard.\n\n\n### Exercice 1\n\nEn regardant le graphique du deuxième patron de points (semis de peuplier), pouvez-vous prédire où se situera le $K$ de Ripley par rapport à l'hypothèse nulle d'une structure spatiale totalement aléatoire? Vérifiez votre prédiction en calculant le $K$ de Ripley pour ce patron de points dans R.\n\n\n## Effet de l'hétérogénéité\n\nLe graphique ci-dessous illustre un patron de points *hétérogène*, c'est-à-dire qu'il présente un gradient d'intensité (plus de points à gauche qu'à droite).\n\n```{r, include = FALSE}\nlam_gr <- function(x, y) ifelse(x < 0.5, 500*(1-x), 200*(1-x))\nhetp <- rpoispp(lam_gr)\nkhet <- envelope(hetp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nplot(hetp, pch = 19, main = \"\")\nplot(khet, main = \"\", legend = FALSE)\n```\n\nUn gradient de densité peut être confondu avec une agrégation des points, comme on peut voir sur le graphique du $K$ de Ripley correspondant. En théorie, il s'agit de deux processus différents:\n\n- Hétérogénéité: La densité de points varie dans la région d'étude, par exemple dû au fait que certaines conditions locales sont plus propices à la présence de l'espèce étudiée.\n\n- Agrégation: La densité moyenne des points est homogène, mais la présence d'un point augmente la présence d'autre points dans son voisinage, par exemple en raison d'interactions positives entre les individus.\n\nCependant, il peut être difficile de différencier les deux en pratique, surtout que certains patrons peuvent être à la fois hétérogènes et agrégés.\n\nPrenons l'exemple des semis de peuplier de l'exercice précédent. La fonction `density` appliquée à un patron de points effectue une estimation par noyau (*kernel density estimation*) de la densité des semis à travers la placette. Par défaut, cette fonction utilise un noyau gaussien avec un écart-type `sigma` spécifié dans la fonction, qui détermine l'échelle à laquelle les fluctuations de densité sont \"lissées\". Ici, nous utilisons une valeur de 2 m pour `sigma` et nous représentons d'abord la densité estimée avec `plot`, avant d'y superposer les points (`add = TRUE` signifie que les points sont ajoutés au graphique existant plutôt que de créer un nouveau graphique).\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 2)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n```\n\nPour mesurer l'agrégation ou la répulsion des points d'un patron hétérogène, nous devons utilisé la version non-homogène de la statistique $K$ (`Kinhom` dans *spatstat*). Cette statistique est toujours égale au nombre moyen de voisins dans un rayon $r$ d'un point du patron, mais plutôt que de normaliser ce nombre par l'intensité globale du patron, il est normalisé par l'estimation locale de la densité de points. Comme ci-dessus, nous spécifions `sigma = 2` pour contrôler le niveau de lissage de l'estimation de la densité variable.\n\n```{r}\nplot(Kinhom(semis_split[[2]], sigma = 2, correction = \"iso\"))\n```\n\nEn tenant compte de l'hétérogénéité du patron à une échelle `sigma` de 2 m, il semble donc y avoir un déficit de voisins à partir d'environ 1.5 m des points du patron. Il reste à voir si cette déviation est significative.\n\nComme précédemment, nous utilisons `envelope` pour simuler la statistique `Kinhom` sous le modèle nul. Cependant, ici le modèle nul n'est pas un processus de Poisson homogène (structure spatiale totalement aléatoire). Il s'agit plutôt d'un processus de Poisson hétérogène simulé par la fonction `rpoispp(dens_p)`, c'est-à-dire que les points sont indépendants les uns des autres, mais leur densité est hétérogène et donnée par `dens_p`. L'argument `simulate` de la fonction `envelope` permet de spécifier une fonction utilisée pour les simulations sous le modèle nul; cette fonction doit avoir un argument, ici `x`, même s'il n'est pas utilisé.\n\nFinalement, en plus des arguments nécessaires pour `Kinhom`, soit `sigma` et `correction`, nous spécifions aussi `nsim = 199` pour réaliser 199 simulations et `nrank = 5` pour éliminer les 5 résultats les plus extrêmes de chaque côté de l'enveloppe, donc les 10 plus extrêmes sur 199, pour réaliser un intervalle contenant environ 95% de la probabilité sous l'hypothèse nulle.\n\n```{r}\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 2, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\n*Note*: Pour un test d'hypothèse basé sur des simulations d'une hypothèse nulle, la valeur $p$ est estimée par $(m + 1)/(n + 1)$, où $n$ est le nombre de simulations et $m$ est le nombre de simulations où la valeur de la statistique est plus extrême que celle des données observées. C'est pour cette raison qu'on choisit un nombre de simulations comme 99, 199, etc.\n\n### Exercice 2\n\nRépétez l'estimation de la densité hétérogène et le calcul de `Kinhom` avec un écart-type `sigma` de 5 plutôt que 2. Comment le niveau de lissage pour la densité influence-t-il les conclusions?\n\nPour différencier une variation de densité des points et d'une interaction (agrégation ou répulsion) entre ces points avec ce type d'analyse, il faut généralement supposer que les deux processus opèrent à différentes échelles. Typiquement, nous pouvons tester si les points sont agrégés à petite échelle après avoir tenu compte d'une variation de la densité à une échelle plus grande.\n\n\n## Relation entre deux patrons de points\n\nConsidérons un cas où nous avons deux patrons de points, par exemple la position des arbres de deux espèces dans une parcelle (points oranges et verts dans le graphique ci-dessous). Chacun des deux patrons peut présenter ou non des agrégations de points. \n\n```{r, echo = FALSE}\ndata(lansing)\nlansing <- subset(lansing, marks %in% c(\"maple\", \"redoak\"), drop = TRUE)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"\", legend = FALSE)\n```\n\nSans égard à cette agrégation au niveau de l'espèce, nous voulons déterminer si les deux espèces sont disposées indépendamment. Autrement dit, la probabilité d'observer un arbre d'une espèce dépend-elle de la présence d'un arbre de l'autre espèce à une distance donnée?\n\nLa version bivariée du $K$ de Ripley permet de répondre à cette question. Pour deux patrons désignés 1 et 2, l'indice $K_{12}(r)$ calcule le nombre moyen de points du patron 2 dans un rayon $r$ autour d'un point du patron 1, normalisé par la densité du patron 2.\n\nEn théorie, cet indice est symétrique, donc $K_{12}(r) = K_{21}(r)$ et le résultat serait le même si on choisit les points du patron 1 ou 2 comme points \"focaux\" pour l'analyse. Cependant, l'estimation des deux quantités pour un patron observé peut différer, notamment en raison des effets de bord. La variabilité peut aussi être différente pour $K_{12}$ et $K_{21}$ entre les simulations d'un modèle nul, donc le test de l'hypothèse nulle peut avoir une puissance différente selon le choix de l'espèce focale.\n\nLe choix d'un modèle nul approprié est important ici. Afin de déterminer s'il existe une attraction ou une répulsion significative entre les deux patrons, il faut déplacer aléatoirement la position d'un des patrons relative à celle de l'autre patron, tout en conservant la structure spatiale de chaque patron pris isolément.\n\nUne des façons d'effectuer cette randomisation consiste à décaler l'un des deux patrons horizontalement et/ou verticalement d'une distance aléatoire. La partie du patron qui \"sort\" d'un côté de la fenêtre est rattachée de l'autre côté. Cette méthode s'appelle une translation toroïdale (*toroidal shift*), car en connectant le haut et le bas ainsi que la gauche et la droite d'une surface rectangulaire, on obtient la forme d'un tore (un \"beigne\" en trois dimensions).\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nset.seed(35)\nrsh <- rshift(lansing, which = 1, width = 0.5, height = 0)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Original\", legend = FALSE)\nrect(xleft = 1 - rsh$x[8], xright = 1, ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\nplot(rsh, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Après translation\", legend = FALSE)\nrect(xleft = 0, xright = rsh$x[8], ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\n```\n\nLe graphique ci-dessus illustre une translation du patron vert vers la droite, tandis que le patron orange reste au même endroit. Les points verts dans la zone ombragée sont ramenés de l'autre côté. Notez que si cette méthode préserve de façon générale la structure de chaque patron tout en randomisant leur position relative, elle peut comporter certains inconvénients, comme de diviser des amas de points qui se trouvent près du point de coupure.\n\nVérifions maintenant s'il y a une dépendance entre la position des deux espèces (bouleau et peuplier) dans notre placette. La fonction `Kcross` calcule l'indice bivarié $K_{ij}$, il faut spécifier quel type de point est considéré comme l'espèce focale $i$ et l'espèce voisine $j$.\n\n```{r}\nplot(Kcross(semis, i = \"P\", j = \"B\", correction = \"iso\"))\n```\n\nIci, le $K$ observé est inférieur à la valeur théorique, indiquant une répulsion possible des deux patrons.\n\nPour déterminer l'enveloppe du $K$ selon l'hypothèse nulle d'indépendance des deux patrons, nous devons spécifier que les simulations doivent être basées sur une translation des patrons. Nous indiquons que les simulations doivent utiliser la fonction `rshift` (translation aléatoire) avec l'argument `simulate = function(x) rshift(x, which = \"B\")`; ici, l'argument `x` de `simulate` correspond au patron de points original et l'argument `which` indique quel type de points subit la translation. Comme pour le cas précédent, il faut répéter dans la fonction `envelope` les arguments nécessaires pour `Kcross`, soit `i`, `j` et `correction`. \n\n```{r}\nplot(envelope(semis, Kcross, i = \"P\", j = \"B\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = function(x) rshift(x, which = \"B\")))\n```\n\nIci, la courbe observée se situe totalement dans l'enveloppe, donc nous ne rejetons pas l'hypothèse nulle d'indépendance des deux patrons.\n\n### Questions\n\n1. Quelle raison pourrait justifier ici notre choix d'effectuer la translation des points du bouleau plutôt que du peuplier?\n\n2. Est-ce que les simulations générées par translation aléatoire constitueraient un bon modèle nul si les deux patrons étaient hétérogènes?\n\n\n## Patrons de points marqués\n\nLe jeu de données [fir.csv](data/fir.csv) contient les coordonnées $(x, y)$ de 822 sapins dans une placette d'un hectare et leur statut (A = vivant, D = mort) suivant une épidémie de tordeuse des bourgeons de l'épinette.\n\n```{r}\nfir <- read.csv(\"data/fir.csv\")\nhead(fir)\n```\n\n```{r}\nfir <- ppp(x = fir$x, y = fir$y, marks = as.factor(fir$status),\n window = owin(xrange = c(0, 100), yrange = c(0, 100)))\nplot(fir)\n```\n\nSupposons que nous voulons vérifier si la mortalité des sapins est indépendante ou corrélée entre arbres rapprochés. En quoi cette question diffère-t-elle de l'exemple précédent où nous voulions savoir si la position des points de deux espèces était indépendante?\n\nDans l'exemple précédent, l'indépendance ou l'interaction entre les espèces référait à la formation du patron lui-même (que des semis d'une espèce s'établissent ou non à proximité de ceux de l'autre espèce). Ici, la caractéristique qui nous intéresse (survie des sapins) est postérieure à l'établissement du patron, en supposant que tous ces arbres étaient vivants d'abord et que certains sont morts suite à l'épidémie. Donc nous prenons la position des arbres comme fixe et nous voulons savoir si la distribution des statuts (mort, vivant) entre ces arbres est aléatoire ou présente un patron spatial.\n\nDans le manuel de Wiegand et Moloney, la première situation (établissement de semis de deux espèces) est appelé patron bivarié, donc il s'agit vraiment de deux patrons qui interagissent, tandis que la deuxième est un seul patron avec une *marque* qualitative. Le package *spatstat* dans R ne fait pas de différences entre les deux au niveau de la définition du patron (les types de points sont toujours représentés par l'argument `marks`), mais les méthodes d'analyse appliquées aux deux questions diffèrent.\n\nDans le cas d'un patron avec une marque qualitative, nous pouvons définir une fonction de connexion de marques (*mark connection function*) $p_{ij}(r)$. Pour deux points séparés par une distance $r$, cette fonction donne la probabilité que le premier point porte la marque $i$ et le deuxième la marque $j$. Selon l'hypothèse nulle où les marques sont indépendantes, cette probabilité est égale au produit des proportions de chaque marque dans le patron entier, $p_{ij}(r) = p_i p_j$ indépendamment de $r$.\n\nDans *spatstat*, la fonction de connexion de marques est calculée avec la fonction `markconnect`, où il faut spécifier les marques $i$ et $j$ ainsi que le type de correction des effets de bord. Dans notre exemple, nous voyons que deux points rapprochés ont moins de chance d'avoir une statut différent (A et D) que prévu selon l'hypothèse de distribution aléatoire et indépendante des marques (ligne rouge pointillée).\n\n```{r}\nplot(markconnect(fir, i = \"A\", j = \"D\", correction = \"iso\"))\n```\n\nDans ce graphique, les ondulations dans la fonction sont dues à l'erreur d'estimation d'une fonction continue de $r$ à partir d'un nombre limité de paires de points discrètes.\n\nPour simuler le modèle nul dans ce cas-ci, nous utilisons la fonction `rlabel` qui réassigne aléatoirement les marques parmi les points du patron, en maintenant la position des points.\n\n```{r}\nplot(envelope(fir, markconnect, i = \"A\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nNotez que puisque la fonction `rlabel` a un seul argument obligatoire correspondant au patron de points original, il n'était pas nécessaire de spécifier au long: `simulate = function(x) rlabel(x)`.\n\nVoici les résultats pour les paires d'arbres du même statut A ou D:\n\n```{r, fig.dim = c(10, 5)}\npar(mfrow = c(1, 2))\nplot(envelope(fir, markconnect, i = \"A\", j = \"A\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\nplot(envelope(fir, markconnect, i = \"D\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nIl semble donc que la mortalité des sapins due à cette épidémie est agrégée spatialement, puisque les arbres situés à proximité l'un de l'autre ont une plus grande probabilité de partager le même statut que prévu par l'hypothèse nulle.\n\n## Références\n\nFortin, M.-J. et Dale, M.R.T. (2005) *Spatial Analysis: A Guide for Ecologists*. Cambridge University Press: Cambridge, UK. \n\nWiegand, T. et Moloney, K.A. (2013) *Handbook of Spatial Point-Pattern Analysis in Ecology*, CRC Press.\n\nLe jeu de données du dernier exemple est tiré des données de la Forêt d'enseignement et de recherche du Lac Duparquet (FERLD), disponibles sur Dryad en suivant [ce lien](https://doi.org/10.5061/dryad.tqjq2bvwz).\n\n\n# Solutions\n\n### Exercice 1\n\n```{r}\nplot(envelope(semis_split[[2]], Kest, correction = \"iso\"))\n```\n\nLes semis de peuplier semblent significativement agrégés selon la valeur du $K$.\n\n### Exercice 2\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 5)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 5, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\nIci, puisque nous estimons la variation de densité à une plus grande échelle, même après avoir tenu compte de cette variation, les semis de peuplier semblent agrégés à petite échelle.\n\n\n# Corrélation spatiale d'une variable {#spatial-correlation-fr}\n\nLa corrélation entre les mesures d'une variable prises à des points rapprochés est une caractéristique dans de nombreux jeux de données. Ce principe est parfois appelé \"première loi de la géographie\" et exprimé par la citation de Waldo Tobler: \"Everything is related to everything else, but near things are more related than distant things.\" (Tout est relié, mais les choses rapprochées le sont davantage que celles éloignées).\n\nEn statistique, nous parlons souvent d'*autocorrélation* pour désigner la corrélation qui existe entre les mesures d'une même variable prises à différents moments (autocorrélation temporelle) ou différents lieux (autocorrélation spatiale).\n\n## Dépendance intrinsèque ou induite\n\nIl existe deux types fondamentaux de dépendance spatiale sur une variable mesurée $y$: une dépendance *intrinsèque* à $y$, ou une dépendance *induite* par des variables externes influençant $y$, qui sont elles-mêmes corrélées dans l'espace.\n\nPar exemple, supposons que l'abondance d'une espèce soit corrélée entre deux sites rapprochés:\n\n- cette dépendance spatiale peut être induite si elle est due à une corrélation spatiale des facteurs d'habitat qui favorisent ou défavorisent l'espèce;\n\n- ou elle peut être intrinsèque si elle est due à la dispersion d'individus entre sites rapprochés.\n\nDans plusieurs cas, les deux types de dépendance affectent une variable donnée.\n\nSi la dépendance est simplement induite et que les variables externes qui en sont la cause sont incluses dans le modèle expliquant $y$, alors les résidus du modèle seront indépendants et nous pouvons utiliser toutes les méthodes déjà vues qui ignorent la dépendance spatiale.\n\nCependant, si la dépendance est intrinsèque ou due à des influences externes non-mesurées, alors il faudra tenir compte de la dépendance spatiale des résidus dans le modèle.\n\n## Différentes façons de modéliser les effets spatiaux\n\nDans cette formation, nous modéliserons directement les corrélations spatiales de nos données. Il est utile de comparer cette approche à d'autres façons d'inclure des aspects spatiaux dans un modèle statistique.\n\nD'abord, nous pourrions inclure des prédicteurs dans le modèle qui représentent la position (ex.: longitude, latitude). De tels prédicteurs peuvent être utiles pour détecter une tendance ou un gradient systématique à grande échelle, que cette tendance soit linéaire ou non (par exemple, avec un modèle additif généralisé).\n\nEn contraste à cette approche, les modèles que nous verrons maintenant servent à modéliser une corrélation spatiale dans les fluctuations aléatoires d'une variable (i.e., dans les résidus après avoir enlevé tout effet systématique).\n\nLes modèles mixtes utilisent des effets aléatoires pour représenter la non-indépendance de données sur la base de leur groupement, c'est-à-dire qu'après avoir tenu compte des effets fixes systématiques, les données d'un même groupe sont plus semblables (leur variation résiduelle est corrélée) par rapport aux données de groupes différents. Ces groupes étaient parfois définis selon des critères spatiaux (observations regroupées en sites).\n\nCependant, dans un contexte d'effet aléatoire de groupe, tous les groupes sont aussi différents les uns des autres, ex.: deux sites à 100 km l'un de l'autre ne sont pas plus ou moins semblables que deux sites distants de 2 km.\n\nLes méthodes que nous verrons ici et dans les prochains parties de la formation nous permettent donc ce modéliser la non-indépendance sur une échelle continue (plus proche = plus corrélé) plutôt que seulement discrète (hiérarchie de groupements).\n\n\n# Modèles géostatistiques {#geostat-models-fr}\n\nLa géostatistique désigne un groupe de techniques tirant leur origine en sciences de la Terre. Elle s'intéresse à des variables distribuées de façon continue dans l'espace, dont on cherche à estimer la distribution en échantillonnant un nombre de points. Un exemple classique de ces techniques provient du domaine minier, où l'on cherchait à créer une carte de la concentration du minerai sur un site à partir d'échantillons pris à différents points du site.\n\nPour ces modèles, nous supposerons que $z(x, y)$ est une variable spatiale stationnaire mesurée selon les coordonnées $x$ et $y$.\n\n## Variogramme\n\nUn aspect central de la géostatistique est l'estimation du variogramme $\\gamma_z$ de la variable $z$. Le variogramme est égal à la moitié de l'écart carré moyen entre les valeurs de $z$ pour deux points $(x_i, y_i)$ et $(x_j, y_j)$ séparés par une distance $h$.\n\n$$\\gamma_z(h) = \\frac{1}{2} \\text{E} \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h}$$\n\nDans cette équation, la fonction $\\text{E}$ avec l'indice $d_{ij}=h$ désigne l'espérance statistique (autrement dit, la moyenne) de l'écart au carré entre les valeurs de $z$ pour les points séparés par une distance $h$.\n\nSi on préfère exprimer l'autocorrélation $\\rho_z(h)$ entre mesures de $z$ séparées par une distance $h$, celle-ci est reliée au variogramme par l'équation:\n\n$$\\gamma_z = \\sigma_z^2(1 - \\rho_z)$$ ,\n\noù $\\sigma_z^2$ est la variance globale de $z$. \n\nNotez que $\\gamma_z = \\sigma_z^2$ si nous sommes à une distance où les mesures de $z$ sont indépendantes, donc $\\rho_z = 0$. Dans ce cas, on voit bien que $\\gamma_z$ s'apparente à une variance, même s'il est parfois appelé \"semivariogramme\" ou \"semivariance\" en raison du facteur 1/2 dans l'équation ci-dessus.\n\n## Modèles théoriques du variogramme\n\nPlusieurs modèles paramétriques ont été proposés pour représenter la corrélation spatiale en fonction de la distance entre points d'échantillonnage. Considérons d'abord une corrélation qui diminue de façon exponentielle: \n\n$$\\rho_z(h) = e^{-h/r}$$\n\nIci, $\\rho_z = 1$ pour $h = 0$ et la corréaltion est multipliée par $1/e \\approx 0.37$ pour chaque augmentation de $r$ de la distance. Dans ce contexte, $r$ se nomme la portée (*range*) de la corrélation.\n\nÀ partir de l'équation ci-dessus, nous pouvons calculer le variogramme correspondant.\n\n$$\\gamma_z(h) = \\sigma_z^2 (1 - e^{-h/r})$$\n\nVoici une représentation graphique de ce variogramme.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 5*(1-exp(-1)),\n yend = 5*(1-exp(-1))), \n arrow = arrow(length = unit(0.05, \"inches\"), ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 3.5, label = \"portée (range)\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"palier (sill)\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nEn raison de la fonction exponentielle, la valeur de $\\gamma$ à des grandes distances s'approche de la variance globale $\\sigma_z^2$ sans exactement l'atteindre. Cette asymptote est appelée palier (*sill*) dans le contexte géostatistique et représentée par le symbole $s$.\n\nFinalement, il n'est parfois pas réaliste de supposer une corrélation parfaite lorsque la distance tend vers 0, en raison d'une variation possible de $z$ à très petite échelle. On peut ajouter au modèle un effet de pépite (*nugget*), noté $n$, pour que $\\gamma$ s'approche de $n$ (plutôt que 0) si $h$ tend vers 0. Le terme pépite provient de l'origine minière de ces techniques, où une pépite d'un minerai pourrait être la source d'une variation abrupte de la concentration à petite échelle.\n\nEn ajoutant l'effet de pépite, le reste du variogramme est \"compressé\" pour conserver le même palier, ce qui résulte en l'équation suivante.\n\n$$\\gamma_z(h) = n + (s - n) (1 - e^{-h/r})$$\n\nDans le package *gstat* que nous utiliserons ci-dessous, le terme $(s - n)$ est le palier partiel (*partial sill*, ou `psill`) pour la partie exponentielle.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 4 * (1 - exp(-x/3)) + 1,\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 4*(1-exp(-1)) + 1,\n yend = 4*(1-exp(-1)) + 1), \n arrow = arrow(length = unit(0.05, \"inches\"), \n ends = \"both\", type = \"closed\")) +\n geom_segment(aes(x = 0, xend = 0, y = 0, yend = 0.9),\n arrow = arrow(length = unit(0.05, \"inches\"),\n ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 4, label = \"portée (range)\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"palier (sill)\") +\n annotate(\"text\", x = 1.5, y = 0.5, label = \"pépite (nugget)\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nEn plus du modèle exponentiel, deux autres modèles théoriques courants pour le variogramme sont le modèle gaussien (où la corrélation suit une courbe demi-normale), ainsi que le modèle sphérique (où le variogramme augmente de façon linéaire au départ pour ensuite courber et atteindre le palier à une distance égale à sa portée $r$). Le modèle sphérique permet donc à la corrélation d'être exactement 0 à grande distance, plutôt que de s'approcher graduellement de zéro dans le cas des autres modèles.\n\n Modèle | $\\rho(h)$ | $\\gamma(h)$\n-------|-----------|-------------\nExponentiel | $\\exp\\left(-\\frac{h}{r}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h}{r}\\right)\\right)$\nGaussien | $\\exp\\left(-\\frac{h^2}{r^2}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h^2}{r^2}\\right)\\right)$\nSphérique $(h < r)$ * | $1 - \\frac{3}{2}\\frac{h}{r} + \\frac{1}{2}\\frac{h^3}{r^3}$ | $s \\left(\\frac{3}{2}\\frac{h}{r} - \\frac{1}{2}\\frac{h^3}{r^3} \\right)$\n\n\\* Pour le modèle sphérique, $\\rho = 0$ et $\\gamma = s$ si $h \\ge r$.\n\n\n```{r, echo = FALSE, fig.dim = c(9, 4)}\nvexp <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Exponentiel\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n \n\nvgau <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Gaussien\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x^2/4^2)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nvsph <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Sphérique\") +\n stat_function(fun = function(x) ifelse(x < 8, 5 * (1.5*x/8 - 0.5*x^3/8^3), 5),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nplot_grid(vexp, vgau, vsph, nrow = 1)\n```\n\n## Variogramme empirique\n\nPour estimer $\\gamma_z(h)$ à partir de données empiriques, nous devons définir des classes de distance, donc grouper différentes distances dans une marge $\\pm \\delta$ autour d'une distance $h$, puis calculer l'écart-carré moyen pour les paires de points dans cette classe de distance.\n\n$$\\hat{\\gamma_z}(h) = \\frac{1}{2 N_{\\text{paires}}} \\sum \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h \\pm \\delta}$$\n\nNous verrons dans la partie suivante comment estimer un variogramme dans R.\n\n## Modèle de régression avec corrélation spatiale\n\nL'équation suivante représente une régression linéaire multiple incluant une corrélation spatiale résiduelle:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nIci, $v$ désigne la variable réponse et $u$ les prédicteurs, pour ne pas confondre avec les coordonnées spatiales $x$ et $y$. \n\nEn plus du résidu $\\epsilon$ qui est indépendant entre les observations, le modèle inclut un terme $z$ qui représente la portion spatialement corrélée de la variance résiduelle.\n\nVoici une suggestions d'étapes à suivre pour appliquer ce type de modèle:\n\n1. Ajuster le modèle de régression sans corrélation spatiale.\n\n2. Vérifier la présence de corrélation spatiale à partir du variogramme empirique des résidus.\n\n3. Ajuster un ou plusieurs modèles de régression avec corrélation spatiale et choisir celui qui montre le meilleur ajustement aux données. \n\n# Modèles géostatistiques dans R\n\nLe package *gstat* contient des fonctions liées à la géostatistique. Pour cet exemple, nous utiliserons le jeu de données `oxford` de ce package, qui contient des mesures de propriétés physiques et chimiques pour 126 échantillons du sol d'un site, ainsi que leurs coordonnées `XCOORD` et `YCOORD`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gstat)\n\ndata(oxford)\nstr(oxford)\n```\n\nSupposons que nous souhaitons modéliser la concentration de magnésium (`MG1`), représentée en fonction de la position spatiale dans le graphique suivant.\n\n```{r}\nlibrary(ggplot2)\nggplot(oxford, aes(x = YCOORD, y = XCOORD, size = MG1)) +\n geom_point() +\n coord_fixed()\n```\n\nNotez que les axes $x$ et $y$ ont été inversés par souci d'espace. La fonction `coord_fixed()` de *ggplot2* assure que l'échelle soit la même sur les deux axes, ce qui est utile pour représenter des données spatiales. \n\nNous voyons tout de suite que ces mesures ont été prises sur une grille de 100 m de côté. Il semble que la concentration de magnésium soit spatialement corrélée, bien qu'il puisse s'agir d'une corrélation induite par une autre variable. Nous savons notamment que la concentration de magnésium est reliée négativement au pH du sol (`PH1`).\n\n```{r}\nggplot(oxford, aes(x = PH1, y = MG1)) +\n geom_point()\n```\n\nLa fonction `variogram` de *gstat* sert à estimer un variogramme à partir de données empiriques. Voici le résultat obtenu pour la variable `MG1`.\n\n```{r}\nvar_mg <- variogram(MG1 ~ 1, locations = ~ XCOORD + YCOORD, data = oxford)\nvar_mg\n```\n\nLa formule `MG1 ~ 1` indique qu'aucun prédicteur linéaire n'est inclus dans ce modèle, tandis que l'argument `locations` indique quelles variables du tableau correspondent aux coordonnées spatiales. \n\nDans le tableau obtenu, `gamma` est la valeur du variogramme pour la classe de distance centrée sur `dist`, tandis que `np` est le nombre de paires de points dans cette classe. Ici, puisque les points sont situés sur une grille, nous obtenons des classes de distance régulières (ex.: 100 m pour les points voisins sur la grille, 141 m pour les voisins en diagonale, etc.).\n\nNous nous limitons ici à l'estimation de variogrammes isotropiques, c'est-à-dire que le variogramme dépend seulement de la distance entre les deux points et non de la direction. Bien que nous n'ayons pas le temps de le voir aujourd'hui, il est possible avec *gstat* d'estimer séparément le variogramme dans différentes directions.\n\nNous pouvons illustrer le variogramme avec `plot`.\n\n```{r}\nplot(var_mg, col = \"black\")\n```\n\nSi nous voulons estimer la corrélation spatiale résiduelle de `MG1` après avoir inclus l'effet de `PH1`, nous pouvons ajouter ce prédicteur à la formule.\n\n```{r}\nvar_mg <- variogram(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford)\nplot(var_mg, col = \"black\")\n```\n\nEn incluant l'effet du pH, la portée de la corrélation spatiale semble diminuer, alors que le plateau est atteint autour de 300 m. Il semble même que le variogramme diminue au-delà de 400 m. En général, nous supposons que la variance entre deux points ne diminue pas avec la distance, à moins d'avoir un patron spatial périodique.\n\nLa fonction `fit.variogram` accepte comme arguments un variogramme estimé à partir des données, ainsi qu'un modèle théorique décrit dans une fonction `vgm`, puis estime les paramètres de ce modèle en fonction des données. L'ajustement se fait par la méthode des moindres carrés.\n\nPar exemple, `vgm(\"Exp\")` indique d'ajuster un modèle exponentiel. \n\n```{r}\nvfit <- fit.variogram(var_mg, vgm(\"Exp\"))\nvfit\n```\n\nIl n'y a aucun effet de pépite, car `psill = 0` pour la partie `Nug` (*nugget*) du modèle. La partie exponentielle a un palier à 1951 et une portée de 95 m.\n\nPour comparer différents modèles, on peut donner un vecteur de noms de modèles à `vgm`. Dans l'exemple suivant, nous incluons les modèles exponentiel, gaussien (\"Gau\") et sphérique (\"Sph\").\n\n```{r, warning = FALSE, message = FALSE}\nvfit <- fit.variogram(var_mg, vgm(c(\"Exp\", \"Gau\", \"Sph\")))\nvfit\n```\n\nLa fonction nous donne le résultat du modèle le mieux ajusté (plus faible somme des écarts au carré), qui est ici le même modèle exponentiel.\n\nFinalement, nous pouvons superposer le modèle théorique et le variogramme empirique sur un même graphique.\n\n```{r}\nplot(var_mg, vfit, col = \"black\")\n```\n\n## Régression avec corrélation spatiale\n\nNous avons vu ci-dessus que le package *gstat* permet d'estimer le variogramme des résidus d'un modèle linéaire. Dans notre exemple, la concentration de magnésium était modélisée en fonction du pH, avec des résidus spatialement corrélés.\n\nUn autre outil pour ajuster ce même type de modèle est la fonction `gls` du package *nlme*, qui est inclus avec l'installation de R. \n\nCette fonction applique la méthode des moindres carrés généralisés (*generalized least squares*) pour ajuster des modèles de régression linéaire lorsque les résidus ne sont pas indépendants ou lorsque la variance résiduelle n'est pas la même pour toutes les observations. Comme les estimés des coefficients dépendent de l'estimé des corrélations entre les résidus et que ces derniers dépendent eux-mêmes des coefficients, le modèle est ajusté par un algorithme itératif:\n\n1. On ajuste un modèle de régression linéaire classique (sans corrélation) pour obtenir des résidus.\n\n2. On ajuste le modèle de corrélation spatiale (variogramme) avec ses résidus.\n\n3. On ré-estime les coefficients de la régression en tenant compte maintenant des corrélations.\n\nLes étapes 2 et 3 sont répétées jusqu'à ce que les estimés soient stables à une précision voulue.\n\nVoici l'application de cette méthode au même modèle pour la concentration de magnésium dans le jeu de données `oxford`. Dans l'argument `correlation` de `gls`, nous spécifions un modèle de corrélation exponentielle en fonction de nos coordonnées spatiales et indiquons que nous voulons aussi estimer un effet de pépite.\n\nEn plus de la corrélation exponentielle `corExp`, la fonction `gls` peut aussi estimer un modèle gaussien (`corGaus`) ou sphérique (`corSpher`).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(nlme)\ngls_mg <- gls(MG1 ~ PH1, oxford, \n correlation = corExp(form = ~ XCOORD + YCOORD, nugget = TRUE))\nsummary(gls_mg)\n```\n\nPour comparer ce résultat au variogramme ajusté ci-dessus, il faut transformer les paramètres donnés par `gls`. La portée (range) a le même sens dans les deux cas et correspond à 478 m pour le résultat de `gls`. La variance globale des résidus est le carré de `Residual standard error`. L'effet de pépite ici (0.294) est exprimé comme fraction de cette variance. Finalement, pour obtenir le palier partiel de la partie exponentielle, il faut soustraire l'effet de pépite de la variance totale. \n\nAprès avoir réalisé ces calculs, nous pouvons donner ces paramètres à la fonction `vgm` de *gstat* pour superposer ce variogramme estimé par `gls` à notre variogramme des résidus du modèle linéaire classique.\n\n```{r}\ngls_range <- 478\ngls_var <- 53.823^2\ngls_nugget <- 0.294 * gls_var\ngls_psill <- gls_var - gls_nugget\n\ngls_vgm <- vgm(\"Exp\", psill = gls_psill, range = gls_range, nugget = gls_nugget)\n\nplot(var_mg, gls_vgm, col = \"black\", ylim = c(0, 4000))\n```\n\nEst-ce que le modèle est moins bien ajusté aux données ici? En fait, ce variogramme empirique représenté par les points avait été obtenu à partir des résidus du modèle linéaire ignorant la corrélation spatiale, donc c'est un estimé biaisé des corrélations spatiales réelles. La méthode est quand même adéquate pour vérifier rapidement s'il y a présence de corrélations spatiales. Toutefois, pour ajuster simultanément les coefficients de la régression et les paramètres de corrélation spatiale, l'approche des moindres carrés généralisés (GLS) est préférable et produira des estimés plus justes.\n\nFinalement, notez que le résultat du modèle `gls` donne aussi l'AIC, que nous pouvons utiliser pour comparer l'ajustement de différents modèles (avec différents prédicteurs ou différentes formes de corrélation spatiale).\n\n## Exercice\n\nLe fichier [bryo_belg.csv](data/bryo_belg.csv) est adapté des données de l'étude: \n\n> Neyens, T., Diggle, P.J., Faes, C., Beenaerts, N., Artois, T. et Giorgi, E. (2019) Mapping species richness using opportunistic samples: a case study on ground-floor bryophyte species richness in the Belgian province of Limburg. *Scientific Reports* 9, 19122. https://doi.org/10.1038/s41598-019-55593-x\n\nCe tableau de données indique la richesse spécifique des bryophytes au sol (*richness*) pour différents points d'échantillonnage de la province belge de Limbourg, avec leur position *(x, y)* en km, en plus de l'information sur la proportion de forêts (*forest*) et de milieux humides (*wetland*) dans une cellule de 1 km$^2$ contenant le point d'échantillonnage.\n\n```{r}\nbryo_belg <- read.csv(\"data/bryo_belg.csv\")\nhead(bryo_belg)\n```\n\nPour cet exercice, nous utiliserons la racine carrée de la richesse spécifique comme variable réponse. La transformation racine carrée permet souvent d'homogénéiser la variance des données de comptage afin d'y appliquer une régression linéaire. \n\na) Ajustez un modèle linéaire de la richesse spécifique transformée en fonction de la fraction de forêt et de milieux humides, sans tenir compte des corrélations spatiales. Quel est l'effet des deux prédicteurs selon ce modèle?\n\nb) Calculez le variogramme empirique des résidus du modèle en (a). Semble-t-il y avoir une corrélation spatiale entre les points?\n\n*Note*: L'argument `cutoff` de la fonction `variogram` spécifie la distance maximale à laquelle le variogramme est calculé. Vous pouvez ajuster manuellement cette valeur pour bien voir le palier.\n\nc) Ré-ajustez le modèle linéaire en (a) avec la fonction `gls` du package *nlme*, en essayant différents types de corrélations spatiales (exponentielle, gaussienne, sphérique). Comparez les modèles (incluant celui sans corrélation spatiale) avec l'AIC.\n\nd) Quel est l'effet de la fraction de forêts et de milieux humides selon le modèle en (c)? Expliquez les différences entre les conclusions de ce modèle et du modèle en (a).\n\n\n# Krigeage\n\nTel que mentionné précédemment, une application courante des modèles géostatistiques consiste à prédire la valeur de la variable de réponse à des points non-échantillonnés, une forme d'interpolation spatiale appelée krigeage (*kriging*).\n\nIl existe trois principaux types de krigeage selon les suppositions faites au sujet de la variable réponse:\n\n- Krigeage ordinaire: variable stationnaire avec une moyenne inconnue.\n\n- Krigeage simple: Variable stationnaire avec une moyenne connue.\n\n- Krigeage universel: Variable dont la tendance est donnée par un modèle linéaire ou non linéaire.\n\nPour toutes les méthodes de krigeage, les prédictions à un nouveau point sont une moyenne pondérée des valeurs à des points connus. Ces pondérations sont choisies de manière à ce que le krigeage fournisse la meilleure prédiction linéaire non biaisée de la variable de réponse, si les hypothèses du modèle (en particulier le variogramme) sont correctes. C'est-à-dire que, parmi toutes les prédictions non biaisées possibles, les poids sont choisis de manière à donner l'erreur quadratique moyenne minimale. Le krigeage fournit également une estimation de l'incertitude de chaque prédiction.\n\nBien que nous ne présentions pas ici les équations détaillées du krigeage, les poids dépendent à la fois des corrélations (estimées par le variogramme) entre les points échantillonnés et le nouveau point, ainsi que des corrélations entre les points échantillonnés eux-mêmes. Autrement dit, les points échantillonnés proches du nouveau point ont plus de poids, mais les points échantillonnés isolés ont également plus de poids, car les points échantillonnés proches les uns des autres fournissent une informations redondante.\n\nLe krigeage est une méthode d'interpolation, donc la prédiction à un point échantillonné sera toujours égale à la valeur mesurée (la variable est supposée être mesurée sans erreur, elle varie seulement entre les points). Cependant, en présence d'un effet de pépite, tout petit déplacement par rapport à l'endroit échantillonné présentera une variabilité en fonction de la pépite.\n\nDans l'exemple ci-dessous, nous générons un nouvel ensemble de données composé de coordonnées (x, y) générées de façon aléatoire dans la zone d'étude ainsi que des valeurs de pH générées de façon aléatoire sur la base des données `oxford`. Nous appliquons ensuite la fonction `krige` pour prédire les valeurs de magnésium à ces nouveaux points. Notez que nous spécifions le variogramme dérivé des résultats du `gls` dans l'argument `model` de `krige`.\n\n```{r}\nset.seed(14)\nnew_points <- data.frame(\n XCOORD = runif(100, min(oxford$XCOORD), max(oxford$XCOORD)),\n YCOORD = runif(100, min(oxford$YCOORD), max(oxford$YCOORD)),\n PH1 = rnorm(100, mean(oxford$PH1), sd(oxford$PH1))\n)\n\npred <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm)\nhead(pred)\n```\n\nLe résultat de `krige` comprend les nouvelles coordonnées du point, la prédiction de la variable `var1.pred` ainsi que sa variance estimée `var1.var`. Dans le graphique ci-dessous, nous montrons les prédictions moyennes de MG1 à partir du krigeage (triangles) ainsi que les mesures (cercles).\n\n```{r}\npred$MG1 <- pred$var1.pred\n\nggplot(oxford, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n geom_point(data = pred, shape = 17, size = 2) +\n coord_fixed()\n```\n\nLa moyenne et la variance estimées par krigeage peuvent être utilisées pour simuler les valeurs possibles de la variable à chaque nouveau point, conditionnellement aux valeurs échantillonnées. Dans l'exemple ci-dessous, nous avons effectué 4 simulations conditionnelles en ajoutant l'argument `nsim = 4` à la même instruction `krige`.\n\n```{r}\nsim_mg <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm, nsim = 4)\nhead(sim_mg)\n```\n\n```{r, message = FALSE, warning = FALSE, fig.dim = c(10, 5)}\nlibrary(tidyr)\nsim_mg <- pivot_longer(sim_mg, cols = c(sim1, sim2, sim3, sim4), \n names_to = \"sim\", values_to = \"MG1\")\nggplot(sim_mg, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n coord_fixed() +\n facet_wrap(~ sim)\n```\n\n\n# Solutions\n\n```{r}\nbryo_lm <- lm(sqrt(richness) ~ forest + wetland, data = bryo_belg)\nsummary(bryo_lm)\n```\n\nLa proportion de forêts a un effet positif significatif et la proportion de milieux humides a un effet négatif significatif sur la richesse des bryophytes.\n\n```{r}\nplot(variogram(sqrt(richness) ~ forest + wetland, locations = ~ x + y,\n data = bryo_belg, cutoff = 50), col = \"black\")\n```\n\nLe variogramme augmente au moins jusqu'à une distance de 40 km, il semble donc y avoir des corrélations spatiales dans les résidus du modèle.\n\n```{r}\nbryo_exp <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corExp(form = ~ x + y, nugget = TRUE))\nbryo_gaus <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corGaus(form = ~ x + y, nugget = TRUE))\nbryo_spher <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corSpher(form = ~ x + y, nugget = TRUE))\n```\n\n```{r}\nAIC(bryo_lm)\nAIC(bryo_exp)\nAIC(bryo_gaus)\nAIC(bryo_spher)\n```\n\nLe modèle sphérique a l'AIC le plus faible.\n\n```{r}\nsummary(bryo_spher)\n```\n\nLa magnitude des deux effets est moins importante et l'effet des milieux humides n'est plus significatif. Comme c'est le cas pour d'autres types de résidus non indépendants, la \"taille effective\" de l'échantillon est ici inférieure au nombre de points, car des points proches les uns des autres fournissent une information redondante. Par conséquent, la relation entre les prédicteurs et la réponse est moins claire que celle donnée par le modèle supposant que tous ces points étaient indépendants.\n\nNotez que les résultats pour les trois modèles `gls` sont assez similaires, donc le choix d'inclure des corrélations spatiales était plus important que la forme exacte supposée pour le variogramme.\n\n\n# Données aréales {#areal-data-fr}\n\nLes données aréales sont des variables mesurées pour des régions de l'espace; ces régions sont définies par des polygones. Ce type de données est plus courant en sciences sociales, en géographie humaine et en épidémiologie, où les données sont souvent disponibles à l'échelle de divisions administratives du territoire. \n\nCe type de données apparaît aussi fréquemment dans la gestion des ressources naturelles. Par exemple, la carte suivante montre les unités d'aménagement forestier du Ministère de la Forêts, de la Faune et des Parcs du Québec.\n\n![](images/cartes_unites.png)\n\nSupposons qu'une certaine variable soit disponible au niveau de ces divisions du territoire. Comment pouvons-nous modéliser la corrélation spatiale entre les unités qui sont spatialement rapprochées?\n\nUne option serait d'appliquer les méthodes géostatistiques vues précédemment, en calculant par exemple la distance entre les centres des polygones.\n\nUne autre option, qui est davantage privilégiée pour les données aréales, consiste à définir un réseau où chaque région est connectée aux régions voisines par un lien. On suppose ensuite que les variables sont directement corrélées entre régions voisines seulement. (Notons toutefois que les corrélations directes entre voisins immédiats génèrent aussi des corrélations indirectes pour une chaîne de voisins.)\n\nDans ce type de modèle, la corrélation n'est pas nécessairement la même d'un lien à un autre. Dans ce cas, chaque lien du réseau peut être associé à un *poids* représentant son importance pour la corrélation spatiale. Nous représentons ces poids par une matrice $W$ où $w_{ij}$ est le poids du lien entre les régions $i$ et $j$. Une région n'a pas de lien avec elle-même, donc $w_{ii} = 0$.\n\nUn choix simple pour $W$ consiste à assigner un poids égal à 1 si les régions sont voisines, sinon 0 (poids binaires).\n\nOutre les divisions du territoire en polygones, un autre exemple de données aréales consiste en une grille où la variable est compilée pour chaque cellule de la grille. Dans ce cas, une cellule a généralement 4 ou 8 cellules voisines, selon que les diagonales soient incluses ou non.\n\n# Indice de Moran {#moran-i-fr}\n\nAvant de discuter des modèles d'autocorrélation spatiale, nous présentons l'indice $I$ de Moran, qui permet de tester si une corrélation significative est présente entre régions voisines. \n\nL'indice de Moran est un coefficient d'autocorrélation spatiale des $z$, pondéré par les poids $w_{ij}$. Il prend donc des valeurs entre -1 et 1.\n\n$$I = \\frac{N}{\\sum_i \\sum_j w_{ij}} \\frac{\\sum_i \\sum_j w_{ij} (z_i - \\bar{z}) (z_j - \\bar{z})}{\\sum_i (z_i - \\bar{z})^2}$$\n\nDans cette équation, nous reconnaissons l'expression d'une corrélation, soit le produit des écarts à la moyenne de deux variables $z_i$ et $z_j$, divisé par le produit de leurs écarts-types (qui est le même, donc on obtient la variance). La contribution de chaque paire $(i, j)$ est multipliée par son poids $w_{ij}$ et le terme à gauche (le nombre de régions $N$ divisé par la somme des poids) assure que le résultat soit borné entre -1 et 1.\n\nPuisque la distribution de $I$ est connue en l'absence d'autocorrélation spatiale, cette statistique permet de tester l'hypothèse nulle selon laquelle il n'y a pas de corrélation spatiale entre régions voisines.\n\nBien que nous ne verrons pas d'exemple dans ce cours-ci, l'indice de Moran peut aussi être appliqué aux données ponctuelles. Dans ce cas, on divise les paires de points en classes de distance et on calcule $I$ pour chaque classe de distance; le poids $w_{ij} = 1$ si la distance entre $i$ et $j$ se trouve dans la classe de distance voulue, 0 autrement.\n\n# Modèles d'autorégression spatiale {#spatial-autoreg-fr}\n\nRappelons-nous la formule pour une régression linéaire avec dépendance spatiale:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\noù $z$ est la portion de la variance résiduelle qui est spatialement corrélée.\n\nIl existe deux principaux types de modèles autorégressifs pour représenter la dépendance spatiale de $z$: l'autorégression conditionnelle (CAR) et l'autorégression simultanée (SAR).\n\n## Autorégression conditionnelle (CAR)\n\nDans le modèle d'autorégression conditionnelle, la valeur de $z_i$ pour la région $i$ suit une distribution normale: sa moyenne dépend de la valeur $z_j$ des régions voisines, multipliée par le poids $w_{ij}$ et un coefficient de corrélation $\\rho$; son écart-type $\\sigma_{z_i}$ peut varier d'une région à l'autre.\n\n$$z_i \\sim \\text{N}\\left(\\sum_j \\rho w_{ij} z_j,\\sigma_{z_i} \\right)$$\n\nDans ce modèle, si $w_{ij}$ est une matrice binaire (0 pour les non-voisins, 1 pour les voisins), alors $\\rho$ est le coefficient de corrélation partielle entre régions voisines. Cela est semblable à un modèle autorégressif d'ordre 1 dans le contexte de séries temporelles, où le coefficient d'autorégression indique la corrélation partielle.\n\n## Autorégression simultanée (SAR)\n\nDans le modèle d'autorégression simultanée, la valeur de $z_i$ est donnée directement par la somme de contributions des valeurs voisines $z_j$, multipliées par $\\rho w_{ij}$, avec un résidu indépendant $\\nu_i$ d'écart-type $\\sigma_z$.\n\n$$z_i = \\sum_j \\rho w_{ij} z_j + \\nu_i$$\n\nÀ première vue, cela ressemble à un modèle autorégressif temporel. Il existe cependant une différence conceptuelle importante. Pour les modèles temporels, l'influence causale est dirigée dans une seule direction: $v(t-2)$ affecte $v(t-1)$ qui affecte ensuite $v(t)$. Pour un modèle spatial, chaque $z_j$ qui affecte $z_i$ dépend à son tour de $z_i$. Ainsi, pour déterminer la distribution conjointe des $z$, il faut résoudre simultanément (d'où le nom du modèle) un système d'équations. \n\nPour cette raison, même si ce modèle ressemble à la formule du modèle conditionnel (CAR), les solutions des deux modèles diffèrent et dans le cas du SAR, le coefficient $\\rho$ n'est pas directement égal à la corrélation partielle due à chaque région voisine.\n\nPour plus de détails sur les aspects mathématiques de ces modèles, vous pouvez consulter l'article de Ver Hoef et al. (2018) suggéré en référence. \n\nPour l'instant, nous considérerons les SAR et les CAR comme deux types de modèles possibles pour représenter une corrélation spatiale sur un réseau. Nous pouvons toujours ajuster plusieurs modèles et les comparer avec l'AIC pour choisir la meilleure forme de la corrélation ou la meilleure matrice de poids.\n\nLes modèles CAR et SAR partagent un avantage sur les modèles géostatistiques au niveau de l'efficacité. Dans un modèle géostatistique, les corrélations spatiales sont définies entre chaque paire de points, même si elles deviennent négligeables lorsque la distance augmente. Pour un modèle CAR ou SAR, seules les régions voisines contribuent et la plupart des poids sont égaux à 0, ce qui rend ces modèles plus rapides à ajuster qu'un modèle géostatistique lorsque les données sont massives.\n\n# Analyse des données aréales dans R {#analysis-areal-fr}\n\nPour illustrer l'analyse de données aréales dans R, nous chargeons les packages *sf* (pour lire des données géospatiales), *spdep* (pour définir des réseaux spatiaux et calculer l'indice de Moran) et *spatialreg* (pour les modèles SAR et CAR).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nlibrary(spdep)\nlibrary(spatialreg)\n```\n\nNous utiliserons comme exemple un jeu de données qui présente une partie des résultats de l'élection provinciale de 2018 au Québec, avec des caractéristiques de la population de chaque circonscription. Ces données sont inclues dans un fichier de type *shapefile* (.shp), que nous pouvons lire avec la fonction `read_sf` du package *sf*.\n\n```{r}\nelect2018 <- read_sf(\"data/elect2018.shp\")\nhead(elect2018)\n```\n\n*Note*: Le jeu de données est en fait composé de 4 fichiers avec les extensions .dbf, .prj, .shp et .shx, mais il suffit d'inscrire le nom du fichier .shp dans `read_sf`.\n\nLes colonnes du jeu de données sont dans l'ordre:\n\n- le nom de la circonscription électorale;\n- quatre caractéristiques de la population (âge moyen, fraction de la population qui parle principalement français à la maison, fraction des ménages qui sont propriétaires de leur logement, revenu médian);\n- quatre colonnes montrant la fraction des votes obtenues par les principaux partis (CAQ, PQ, PLQ, QS);\n- une colonne `geometry` qui contient l'objet géométrique (multipolygone) correspondant à la circonscription.\n\nPour illustrer une des variables sur une carte, nous appelons la fonction `plot` avec le nom de la colonne entre crochets et guillemets. \n\n```{r}\nplot(elect2018[\"rev_med\"])\n```\n\nDans cet exemple, nous voulons modéliser la fraction des votes obtenue par la CAQ en fonction des caractéristiques de la population dans chaque circonscription et en tenant compte des corrélations spatiales entre circonscriptions voisines.\n\n## Définition du réseau de voisinage\n\nLa fonction `poly2nb` du package *spdep* définit un réseau de voisinage à partir de polygones. Le résultat `vois` est une liste de 125 éléments où chaque élément contient les indices des polygones voisins (limitrophes) d'un polygone donné.\n\n```{r}\nvois <- poly2nb(elect2018)\nvois[[1]]\n```\n\nAinsi, la première circonscription (Abitibi-Est) a 6 circonscriptions voisines, dont on peut trouver les noms ainsi:\n\n```{r}\nelect2018$circ[vois[[1]]]\n```\n\nNous pouvons illustrer ce réseau en faisant l'extraction des coordonnées du centre de chaque circonscription, en créant une carte muette avec `plot(elect2018[\"geometry\"])`, puis en ajoutant le réseau comme couche additionnelle avec `plot(vois, add = TRUE, coords = coords)`.\n\n```{r, message = FALSE, warning = FALSE}\ncoords <- st_centroid(elect2018) %>%\n st_coordinates()\nplot(elect2018[\"geometry\"])\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nOn peut faire un \"zoom\" sur le sud du Québec en choisissant les limites `xlim` et `ylim` appropriées.\n\n```{r}\nplot(elect2018[\"geometry\"], \n xlim = c(400000, 800000), ylim = c(100000, 500000))\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nIl nous reste à ajouter des poids à chaque lien du réseau avec la fonction `nb2listw`. Le style de poids \"B\" correspond aux poids binaires, soit 1 pour la présence de lien et 0 pour l'absence de lien entre deux circonscriptions.\n\nUne fois ces poids définis, nous pouvons vérifier avec le test de Moran s'il y a une autocorrélation significative des votes obtenus par la CAQ entre circonscriptions voisines.\n\n```{r}\npoids <- nb2listw(vois, style = \"B\")\n\nmoran.test(elect2018$propCAQ, poids)\n```\n\nLa valeur de $I = 0.68$ est très significative à en juger par la valeur $p$ du test.\n\nVérifions si la corrélation spatiale persiste après avoir tenu compte des quatre caractéristiques de la population, donc en inspectant les résidus d'un modèle linéaire incluant ces quatre prédicteurs.\n\n```{r}\nelect_lm <- lm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, data = elect2018)\nsummary(elect_lm)\nmoran.test(residuals(elect_lm), poids)\n```\n\nL'indice de Moran a diminué mais demeure significatif, donc une partie de la corrélation précédente était induite par ces prédicteurs, mais il reste une corrélation spatiale due à d'autres facteurs. \n\n## Modèles d'autorégression spatiale\n\nFinalement, nous ajustons des modèles SAR et CAR à ces données avec la fonction `spautolm` (*spatial autoregressive linear model*) de *spatialreg*. Voici le code pour un modèle SAR incluant l'effet des même quatre prédicteurs. \n\n```{r}\nelect_sar <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids)\nsummary(elect_sar)\n```\n\nLa valeur donnée par `Lambda` dans le sommaire correspond au coefficient $\\rho$ dans notre description du modèle. Le test du rapport de vraisemblance (`LR test`) confirme que cette corrélation spatiale résiduelle (après avoir tenu compte de l'effet des prédicteurs) est significative.\n\nLes effets estimés pour les prédicteurs sont semblables à ceux du modèle linéaire sans corrélation spatiale. Les effets de l'âge moyen, de la fraction de francophones et la fraction de propriétaires demeurent significatifs, bien que leur magnitude ait un peu diminué.\n\nPour évaluer un modèle CAR plutôt que SAR, nous devons spécifier `family = \"CAR\"`.\n\n```{r}\nelect_car <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids, family = \"CAR\")\nsummary(elect_car)\n```\n\nPour un modèle CAR avec des poids binaires, la valeur de `Lambda` (que nous avions appelé $\\rho$) donne directement le coefficient de corrélation partielle entre circonscriptions voisines. Notez que l'AIC ici est légèrement supérieur au modèle SAR, donc ce dernier donnait un meilleur ajustement.\n\n## Exercice\n\nLe jeu de données `rls_covid`, en format *shapefile*, contient des données sur les cas de COVID-19 détectés, le nombre de cas par 1000 personnes (`taux_1k`) et la densité de population (`dens_pop`) dans chacun des réseaux locaux de service de santé (RLS) du Québec. (Source: Données téléchargées de l'Institut national de santé publique du Québec en date du 17 janvier 2021.)\n\n```{r}\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nhead(rls_covid)\n```\n\nAjustez un modèle linéaire du nombre de cas par 1000 en fonction de la densité de population (il est suggéré d'appliquer une transformation logarithmique à cette dernière). Vérifiez si les résidus du modèle sont corrélés entre RLS limitrophes avec un test de Moran, puis modélisez les mêmes données avec un modèle autorégressif conditionnel.\n\n## Référence\n\nVer Hoef, J.M., Peterson, E.E., Hooten, M.B., Hanks, E.M. et Fortin, M.-J. (2018) Spatial autoregressive models for statistical inference from ecological data. *Ecological Monographs* 88: 36-59.\n\n\n# GLMM avec processus spatial gaussien {#glmm-spatial-gaussian-fr}\n\nDans les parties précédentes, nous avons vu comment tenir compte de la dépendance spatiale dans les modèles de régression linéaire avec des modèles géostatistiques (également appelés processus gaussiens) ou des modèles d'autocorrélation spatiale (CAR/SAR). Dans cette dernière partie, nous verrons comment combiner ces caractéristiques avec des modèles de régression plus complexes, en particulier les modèles linéaires généralisés à effets mixtes (GLMM).\n\n## Données\n\nLe jeu de données `gambia` inclus avec le package *geoR* présente les résultats d'une étude sur la prévalence du paludisme chez les enfants de 65 villages en Gambie. Nous utiliserons une version légèrement transformée des données contenues dans le fichier [gambia.csv](data/gambia.csv).\n\n```{r, warning = FALSE, message = FALSE}\nlibrary(geoR)\n\ngambia <- read.csv(\"data/gambia.csv\")\nhead(gambia)\n```\n\nVoici les champs de ce jeu de données:\n\n- *id_village*: Identifiant du village.\n- *x* and *y*: Coordonnées spatiales du village (en km, basé sur les coordonnées UTM).\n- *pos*: Réponse binaire, si l'enfant a eu un test positif du paludisme.\n- *age*: Âge de l'enfant en jours.\n- *netuse*: Si l'enfant dort sous un moustiquaire ou non.\n- *treated*: Si le moustiquaire est traité ou non.\n- *green*: Mesure de la végétation basée sur les données de télédétection (disponible à l'échelle du village).\n- *phc*: Présence ou absence d'un centre de santé publique pour le village.\n\nNous pouvons compter le nombre de cas positifs et le nombre total d'enfants testés par village pour cartographier la fraction des cas positifs (ou prévalence, *prev*).\n\n```{r}\n# Jeu de données à l'échelle du village\ngambia_agg <- group_by(gambia, id_village, x, y, green, phc) %>%\n summarize(pos = sum(pos), total = n()) %>%\n mutate(prev = pos / total) %>%\n ungroup()\nhead(gambia_agg)\n```\n\n\n```{r, message = FALSE, warning = FALSE}\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nNous utilisons le jeu de données `gambia.borders` du package *geoR* pour tracer les frontières des pays avec `geom_path`. Comme ces frontières sont en mètres, nous les divisons par 1000 pour obtenir la même échelle que nos points. Nous utilisons également `coord_fixed` pour assurer un rapport d'aspect de 1:1 entre les axes et utilisons la palette de couleur `viridis`, qui permet de visualiser plus facilement une variable continue par rapport à la palette par défaut dans *ggplot2*.\n\nSur la base de cette carte, il semble y avoir une corrélation spatiale dans la prévalence du paludisme, le groupe de villages de l'est montrant des valeurs de prévalence plus élevées (jaune-vert) et le groupe du milieu montrant des valeurs de prévalence plus faibles (violet).\n\n## GLMM non spatial\n\nPour ce premier exemple, nous allons ignorer l'aspect spatial des données et modéliser la présence du paludisme (*pos*) en fonction de l'utilisation d'une moustiquaire (*netuse*) et de la présence d'un centre de santé publique (*phc*). Comme nous avons une réponse binaire, nous devons utiliser un modèle de régression logistique (un GLM). Comme nous avons des prédicteurs au niveau individuel et au niveau du village et que nous nous attendons à ce que les enfants d'un même village aient une probabilité plus similaire d'avoir le paludisme même après avoir pris en compte ces prédicteurs, nous devons ajouter un effet aléatoire du village. Le résultat est un GLMM que nous ajustons en utilisant la fonction `glmer` du package *lme4*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(lme4)\n\nmod_glmm <- glmer(pos ~ netuse + phc + (1 | id_village), \n data = gambia, family = binomial)\nsummary(mod_glmm)\n```\n\nD'après ces résultats, les variables *netuse* et *phc* sont toutes deux associées à une diminution de la prévalence du paludisme, bien que l'effet de *phc* ne soit pas significatif à un seuil $\\alpha = 0.05$. L'ordonnée à l'origine (0.149) est le logit de la probabilité de présence du paludisme pour un enfant sans moustiquaire et sans centre de santé publique, mais c'est l'ordonnée à l'origine moyenne pour tous les villages. Il y a beaucoup de variation entre les villages selon l'écart-type de l'effet aléatoire (0.90). Nous pouvons obtenir l'ordonnée à l'origine estimée pour chaque village avec la fonction `coef`:\n\n```{r}\nhead(coef(mod_glmm)$id_village)\n```\n\nPar exemple, l'ordonnée à l'origine pour le village 1 est environ 0.94, équivalente à une probabilité de 72%:\n\n```{r}\nplogis(0.937)\n```\n\ntandis que celle pour le village 2 est équivalente à une probabilité de 52%:\n\n```{r}\nplogis(0.092)\n```\n\nLe [package DHARMa](https://cran.r-project.org/web/packages/DHARMa/vignettes/DHARMa.html) fournit une méthode générale pour vérifier si les résidus d'un GLMM sont distribués selon le modèle spécifié et s'il existe une tendance résiduelle. Il simule des réplicats de chaque observation selon le modèle ajusté et détermine ensuite un \"résidu standardisé\", qui est la position relative de la valeur observée par rapport aux valeurs simulées, par exemple 0 si l'observation est plus petite que toutes les simulations, 0.5 si elle se trouve au milieu, etc. Si le modèle représente bien les données, chaque valeur du résidu standardisé entre 0 et 1 doit avoir la même probabilité, de sorte que les résidus standardisés doivent produire une distribution uniforme entre 0 et 1.\n\nLa fonction `simulateResiduals` effectue le calcul des résidus standardisés, puis la fonction `plot` trace les graphiques de diagnostic avec les résultats de certains tests.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(DHARMa)\nres_glmm <- simulateResiduals(mod_glmm)\nplot(res_glmm)\n```\n\nLe graphique de gauche est un graphique quantile-quantile des résidus standardisés. Les résultats de trois tests statistiques sont également présentés: un test de Kolmogorov-Smirnov (*KS*) qui vérifie s'il y a un écart par rapport à la distribution théorique, un test de dispersion qui vérifie s'il y a une sous-dispersion ou une surdispersion et un test de valeurs aberrantes (*outlier*) basé sur le nombre de résidus qui sont plus extrêmes que toutes les simulations. Ici, nous obtenons un résultat significatif pour les valeurs aberrantes, bien que le message indique que ce résultat pourrait avoir un taux d'erreur de type I plus grand que prévu dans ce cas.\n\nÀ droite, nous obtenons généralement un graphique des résidus standardisés (en *y*) en fonction du rang des valeurs prédites, afin de vérifier l'absence de tendance résiduelle. Ici, les prédictions sont regroupées par quartile, il serait donc préférable d'agréger les prédictions et les résidus par village, ce que nous pouvons faire avec la fonction `recalculateResiduals`.\n\n```{r}\nplot(recalculateResiduals(res_glmm, group = gambia$id_village))\n```\n\nLe graphique de droite montre les points individuels, ainsi qu'une régression quantile pour le 1er quartile, la médiane et le 3e quartile. En théorie, ces trois courbes devraient être des lignes droites horizontales (pas de tendance des résidus par rapport aux prévisions). La courbe pour le 3e quartile (en rouge) est significativement différente d'une ligne horizontale, ce qui pourrait indiquer un effet systématique manquant dans le modèle.\n\n## GLMM spatial avec spaMM\n\nLe package *spaMM* (modèles mixtes spatiaux) est un package R relativement récent qui permet d'effectuer une estimation approximative du maximum de vraisemblance des paramètres pour les GLM avec dépendance spatiale, modélisés soit comme un processus gaussien, soit avec un CAR (nous verrons ce dernier dans la dernière section). Le package implémente différents algorithmes, mais il existe une fonction unique `fitme` qui choisit l'algorithme approprié pour chaque type de modèle. Par exemple, voici le même modèle (non spatial) que nous avons vu ci-dessus, ajusté avec *spaMM*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spaMM)\n\nmod_spamm_glmm <- fitme(pos ~ netuse + phc + (1 | id_village),\n data = gambia, family = binomial)\nsummary(mod_spamm_glmm)\n```\n\nNotez que les estimés des effets fixes ainsi que la variance des effets aléatoires sont presque identiques à ceeux obtenues par `glmer` ci-dessus.\n\nNous pouvons maintenant utiliser *spaMM* pour ajuster le même modèle avec l'ajout de corrélations spatiales entre les villages. Dans la formule du modèle, ceci est représenté comme un effet aléatoire `Matern(1 | x + y)`, ce qui signifie que les ordonnées à l'origine sont spatialement corrélées entre les villages suivant une fonction de corrélation de Matérn des coordonnées (*x, y*). La fonction de Matérn est une fonction flexible de corrélation spatiale qui comprend un paramètre de forme $\\nu$ (`nu`), de sorte que lorsque $\\nu = 0,5$, elle est équivalente à la corrélation exponentielle, mais quand $\\nu$ prend de grandes valeurs, elle se rapproche d'une corrélation gaussienne. Nous pourrions laisser la fonction estimer $\\nu$, mais ici nous le fixons à 0.5 avec l'argument `fixed` de `fitme`.\n\n```{r}\nmod_spamm <- fitme(pos ~ netuse + phc + Matern(1 | x + y) + (1 | id_village),\n data = gambia, family = binomial, fixed = list(nu = 0.5))\nsummary(mod_spamm)\n```\n\nCommençons par vérifier les effets aléatoires du modèle. La fonction de corrélation spatiale a un paramètre `rho` égal à 0.0513. Ce paramètre dans *spaMM* est l'inverse de la portée, donc ici la portée de la corrélation exponentielle est de 1/0.0513 ou environ 19.5 km. Il y a maintenant deux pramètres de variance, celui identifié comme `x + y` est la variance à longue distance (i.e. le palier) pour le modèle de corrélation exponentielle alors que celui identifié comme `id_village` montre la portion non corrélée de la variation entre les villages.\n\nSi nous avions ici laissé les effets aléatoires `(1 | id_village)` dans la formule pour représenter la partie non spatiale de la variation entre les villages, nous pourrions également représenter ceci avec un effet de pépite dans le modèle géostatistique. Dans les deux cas, cela représenterait l'idée que même deux villages très proches l'un de l'autre auraient des prévalences de base différentes dans le modèle.\n\nPar défaut, la fonction `Matern` n'a pas d'effet de pépite, mais nous pouvons en ajouter un en spécifiant une `pépite` non nulle dans la liste initiale des paramètres `init`.\n\n```{r}\nmod_spamm2 <- fitme(pos ~ netuse + phc + Matern(1 | x + y),\n data = gambia, family = binomial, fixed = list(nu = 0.5),\n init = list(Nugget = 0.1))\nsummary(mod_spamm2)\n```\n\nComme vous pouvez le voir, toutes les estimations sont les mêmes, sauf que la variance de la portion spatiale (palier) est maintenant de 0.84 et que la pépite est égale à une fraction 0.235 de ce palier, soit une variance de 0.197, ce qui est identique à l'effet aléatoire `id_village` dans la version ci-dessus. Les deux formulations sont donc équivalentes.\n\nMaintenant, rappelons les coefficients que nous avions obtenus pour le GLMM non spatial :\n\n```{r}\nsummary(mod_glmm)$coefficients\n```\n\nDans la version spatiale, les deux effets fixes se sont légèrement rapprochés de zéro, mais l'erreur-type de l'effet de `phc` a diminué. Il est intéressant de noter que l'inclusion de la dépendance spatiale nous a permis d'estimer plus précisément l'effet de la présence d'un centre de santé publique dans le village. Ce ne serait pas toujours le cas: pour un prédicteur qui est également fortement corrélé dans l'espace, la corrélation spatiale dans la réponse rend plus difficile l'estimation de l'effet de ce prédicteur, puisqu'il est confondu avec l'effet spatial. Cependant, pour un prédicteur qui n'est pas corrélé dans l'espace, l'inclusion de l'effet spatial réduit la variance résiduelle (non spatiale) et peut donc augmenter la précision de l'effet du prédicteur.\n\nLe package *spaMM* est également compatible avec *DHARMa* pour les diagnostics résiduels. (Vous pouvez ignorer l'avertissement selon lequel il ne fait pas partie de la classe des modèles pris en charge, cela est dû à l'utilisation de la fonction `fitme` plutôt que d'une fonction d'algorithme spécifique dans *spaMM*).\n\n```{r}\nres_spamm <- simulateResiduals(mod_spamm2)\nplot(res_spamm)\nplot(recalculateResiduals(res_spamm, group = gambia$id_village))\n```\n\nEnfin, bien que nous allons montrer comment calculer et visualiser des prédictions spatiales ci-dessous, nous pouvons produire une carte rapide des effets spatiaux estimés dans un modèle *spaMM* avec la fonction `filled.mapMM`.\n\n```{r}\nfilled.mapMM(mod_spamm2)\n```\n\n## Processus gaussiens vs. splines de lissage\n\nSi vous connaissez bien les modèles additifs généralisés (GAM), vous avez peut-être pensé à représenter la variation spatiale de la prévalence du paludisme (comme le montre la carte ci-dessus) par une spline de lissage en 2D (en fonction de $x$ et $y$) dans un GAM.\n\nLe code ci-dessous correspond à l'équivalent GAM de notre GLMM avec processus gaussien ci-dessus, ajusté avec la fonction `gam` du package *mgcv*. L'effet spatial est représenté par la spline 2D `s(x, y)` alors que l'effet aléatoire non spatial de village est représenté par `s(id_village, bs = \"re\")`, qui est équivalent à `(1 | id_village)` dans les modèles précédents. Notez que pour la fonction `gam`, les variables catégorielles doivent être explicitement converties en facteurs.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(mgcv)\ngambia$id_village <- as.factor(gambia$id_village)\nmod_gam <- gam(pos ~ netuse + phc + s(id_village, bs = \"re\") + s(x, y), \n data = gambia, family = binomial)\n```\n\nPour visualiser la spline en 2D, nous utiliserons le package [*gratia*](https://fromthebottomoftheheap.net/2018/10/23/introducing-gratia/).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gratia)\ndraw(mod_gam)\n```\n\nNotez que le graphique de la spline `s(x, y)` (en haut à droite) ne s'étend pas trop loin des emplacements des données (les autres zones sont vides). Dans ce graphique, on peut également voir que les effets aléatoires des villages suivent la distribution gaussienne attendue (en haut à gauche).\n\nEnsuite, nous utiliserons à la fois le GLMM spatial de la section précédente et ce GAMM pour prédire la prévalence moyenne sur une grille spatiale de points contenue dans le fichier [gambia_pred.csv](data/gambia_pred.csv). Le graphique ci-dessous ajoute ces points de prédiction (en noir) sur la carte précédente des points de données.\n\n```{r, message = FALSE, warning = FALSE}\ngambia_pred <- read.csv(\"data/gambia_pred.csv\")\n\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(data = gambia_pred) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nPour faire des prédictions à partir du modèle GAMM à ces endroits, le code ci-dessous effectue les étapes suivantes:\n\n- Tous les prédicteurs du modèle doivent se trouver dans le tableau de données de prédiction, nous ajoutons donc des valeurs constantes de *netuse* et *phc* (toutes deux égales à 1) pour tous les points. Ainsi, nous ferons des prédictions sur la prévalence du paludisme dans le cas où un moustiquaire est utilisée et où un centre de santé publique est présent. Nous ajoutons également un *id_village* constant, bien qu'il ne soit pas utilisé dans les prédictions (voir ci-dessous).\n\n- Nous appelons la fonction `predict` à la sortie de `gam` pour produire des prédictions aux nouveaux points de données (argument `newdata`), en incluant les erreurs-types (`se.fit = TRUE`) et en excluant les effets aléatoires du village, donc la prédiction est faite pour un \"village moyen\". L'objet résultant `gam_pred` aura des colonnes `fit` (prédiction moyenne) et `se.fit` (erreur-type). Ces prédictions et erreurs-types sont sur l'échelle du lien (logit).\n\n- Nous rattachons le jeu de données de prédiction original à `gam_pred` avec `cbind`. \n\n- Nous ajoutons des colonnes pour la prédiction moyenne et les limites de l'intervalle de confiance à 50% (moyenne $\\pm$ 0.674 erreur-type), converties de l'échelle logit à l'échelle de probabilité avec `plogis`. Nous choisissons un intervalle de 50% car un intervalle de 95% peut être trop large ici pour contraster les différentes prédictions sur la carte à la fin de cette section.\n\n```{r}\ngambia_pred <- mutate(gambia_pred, netuse = 1, phc = 1, id_village = 1)\n\ngam_pred <- predict(mod_gam, newdata = gambia_pred, se.fit = TRUE, \n exclude = \"s(id_village)\")\ngam_pred <- cbind(gambia_pred, as.data.frame(gam_pred))\ngam_pred <- mutate(gam_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit), # 50% CI\n hi = plogis(fit + 0.674 * se.fit))\n```\n\n*Note* : La raison pour laquelle nous ne faisons pas de prédictions directement sur l'échelle de probabilité (réponse) est que la formule normale des intervalles de confiance s'applique plus précisément sur l'échelle logit. L'ajout d'un certain nombre d'erreurs-types autour de la moyenne sur l'échelle de probabilité conduirait à des intervalles moins précis et peut-être même à des intervalles de confiance en dehors de la plage de valeurs possible (0, 1) pour une probabilité.\n\nNous appliquons la même stratégie pour faire des prédictions à partir du GLMM spatial avec *spaMM*. Il y a quelques différences dans la méthode `predict` par rapport au cas du GAMM.\n\n- L'argument `binding = \"fit\"` signifie que les prédictions moyennes (colonne `fit`) seront attachées à l'ensemble de données de prédiction et retournées sous forme de tableau de données `spamm_pred`.\n\n- L'argument `variances = list(linPred = TRUE)` indique à `predict` de calculer la variance du prédicteur linéaire (donc le carré de l'erreur-type). Cependant, il apparaît comme un attribut `predVar` dans le tableau de données de sortie plutôt que dans une colonne `se.fit`, donc nous le déplaçons vers une colonne sur la ligne suivante. \n\n```{r}\nspamm_pred <- predict(mod_spamm, newdata = gambia_pred, type = \"link\",\n binding = \"fit\", variances = list(linPred = TRUE))\nspamm_pred$se.fit <- sqrt(attr(spamm_pred, \"predVar\"))\nspamm_pred <- mutate(spamm_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit),\n hi = plogis(fit + 0.674 * se.fit))\n```\n\nEnfin, nous combinons les deux ensembles de prédictions sous la forme de différentes rangées d'un tableau de données `pred_all` avec `bind_rows`. Le nom du tableau de données d'où provient chaque prédiction (`gam` ou `spamm`) apparaîtra dans la colonne \"model\" (argument `.id`). Pour simplifier la production du prochain graphique, nous utilisons ensuite `pivot_longer` dans le package *tidyr* pour changer les trois colonnes \"pred\", \"lo\" et \"hi\" en deux colonnes, \"stat\" et \"value\" (`pred_tall` a donc trois rangées pour chaque rangée dans `pred_all`).\n\n```{r}\npred_all <- bind_rows(gam = gam_pred, spamm = spamm_pred, .id = \"model\")\n\nlibrary(tidyr)\npred_tall <- pivot_longer(pred_all, c(pred, lo, hi), names_to = \"stat\",\n values_to = \"value\")\n```\n\nUne fois ces étapes franchies, nous pouvons enfin examiner les cartes de prédiction (moyenne, limites inférieure et supérieure de l'intervalle de confiance à 50 %) à l'aide d'un graphique `ggplot`. Les points de données originaux sont indiqués en rouge.\n\n```{r}\nggplot(pred_tall, aes(x = x, y = y)) +\n geom_point(aes(color = value)) +\n geom_point(data = gambia_agg, color = \"red\", size = 0) +\n coord_fixed() +\n facet_grid(stat~model) +\n scale_color_viridis_c() +\n theme_minimal()\n```\n\nBien que les deux modèles s'accordent à dire que la prévalence est plus élevée près du groupe de villages de l'est, le GAMM estime également une prévalence plus élevée en quelques points (bord ouest et autour du centre) où il n'y a pas de données. Il s'agit d'un artefact de la forme de la spline autour des points de données, puisqu'une spline est censée correspondre à une tendance globale, bien que non linéaire. En revanche, le modèle géostatistique représente l'effet spatial sous forme de corrélations locales et revient à la prévalence moyenne globale lorsqu'il est éloigné de tout point de données, ce qui est une supposition plus sûre. C'est l'une des raisons pour lesquelles il est préférable de choisir un modèle géostatistique / processus gaussien dans ce cas.\n\n## Méthodes bayésiennes pour les GLMM avec processus gaussiens\n\nLes modèles bayésiens fournissent un cadre flexible pour exprimer des modèles avec une structure de dépendance complexe entre les données, y compris la dépendance spatiale. Cependant, l'ajustement d'un modèle de processus gaussien avec une approche entièrement bayésienne peut être lent, en raison de la nécessité de calculer une matrice de covariance spatiale entre toutes les paires de points à chaque itération. \n\nLa méthode INLA (pour *integrated nested Laplace approximation*) effectue un calcul approximatif de la distribution postérieure bayésienne, ce qui la rend adaptée aux problèmes de régression spatiale. Nous ne l'abordons pas dans ce cours, mais je recommande le manuel de Paula Moraga (dans la section des références ci-dessous) qui fournit des exemples concrets d'utilisation de la méthode INLA pour divers modèles de données géostatistiques et aréales, dans le contexte de l'épidémiologie, y compris des modèles avec une dépendance à la fois spatiale et temporelle. Le livre présente les mêmes données sur le paludisme en Gambie comme exemple d'un ensemble de données géostatistiques, ce qui a inspiré son utilisation dans ce cours.\n\n# GLMM avec autorégression spatiale {#glmm-spatial-autoreg-fr}\n\nNous revenons au dernier exemple de la partie précédente, où nous avions modélisé le taux de cas de COVID-19 (cas / 1000) pour les divisions administratives du réseau de la santé (RLS) au Québec en fonction de leur densité de population. Le taux est donné par la colonne \"taux_1k\" dans le *shapefile* `rls_covid`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nrls_covid <- rls_covid[!is.na(rls_covid$dens_pop), ]\nplot(rls_covid[\"taux_1k\"])\n```\n\nAuparavant, nous avions modélisé le logarithme de ce taux comme une fonction linéaire du logarithme de la densité de population, la variance résiduelle étant corrélée entre les unités voisines via une structure CAR (autorégression conditionnelle), comme le montre le code ci-dessous.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spdep)\nlibrary(spatialreg)\n\nrls_nb <- poly2nb(rls_covid)\nrls_w <- nb2listw(rls_nb, style = \"B\")\n\ncar_lm <- spautolm(log(taux_1k) ~ log(dens_pop), data = rls_covid,\n listw = rls_w, family = \"CAR\")\nsummary(car_lm)\n```\n\n*Rappel*: La fonction `poly2nb` du package *spdep* crée une liste de voisins basée sur les polygones limitrophes dans un *shapefile*, puis `nb2listw` la convertit en une liste de poids, ici des poids binaires (`style = \"B\"`) de sorte que chaque région limitrophe reçoive le même poids de 1 dans le modèle autorégressif.\n\nAu lieu d'utiliser les taux, il serait possible de modéliser directement les cas avec une régression de Poisson, qui est appropriée pour les données de comptage. Pour tenir compte du fait que si le risque par personne était égal, les cas seraient proportionnels à la population, nous pouvons ajouter la population de l'unité `pop` comme *offset* dans la régression de Poisson. Par conséquent, le modèle ressemblerait à : `cas ~ log(dens_pop) + offset(log(pop))`. Notez que puisque la régression de Poisson utilise un lien logarithmique, ce modèle avec `log(pop)` comme *offset* suppose que `log(cas / pop)` (donc le taux logarithmique) est proportionnel à `log(dens_pop)`, tout comme le modèle linéaire ci-dessus, mais il a l'avantage de modéliser la variabilité des données brutes (le nombre de cas) directement avec une distribution de Poisson.\n\nNous n'avons pas la population dans ces données, mais nous pouvons l'estimer à partir des cas et du taux (cas / 1000) comme suit:\n\n```{r}\nrls_covid$pop <- rls_covid$cas / rls_covid$taux_1k * 1000\n```\n\nPour définir un modèle CAR dans *spaMM*, nous avons besoin d'une matrice de poids plutôt que d'une liste de poids comme dans le package *spatialreg*. Heureusement, le package *spdep* comprend également une fonction `nb2mat` pour convertir la liste des voisins en une matrice de poids, là encore en utilisant des poids binaires. Pour éviter un avertissement dans R, nous spécifions que les noms des lignes et des colonnes de cette matrice doivent être égaux aux identifiants associés à chaque unité (`RLS_code`). Ensuite, nous ajoutons un terme `adjacency(1 | RLS_code)` au modèle pour spécifier que la variation résiduelle entre les différents groupes définis par `RLS_code` est spatialement corrélée avec une structure CAR (ici, chaque groupe n'a qu'une observation puisque nous avons un point de données par unité RLS).\n\n```{r}\nlibrary(spaMM)\n\nrls_mat <- nb2mat(rls_nb, style = \"B\")\nrownames(rls_mat) <- rls_covid$RLS_code\ncolnames(rls_mat) <- rls_covid$RLS_code\n\nrls_spamm <- fitme(cas ~ log(dens_pop) + offset(log(pop)) + adjacency(1 | RLS_code),\n data = rls_covid, adjMatrix = rls_mat, family = poisson)\nsummary(rls_spamm)\n```\n\nNotez que le coefficient de corrélation spatiale `rho` (0.158) est similaire à la quantité équivalente dans le modèle `spautolm` ci-dessus, où il était appelé `Lambda`. L'effet de `log(dens_pop)` est également d'environ 0.2 dans les deux modèles.\n\n\n## Référence\n\nMoraga, Paula (2019) Geospatial Health Data: Modeling and Visualization with R-INLA and Shiny. Chapman & Hall/CRC Biostatistics Series. Disponible en ligne: [https://www.paulamoraga.com/book-geospatial/](https://www.paulamoraga.com/book-geospatial/). \n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":true,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"knitr"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"4-Day Training in Spatial Statistics with Philippe Marchand","description":"Training session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). |\nSession de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n","author":"Philippe Marchand","categories":["FR","EN","Technical"],"date":"2021-01-12","image":"image.jpg","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file +{"title":"Spatial Statistics in Ecology","markdown":{"yaml":{"title":"Spatial Statistics in Ecology","description":"Training session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). |\nSession de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n","author":"Philippe Marchand","categories":["FR","EN","Technical"],"date":"2021-01-12","image":"image.jpg","toc":true,"number-sections":true,"number-depth":1,"execute":{"freeze":true,"cache":true}},"headingText":"Spatial Statistics in Ecology","containsRefs":false,"markdown":"\n\nVersion en français [à la suite](#statistiques-spatiales-en-écologie).\n\n\nBIOS² hosted an online training session about statistical analysis of spatial data in ecology, led by Pr. Philippe Marchand (UQAT). This 12-hour training was conducted in 4 sessions: January 12, 14, 19 & 21 (2021) from 1:00 to 4:00 pm EST.\n\nThe content included three types of spatial statistical analyses and their applications to ecology: (1) point pattern analysis to study the distribution of individuals or events in space; (2) geostatistical models to represent the spatial correlation of variables sampled at geolocated points; and (3) areal data models, which apply to measurements taken on areas in space and model spatial relationships as networks of neighbouring regions. The training also included practical exercises using the R statistical programming environment.\n\n[Philippe Marchand](https://github.com/pmarchand1) is a professor in ecology and biostatistics at Institut de recherche sur les forêts, Université du Québec en Abitibi-Témiscamingue (UQAT) and BIOS² academic member. His research focuses on modeling processes that influence the spatial distribution of populations, including: seed dispersal and seedling establishment, animal movement, and the spread of forest diseases.\n\n**If you wish to consult the lesson materials and follow the exercises at your own pace, you can access them through [this link](https://bios2.github.io/Marchand.html#category:EN). Basic knowledge of linear regression models and experience fitting them in R is recommended. Original repository can be found [here](https://github.com/pmarchand1/BIOS2-spatial-stats).**\n\n## Course outline\n\n| Day | Topics (EN) |\n|-----------------|:--------------------------|\n| 1 | • [Introduction to spatial statistics](#introduction)
• [Point pattern analysis](#point-pattern)
|\n| 2 | • [Spatial correlation](#spatial-correlation)
• [Geostatistical models](#geostat-models) |\n| 3 | • [Areal data](#areal-data)
• [Moran's I](#moran-i)
• [Spatial autoregression models](#spatial-autoreg)
• [Analysis of areal data in R](#analysis-areal) |\n| 4 | • [GLMM with spatial Gaussian process](#glmm-spatial-gaussian)
• [GLMM with spatial autoregression](#glmm-spatial-autoreg) |\n\n\n# Introduction to spatial statistics {#introduction}\n\n## Types of spatial analyses\n\nIn this training, we will discuss three types of spatial analyses: point pattern analysis, geostatistical models and models for areal data.\n\nIn **point pattern analysis**, we have point data representing the position of individuals or events in a study area and we assume that all individuals or events have been identified in that area. That analysis focuses on the distribution of the positions of the points themselves. Here are some typical questions for the analysis of point patterns:\n\n- Are the points randomly arranged or clustered?\n\n- Are two types of points arranged independently?\n\n**Geostatistical models** represent the spatial distribution of continuous variables that are measured at certain sampling points. They assume that measurements of those variables at different points are correlated as a function of the distance between the points. Applications of geostatistical models include the smoothing of spatial data (e.g., producing a map of a variable over an entire region based on point measurements) and the prediction of those variables for non-sampled points.\n\n**Areal data** are measurements taken not at points, but for regions of space represented by polygons (e.g. administrative divisions, grid cells). Models representing these types of data define a network linking each region to its neighbours and include correlations in the variable of interest between neighbouring regions.\n\n## Stationarity and isotropy\n\nSeveral spatial analyses assume that the variables are **stationary** in space. As with stationarity in the time domain, this property means that summary statistics (mean, variance and correlations between measures of a variable) do not vary with translation in space. For example, the spatial correlation between two points may depend on the distance between them, but not on their absolute position.\n\nIn particular, there cannot be a large-scale trend (often called *gradient* in a spatial context), or this trend must be taken into account before modelling the spatial correlation of residuals.\n\nIn the case of point pattern analysis, stationarity (also called homogeneity) means that point density does not follow a large-scale trend.\n\nIn a **isotropic** statistical model, the spatial correlations between measurements at two points depend only on the distance between the points, not on the direction. In this case, the summary statistics do not change under a spatial rotation of the data.\n\n## Georeferenced data\n\nEnvironmental studies increasingly use data from geospatial data sources, i.e. variables measured over a large part of the globe (e.g. climate, remote sensing). The processing of these data requires concepts related to Geographic Information Systems (GIS), which are not covered in this workshop, where we focus on the statistical aspects of spatially varying data.\n\nThe use of geospatial data does not necessarily mean that spatial statistics are required. For example, we will often extract values of geographic variables at study points to explain a biological response observed in the field. In this case, the use of spatial statistics is only necessary when there is a spatial correlation in the residuals, after controlling for the effect of the predictors.\n\n# Point pattern analysis {#point-pattern}\n\n## Point pattern and point process\n\nA *point pattern* describes the spatial position (most often in 2D) of individuals or events, represented by points, in a given study area, often called the observation \"window\".\n\nIt is assumed that each point has a negligible spatial extent relative to the distances between the points. More complex methods exist to deal with spatial patterns of objects that have a non-negligible width, but this topic is beyond the scope of this workshop.\n\nA *point process* is a statistical model that can be used to simulate point patterns or explain an observed point pattern.\n\n## Complete spatial randomness\n\nComplete spatial randomness (CSR) is one of the simplest point patterns, which serves as a null model for evaluating the characteristics of real point patterns. In this pattern, the presence of a point at a given position is independent of the presence of points in a neighbourhood.\n\nThe process creating this pattern is a homogeneous Poisson process. According to this model, the number of points in any area $A$ follows a Poisson distribution: $N(A) \\sim \\text{Pois}(\\lambda A)$, where $\\lambda$ is the *intensity* of the process (i.e. the density of points per unit area). $N$ is independent between two disjoint regions, no matter how those regions are defined.\n\nIn the graph below, only the pattern on the right is completely random. The pattern on the left shows point aggregation (higher probability of observing a point close to another point), while the pattern in the center shows repulsion (low probability of observing a point very close to another).\n\n```{r, include = FALSE}\nlibrary(spatstat)\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\nset.seed(82)\ncsrp <- rpoispp(lambda = 100)\naggp <- rMatClust(20, 0.1, 5)\nevenp <- rMaternII(150, 0.05)\npar(mfrow = c(1, 3))\nplot(aggp, main = \"Aggregation\", pch = 19)\nplot(evenp, main = \"Repulsion\", pch = 19)\nplot(csrp, main = \"Random\", pch = 19)\n```\n\n## Exploratory or inferential analysis for a point pattern\n\nSeveral summary statistics are used to describe the characteristics of a point pattern. The simplest is the intensity $\\lambda$, which as mentioned above represents the density of points per unit area. If the point pattern is heterogeneous, the intensity is not constant, but depends on the position: $\\lambda(x, y)$.\n\nCompared to intensity, which is a first-order statistic, second-order statistics describe how the probability of the presence of a point in a region depends on the presence of other points. The Ripley's $K$ function presented in the next section is an example of a second-order summary statistic.\n\nStatistical inferences on point patterns usually consist of testing the hypothesis that the point pattern corresponds to a given null model, such as CSR or a more complex null model. Even for the simplest null models, we rarely know the theoretical distribution for a summary statistic of the point pattern under the null model. Hypothesis tests on point patterns are therefore performed by simulation: a large number of point patterns are simulated from the null model and the distribution of the summary statistics of interest for these simulations is compared to their values for the observed point pattern.\n\n## Ripley's K function\n\nRipley's K function $K(r)$ is defined as the mean number of points within a circle of radius $r$ around a point in the pattern, standardized by the intensity $\\lambda$.\n\nUnder the CSR null model, the mean number of points in any circle of radius $r$ is $\\lambda \\pi r^2$, thus in theory $K(r) = \\pi r^2$ for that model. A higher value of $K(r)$ means that there is an aggregation of points at the scale $r$, whereas a lower value means that there is repulsion.\n\nIn practice, $K(r)$ is estimated for a specific point pattern by the equation:\n\n$$ K(r) = \\frac{A}{n(n-1)} \\sum_i \\sum_{j > i} I \\left( d_{ij} \\le r \\right) w_{ij}$$\n\nwhere $A$ is the area of the observation window and $n$ is the number of points in the pattern, so $n(n-1)$ is the number of distinct pairs of points. We take the sum for all pairs of points of the indicator function $I$, which takes a value of 1 if the distance between points $i$ and $j$ is less than or equal to $r$. Finally, the term $w_{ij}$ is used to give extra weight to certain pairs of points to account for edge effects, as discussed in the next section.\n\nFor example, the graphs below show the estimated $K(r)$ function for the patterns shown above, for values of $r$ up to 1/4 of the window width. The red dashed curve shows the theoretical value for CSR and the gray area is an \"envelope\" produced by 99 simulations of that null pattern. The aggregated pattern shows an excess of neighbours up to $r = 0.25$ and the pattern with repulsion shows a significant deficit of neighbours for small values of $r$.\n\n```{r, include = FALSE}\nkagg <- envelope(aggp, Kest, correction = \"iso\") \nkeven <- envelope(evenp, Kest, correction = \"iso\")\nkcsr <- envelope(csrp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\npar(mfrow = c(1, 3))\nplot(kagg, main = \"Aggregation\", legend = FALSE)\nplot(keven, main = \"Repulsion\", legend = FALSE)\nplot(kcsr, main = \"Random\", legend = FALSE)\n```\n\nIn addition to $K$, there are other statistics to describe the second-order properties of point patterns, such as the mean distance between a point and its nearest $N$ neighbours. You can refer to the Wiegand and Moloney (2013) textbook in the references to learn more about different summary statistics for point patterns.\n\n## Edge effects\n\nIn the context of point pattern analysis, edge effects are due to the fact that we have incomplete knowledge of the neighbourhood of points near the edge of the observation window, which can induce a bias in the calculation of statistics such as Ripley's $K$.\n\nDifferent methods have been developed to correct the bias due to edge effects. In Ripley's edge correction method, the contribution of a neighbour $j$ located at a distance $r$ from a point $i$ receives a weight $w_{ij} = 1/\\phi_i(r)$, where $\\phi_i(r)$ is the fraction of the circle of radius $r$ around $i$ contained in the observation window. For example, if 2/3 of the circle is in the window, this neighbour counts as 3/2 neighbours in the calculation of a statistic like $K$.\n\n![](images/ripley_edge.png)\n\nRipley's method is one of the simplest to correct for edge effects, but is not necessarily the most efficient; in particular, larger weights given to certain pairs of points tend to increase the variance of the calculated statistic. Other correction methods are presented in specialized textbooks, such as Wiegand and Moloney (2013).\n\n## Example\n\nFor this example, we use the dataset [semis_xy.csv](data/semis_xy.csv), which represents the $(x, y)$ coordinates for seedlings of two species (*sp*, B = birch and P = poplar) in a 15 x 15 m plot.\n\n```{r}\nsemis <- read.csv(\"data/semis_xy.csv\")\nhead(semis)\n```\n\nThe *spatstat* package provides tools for point pattern analysis in R. The first step consists in transforming our data frame into a `ppp` object (point pattern) with the function of the same name. In this function, we specify which columns contain the coordinates *x* and *y* as well as the *marks*, which here will be the species codes. We also need to specify an observation window (`window`) using the `owin` function, where we provide the plot limits in *x* and *y*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spatstat)\n\nsemis <- ppp(x = semis$x, y = semis$y, marks = as.factor(semis$sp),\n window = owin(xrange = c(0, 15), yrange = c(0, 15)))\nsemis\n```\n\nMarks can be numeric or categorical. Note that for categorical marks as is the case here, the variable must be explicitly converted to a factor.\n\nThe `plot` function applied to a point pattern shows a diagram of the pattern.\n\n```{r}\nplot(semis)\n```\n\nThe `intensity` function calculates the density of points of each species by unit area (here, by $m^2$).\n\n```{r}\nintensity(semis)\n```\n\nTo first analyze the distribution of each species separately, we split the pattern with `split`. Since the pattern contains categorical marks, it is automatically split according to the values of those marks. The result is a list of two point patterns.\n\n```{r}\nsemis_split <- split(semis)\nplot(semis_split)\n```\n\nThe `Kest` function calculates Ripley's $K$ for a series of distances up to (by default) 1/4 of the width of the window. Here we apply it to the first pattern (birch) by choosing `semis_split[[1]]`. Note that double square brackets are necessary to choose an item from a list in R.\n\nThe argument `correction = \"iso\"` tells the function to apply Ripley's correction for edge effects.\n\n```{r}\nk <- Kest(semis_split[[1]], correction = \"iso\")\nplot(k)\n```\n\nAccording to this graph, there seems to be an excess of neighbours for distances of 1 m and above. To check if this is a significant difference, we produce a simulation envelope with the `envelope` function. The first argument of `envelope` is a point pattern to which the simulations will be compared, the second one is a function to be computed (here, `Kest`) for each simulated pattern, then we add the arguments of the `Kest` function (here, only `correction`).\n\n```{r}\nplot(envelope(semis_split[[1]], Kest, correction = \"iso\"))\n```\n\nAs indicated by the message, by default the function performs 99 simulations of the null model corresponding to complete spatial randomness (CSR).\n\nThe observed curve falls outside the envelope of the 99 simulations near $r = 2$. We must be careful not to interpret too quickly a result that is outside the envelope. Although there is about a 1% probability of obtaining a more extreme result under the null hypothesis at a given distance, the envelope is calculated for a large number of values of $r$ and is not corrected for multiple comparisons. Thus, a significant difference for a very small range of values of $r$ may be simply due to chance.\n\n### Exercise 1\n\nLooking at the graph of the second point pattern (poplar seedlings), can you predict where Ripley's $K$ will be in relation to the null hypothesis of complete spatial randomness? Verify your prediction by calculating Ripley's $K$ for this point pattern in R.\n\n## Effect of heterogeneity\n\nThe graph below illustrates a *heterogeneous* point pattern, i.e. it shows an density gradient (more points on the left than on the right).\n\n```{r, include = FALSE}\nlam_gr <- function(x, y) ifelse(x < 0.5, 500*(1-x), 200*(1-x))\nhetp <- rpoispp(lam_gr)\nkhet <- envelope(hetp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nplot(hetp, pch = 19, main = \"\")\nplot(khet, main = \"\", legend = FALSE)\n```\n\nA density gradient can be confused with an aggregation of points, as can be seen on the graph of the corresponding Ripley's $K$. In theory, these are two different processes:\n\n- Heterogeneity: The density of points varies in the study area, for example due to the fact that certain local conditions are more favorable to the presence of the species of interest.\n\n- Aggregation: The mean density of points is homogeneous, but the presence of one point increases the presence of other points in its vicinity, for example due to positive interactions between individuals.\n\nHowever, it may be difficult to differentiate between the two in practice, especially since some patterns may be both heterogeneous and aggregated.\n\nLet's take the example of the poplar seedlings from the previous exercise. The `density` function applied to a point pattern performs a kernel density estimation of the density of the seedlings across the plot. By default, this function uses a Gaussian kernel with a standard deviation `sigma` specified in the function, which determines the scale at which density fluctuations are \"smoothed\". Here, we use a value of 2 m for `sigma` and we first represent the estimated density with `plot`, before overlaying the points (`add = TRUE` means that the points are added to the existing plot rather than creating a new plot).\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 2)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n```\n\nTo measure the aggregation or repulsion of points in a heterogeneous pattern, we must use the inhomogeneous version of the $K$ statistic (`Kinhom` in *spatstat*). This statistic is still equal to the mean number of neighbours within a radius $r$ of a point in the pattern, but rather than standardizing this number by the overall intensity of the pattern, it is standardized by the local estimated density. As above, we specify `sigma = 2` to control the level of smoothing for the varying density estimate.\n\n```{r}\nplot(Kinhom(semis_split[[2]], sigma = 2, correction = \"iso\"))\n```\n\nTaking into account the heterogeneity of the pattern at a scale `sigma` of 2 m, there seems to be a deficit of neighbours starting at a radius of about 1.5 m. We can now check whether this deviation is significant.\n\nAs before, we use `envelope` to simulate the `Kinhom` statistic under the null model. However, the null model here is not a homogeneous Poisson process (CSR). It is instead a heterogeneous Poisson process simulated by the function `rpoispp(dens_p)`, i.e. the points are independent of each other, but their density is heterogeneous and given by `dens_p`. The `simulate` argument of the `envelope` function specifies the function used for simulations under the null model; this function must have one argument, here `x`, even if it is not used.\n\nFinally, in addition to the arguments needed for `Kinhom`, i.e. `sigma` and `correction`, we also specify `nsim = 199` to perform 199 simulations and `nrank = 5` to eliminate the 5 most extreme results on each side of the envelope, i.e. the 10 most extreme results out of 199, to achieve an interval containing about 95% of the probability under the null hypothesis.\n\n```{r}\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 2, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\n*Note*: For a hypothesis test based on simulations of a null hypothesis, the $p$-value is estimated by $(m + 1)/(n + 1)$, where $n$ is the number of simulations and $m$ is the number of simulations where the value of the statistic is more extreme than that of the observed data. This is why the number of simulations is often chosen to be 99, 199, etc.\n\n### Exercise 2\n\nRepeat the heterogeneous density estimation and `Kinhom` calculation with a standard deviation `sigma` of 5 rather than 2. How does the smoothing level for the density estimation influence the conclusions?\n\nTo differentiate between a variation in the density of points from an interaction (aggregation or repulsion) between these points with this type of analysis, it is generally assumed that the two processes operate at different scales. Typically, we can test whether the points are aggregated at a small scale after accounting for a variation in density at a larger scale.\n\n## Relationship between two point patterns\n\nLet's consider a case where we have two point patterns, for example the position of trees of two species in a plot (orange and green points in the graph below). Each of the two patterns may or may not present an aggregation of points.\n\n```{r, echo = FALSE}\ndata(lansing)\nlansing <- subset(lansing, marks %in% c(\"maple\", \"redoak\"), drop = TRUE)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"\", legend = FALSE)\n```\n\nRegardless of whether points are aggregated at the species level, we want to determine whether the two species are arranged independently. In other words, does the probability of observing a tree of one species depend on the presence of a tree of the other species at a given distance?\n\nThe bivariate version of Ripley's $K$ allows us to answer this question. For two patterns noted 1 and 2, the function $K_{12}(r)$ calculates the mean number of points in pattern 2 within a radius $r$ from a point in pattern 1, standardized by the density of pattern 2.\n\nIn theory, this function is symmetrical, so $K_{12}(r) = K_{21}(r)$ and the result would be the same whether the points of pattern 1 or 2 are chosen as \"focal\" points for the analysis. However, the estimation of the two quantities for an observed pattern may differ, in particular because of edge effects. The variance of $K_{12}$ and $K_{21}$ between simulations of a null model may also differ, so the null hypothesis test may have more or less power depending on the choice of the focal species.\n\nThe choice of an appropriate null model is important here. In order to determine whether there is a significant attraction or repulsion between the two patterns, the position of one of the patterns must be randomly moved relative to that of the other pattern, while keeping the spatial structure of each pattern taken in isolation.\n\nOne way to do this randomization is to shift one of the two patterns horizontally and/or vertically by a random distance. The part of the pattern that \"comes out\" on one side of the window is attached to the other side. This method is called a toroidal shift, because by connecting the top and bottom as well as the left and right of a rectangular surface, we obtain the shape of a torus (a three-dimensional \"donut\").\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nset.seed(35)\nrsh <- rshift(lansing, which = 1, width = 0.5, height = 0)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Original\", legend = FALSE)\nrect(xleft = 1 - rsh$x[8], xright = 1, ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\nplot(rsh, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"After translation\", legend = FALSE)\nrect(xleft = 0, xright = rsh$x[8], ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\n```\n\nThe graph above shows a translation of the green pattern to the right, while the orange pattern remains in the same place. The green points in the shaded area are brought back on the other side. Note that while this method generally preserves the structure of each pattern while randomizing their relative position, it can have some drawbacks, such as dividing point clusters that are near the cutoff point.\n\nLet's now check whether the position of the two species (birch and poplar) is independent in our plot. The function `Kcross` calculates the bivariate $K_{ij}$, we must specify which type of point (mark) is considered as the focal species $i$ and the neighbouring species $j$.\n\n```{r}\nplot(Kcross(semis, i = \"P\", j = \"B\", correction = \"iso\"))\n```\n\nHere, the observed $K$ is lower than the theoretical value, indicating a possible repulsion between the two patterns.\n\nTo determine the envelope of the $K$ under the null hypothesis of independence of the two patterns, we must specify that the simulations are based on a translation of the patterns. We indicate that the simulations use the function `rshift` (random translation) with the argument `simulate = function(x) rshift(x, which = \"B\")`; here, the `x` argument in `simulate` corresponds to the original point pattern and the `which` argument indicates which of the patterns is translated. As in the previous case, the arguments needed for `Kcross`, i.e. `i`, `j` and `correction`, must be repeated in the `envelope` function.\n\n```{r}\nplot(envelope(semis, Kcross, i = \"P\", j = \"B\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = function(x) rshift(x, which = \"B\")))\n```\n\nHere, the observed curve is totally within the envelope, so we do not reject the null hypothesis of independence of the two patterns.\n\n### Questions\n\n1. What would be one reason for our choice to translate the points of the birch rather than poplar?\n\n2. Would the simulations generated by random translation be a good null model if the two patterns were heterogeneous?\n\n## Marked point patterns\n\nThe [fir.csv](data/fir.csv) dataset contains the $(x, y)$ coordinates of 822 fir trees in a 1 hectare plot and their status (A = alive, D = dead) following a spruce budworm outbreak.\n\n```{r}\nfir <- read.csv(\"data/fir.csv\")\nhead(fir)\n```\n\n```{r}\nfir <- ppp(x = fir$x, y = fir$y, marks = as.factor(fir$status),\n window = owin(xrange = c(0, 100), yrange = c(0, 100)))\nplot(fir)\n```\n\nSuppose that we want to check whether fir mortality is independent or correlated between neighbouring trees. How does this question differ from the previous example, where we wanted to know if the position of the points of two species was independent?\n\nIn the previous example, the independence or interaction between the species referred to the formation of the pattern itself (whether or not seedlings of one species establish near those of the other species). Here, the characteristic of interest (survival) occurs after the establishment of the pattern, assuming that all those trees were alive at first and that some died as a result of the outbreak. So we take the position of the trees as fixed and we want to know whether the distribution of status (dead, alive) among those trees is random or shows a spatial pattern.\n\nIn Wiegand and Moloney's textbook, the first situation (establishment of seedlings of two species) is called a bivariate pattern, so it is really two interacting patterns, while the second is a single pattern with a qualitative *mark*. The *spatstat* package in R does not differentiate between the two in terms of pattern definition (types of points are always represented by the `marks` argument), but the analysis methods applied to the two questions differ.\n\nIn the case of a pattern with a qualitative mark, we can define a *mark connection function* $p_{ij}(r)$. For two points separated by a distance $r$, this function gives the probability that the first point has the mark $i$ and the second the mark $j$. Under the null hypothesis where the marks are independent, this probability is equal to the product of the proportions of each mark in the entire pattern, $p_{ij}(r) = p_i p_j$ independently of $r$.\n\nIn *spatstat*, the mark connection function is computed with the `markconnect` function, where the marks $i$ and $j$ and the type of edge correction must be specified. In our example, we see that two closely spaced points are less likely to have a different status (A and D) than expected under the assumption of random and independent distribution of marks (red dotted line).\n\n```{r}\nplot(markconnect(fir, i = \"A\", j = \"D\", correction = \"iso\"))\n```\n\nIn this graph, the fluctuations in the function are due to the estimation error of a continuous $r$ function from a limited number of discrete point pairs.\n\nTo simulate the null model in this case, we use the `rlabel` function, which randomly reassigns the marks among the points of the pattern, keeping the points' positions fixed.\n\n```{r}\nplot(envelope(fir, markconnect, i = \"A\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nNote that since the `rlabel` function has only one required argument corresponding to the original point pattern, it was not necessary to specify: `simulate = function(x) rlabel(x)`.\n\nHere are the results for tree pairs of the same status A or D:\n\n```{r, fig.dim = c(10, 5)}\npar(mfrow = c(1, 2))\nplot(envelope(fir, markconnect, i = \"A\", j = \"A\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\nplot(envelope(fir, markconnect, i = \"D\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nIt therefore appears that fir mortality due to this outbreak is spatially aggregated, since trees located in close proximity to each other have a greater probability of sharing the same status than predicted by the null hypothesis.\n\n## References\n\nFortin, M.-J. and Dale, M.R.T. (2005) *Spatial Analysis: A Guide for Ecologists*. Cambridge University Press: Cambridge, UK.\n\nWiegand, T. and Moloney, K.A. (2013) *Handbook of Spatial Point-Pattern Analysis in Ecology*, CRC Press.\n\nThe dataset in the last example is a subet of the Lake Duparquet Research and Teaching Forest (LDRTF) data, available on Dryad [here](https://doi.org/10.5061/dryad.tqjq2bvwz).\n\n# Solutions\n\n### Exercise 1\n\n```{r}\nplot(envelope(semis_split[[2]], Kest, correction = \"iso\"))\n```\n\nPoplar seedlings seem to be significantly aggregated according to the $K$ function.\n\n### Exercise 2\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 5)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 5, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\nHere, as we estimate density variations at a larger scale, even after accounting for this variation, the poplar seedlings seem to be aggregated at a small scale.\n\n# Spatial correlation of a variable {#spatial-correlation}\n\n```{r setup-spatial, include=FALSE}\n# knitr::opts_chunk$set(echo = TRUE)\nlibrary(tidyverse)\nlibrary(cowplot)\ntheme_set(theme_cowplot())\n```\n\nCorrelation between measurements of a variable taken at nearby points often occurs in environmental data. This principle is sometimes referred to as the \"first law of geography\" and is expressed in the following quote from Waldo Tobler: \"Everything is related to everything else, but near things are more related than distant things\".\n\nIn statistics, we often refer to *autocorrelation* as the correlation between measurements of the same variable taken at different times (temporal autocorrelation) or places (spatial autocorrelation).\n\n## Intrinsic or induced dependence\n\nThere are two basic types of spatial dependence on a measured variable $y$: an *intrinsic* dependence on $y$, or a dependence *induced* by external variables influencing $y$, which are themselves spatially correlated.\n\nFor example, suppose that the abundance of a species is correlated between two sites located near each other:\n\n- this spatial dependence can be induced if it is due to a spatial correlation of habitat factors that are favorable or unfavorable to the species;\n\n- or it can be intrinsic if it is due to the dispersion of individuals to nearby sites.\n\nIn many cases, both types of dependence affect a given variable.\n\nIf the dependence is simply induced and the external variables that cause it are included in the model explaining $y$, then the model residuals will be independent and we can use all the methods already seen that ignore spatial correlation.\n\nHowever, if the dependence is intrinsic or due to unmeasured external factors, then the spatial correlation of the residuals in the model will have to be taken into account.\n\n## Different ways to model spatial effects\n\nIn this training, we will directly model the spatial correlations of our data. It is useful to compare this approach to other ways of including spatial aspects in a statistical model.\n\nFirst, we could include predictors in the model that represent position (e.g., longitude, latitude). Such predictors may be useful for detecting a systematic large-scale trend or gradient, whether or not the trend is linear (e.g., with a generalized additive model).\n\nIn contrast to this approach, the models we will see now serve to model a spatial correlation in the random fluctuations of a variable (i.e., in the residuals after removing any systematic effect).\n\nMixed models use random effects to represent the non-independence of data on the basis of their grouping, i.e., after accounting for systematic fixed effects, data from the same group are more similar (their residual variation is correlated) than data from different groups. These groups were sometimes defined according to spatial criteria (observations grouped into sites).\n\nHowever, in the context of a random group effect, all groups are as different from each other, e.g., two sites within 100 km of each other are no more or less similar than two sites 2 km apart.\n\nThe methods we will see here and in the next parts of the training therefore allow us to model non-independence on a continuous scale (closer = more correlated) rather than just discrete (hierarchy of groups).\n\n# Geostatistical models {#geostat-models}\n\nGeostatistics refers to a group of techniques that originated in the earth sciences. Geostatistics is concerned with variables that are continuously distributed in space and where a number of points are sampled to estimate this distribution. A classic example of these techniques comes from the mining field, where the aim was to create a map of the concentration of ore at a site from samples taken at different points on the site.\n\nFor these models, we will assume that $z(x, y)$ is a stationary spatial variable measured at points with coordinates $x$ and $y$.\n\n## Variogram\n\nA central aspect of geostatistics is the estimation of the variogram $\\gamma_z$ . The variogram is equal to half the mean square difference between the values of $z$ for two points $(x_i, y_i)$ and $(x_j, y_j)$ separated by a distance $h$.\n\n$$\\gamma_z(h) = \\frac{1}{2} \\text{E} \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h}$$\n\nIn this equation, the $\\text{E}$ function with the index $d_{ij}=h$ designates the statistical expectation (i.e., the mean) of the squared deviation between the values of $z$ for points separated by a distance $h$.\n\nIf we want instead to express the autocorrelation $\\rho_z(h)$ between measures of $z$ separated by a distance $h$, it is related to the variogram by the equation:\n\n$$\\gamma_z = \\sigma_z^2(1 - \\rho_z)$$ ,\n\nwhere $\\sigma_z^2$ is the global variance of $z$.\n\nNote that $\\gamma_z = \\sigma_z^2$ when we reach a distance where the measurements of $z$ are independent, so $\\rho_z = 0$. In this case, we can see that $\\gamma_z$ is similar to a variance, although it is sometimes called \"semivariogram\" or \"semivariance\" because of the 1/2 factor in the above equation.\n\n## Theoretical models for the variogram\n\nSeveral parametric models have been proposed to represent the spatial correlation as a function of the distance between sampling points. Let us first consider a correlation that decreases exponentially:\n\n$$\\rho_z(h) = e^{-h/r}$$\n\nHere, $\\rho_z = 1$ for $h = 0$ and the correlation is multiplied by $1/e \\approx 0.37$ each time the distance increases by $r$. In this context, $r$ is called the *range* of the correlation.\n\nFrom the above equation, we can calculate the corresponding variogram.\n\n$$\\gamma_z(h) = \\sigma_z^2 (1 - e^{-h/r})$$\n\nHere is a graphical representation of this variogram.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 5*(1-exp(-1)),\n yend = 5*(1-exp(-1))), \n arrow = arrow(length = unit(0.05, \"inches\"), ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 3.5, label = \"range\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"sill\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nBecause of the exponential function, the value of $\\gamma$ at large distances approaches the global variance $\\sigma_z^2$ without exactly reaching it. This asymptote is called a *sill* in the geostatistical context and is represented by the symbol $s$.\n\nFinally, it is sometimes unrealistic to assume a perfect correlation when the distance tends towards 0, because of a possible variation of $z$ at a very small scale. A *nugget* effect, denoted $n$, can be added to the model so that $\\gamma$ approaches $n$ (rather than 0) if $h$ tends towards 0. The term nugget comes from the mining origin of these techniques, where a nugget could be the source of a sudden small-scale variation in the concentration of a mineral.\n\nBy adding the nugget effect, the remainder of the variogram is \"compressed\" to keep the same sill, resulting in the following equation.\n\n$$\\gamma_z(h) = n + (s - n) (1 - e^{-h/r})$$\n\nIn the *gstat* package that we use below, the term $(s-n)$ is called a *partial sill* or `psill` for the exponential portion of the variogram.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 4 * (1 - exp(-x/3)) + 1,\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 4*(1-exp(-1)) + 1,\n yend = 4*(1-exp(-1)) + 1), \n arrow = arrow(length = unit(0.05, \"inches\"), \n ends = \"both\", type = \"closed\")) +\n geom_segment(aes(x = 0, xend = 0, y = 0, yend = 0.9),\n arrow = arrow(length = unit(0.05, \"inches\"),\n ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 4, label = \"range\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"sill\") +\n annotate(\"text\", x = 0.5, y = 0.5, label = \"nugget\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nIn addition to the exponential model, two other common theoretical models for the variogram are the Gaussian model (where the correlation follows a half-normal curve), and the spherical model (where the variogram increases linearly at the start and then curves and reaches the plateau at a distance equal to its range $r$). The spherical model thus allows the correlation to be exactly 0 at large distances, rather than gradually approaching zero in the case of the other models.\n\n| Model | $\\rho(h)$ | $\\gamma(h)$ |\n|------------------|-------------------------|-----------------------------|\n| Exponential | $\\exp\\left(-\\frac{h}{r}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h}{r}\\right)\\right)$ |\n| Gaussian | $\\exp\\left(-\\frac{h^2}{r^2}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h^2}{r^2}\\right)\\right)$ |\n| Spherical $(h < r)$ \\* | $1 - \\frac{3}{2}\\frac{h}{r} + \\frac{1}{2}\\frac{h^3}{r^3}$ | $s \\left(\\frac{3}{2}\\frac{h}{r} - \\frac{1}{2}\\frac{h^3}{r^3} \\right)$ |\n\n\\* For the spherical model, $\\rho = 0$ and $\\gamma = s$ if $h \\ge r$.\n\n```{r, echo = FALSE, fig.dim = c(9, 4)}\nvexp <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Exponential\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n \n\nvgau <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Gaussian\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x^2/4^2)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nvsph <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Spherical\") +\n stat_function(fun = function(x) ifelse(x < 8, 5 * (1.5*x/8 - 0.5*x^3/8^3), 5),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nplot_grid(vexp, vgau, vsph, nrow = 1)\n```\n\n## Empirical variogram\n\nTo estimate $\\gamma_z(h)$ from empirical data, we need to define distance classes, thus grouping different distances within a margin of $\\pm \\delta$ around a distance $h$, then calculating the mean square deviation for the pairs of points in that distance class.\n\n$$\\hat{\\gamma_z}(h) = \\frac{1}{2 N_{\\text{paires}}} \\sum \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h \\pm \\delta}$$\n\nWe will see in the next section how to estimate a variogram in R.\n\n## Regression model with spatial correlation\n\nThe following equation represents a multiple linear regression including residual spatial correlation:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nHere, $v$ designates the response variable and $u$ the predictors, to avoid confusion with the spatial coordinates $x$ and $y$.\n\nIn addition to the residual $\\epsilon$ that is independent between observations, the model includes a term $z$ that represents the spatially correlated portion of the residual variance.\n\nHere are suggested steps to apply this type of model:\n\n1. Fit the regression model without spatial correlation.\n\n2. Verify the presence of spatial correlation from the empirical variogram of the residuals.\n\n3. Fit one or more regression models with spatial correlation and select the one that shows the best fit to the data.\n\n# Geostatistical models in R\n\nThe *gstat* package contains functions related to geostatistics. For this example, we will use the `oxford` dataset from this package, which contains measurements of physical and chemical properties for 126 soil samples from a site, along with their coordinates `XCOORD` and `YCOORD`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gstat)\n\ndata(oxford)\nstr(oxford)\n```\n\nSuppose that we want to model the magnesium concentration (`MG1`), represented as a function of the spatial position in the following graph.\n\n```{r}\nlibrary(ggplot2)\nggplot(oxford, aes(x = YCOORD, y = XCOORD, size = MG1)) +\n geom_point() +\n coord_fixed()\n```\n\nNote that the $x$ and $y$ axes have been inverted to save space. The `coord_fixed()` function of *ggplot2* ensures that the scale is the same on both axes, which is useful for representing spatial data.\n\nWe can immediately see that these measurements were taken on a 100 m grid. It seems that the magnesium concentration is spatially correlated, although it may be a correlation induced by another variable. In particular, we know that the concentration of magnesium is negatively related to the soil pH (`PH1`).\n\n```{r}\nggplot(oxford, aes(x = PH1, y = MG1)) +\n geom_point()\n```\n\nThe `variogram` function of *gstat* is used to estimate a variogram from empirical data. Here is the result obtained for the variable `MG1`.\n\n```{r}\nvar_mg <- variogram(MG1 ~ 1, locations = ~ XCOORD + YCOORD, data = oxford)\nvar_mg\n```\n\nThe formula `MG1 ~ 1` indicates that no linear predictor is included in this model, while the argument `locations` indicates which variables in the data frame correspond to the spatial coordinates.\n\nIn the resulting table, `gamma` is the value of the variogram for the distance class centered on `dist`, while `np` is the number of pairs of points in that class. Here, since the points are located on a grid, we obtain regular distance classes (e.g.: 100 m for neighboring points on the grid, 141 m for diagonal neighbors, etc.).\n\nHere, we limit ourselves to the estimation of isotropic variograms, i.e. the variogram depends only on the distance between the two points and not on the direction. Although we do not have time to see it today, it is possible with *gstat* to estimate the variogram separately in different directions.\n\nWe can illustrate the variogram with `plot`.\n\n```{r}\nplot(var_mg, col = \"black\")\n```\n\nIf we want to estimate the residual spatial correlation of `MG1` after including the effect of `PH1`, we can add that predictor to the formula.\n\n```{r}\nvar_mg <- variogram(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford)\nplot(var_mg, col = \"black\")\n```\n\nIncluding the effect of pH, the range of the spatial correlation seems to decrease, while the plateau is reached around 300 m. It even seems that the variogram decreases beyond 400 m. In general, we assume that the variance between two points does not decrease with distance, unless there is a periodic spatial pattern.\n\nThe function `fit.variogram` accepts as arguments a variogram estimated from the data, as well as a theoretical model described in a `vgm` function, and then estimates the parameters of that model according to the data. The fitting is done by the method of least squares.\n\nFor example, `vgm(\"Exp\")` means we want to fit an exponential model.\n\n```{r}\nvfit <- fit.variogram(var_mg, vgm(\"Exp\"))\nvfit\n```\n\nThere is no nugget effect, because `psill = 0` for the `Nug` (nugget) part of the model. The exponential part has a sill at 1951 and a range of 95 m.\n\nTo compare different models, a vector of model names can be given to `vgm`. In the following example, we include the exponential, gaussian (\"Gau\") and spherical (\"Sph\") models.\n\n```{r, warning = FALSE, message = FALSE}\nvfit <- fit.variogram(var_mg, vgm(c(\"Exp\", \"Gau\", \"Sph\")))\nvfit\n```\n\nThe function gives us the result of the model with the best fit (lowest sum of squared deviations), which here is the same exponential model.\n\nFinally, we can superimpose the theoretical model and the empirical variogram on the same graph.\n\n```{r}\nplot(var_mg, vfit, col = \"black\")\n```\n\n## Regression with spatial correlation\n\nWe have seen above that the *gstat* package allows us to estimate the variogram of the residuals of a linear model. In our example, the magnesium concentration was modeled as a function of pH, with spatially correlated residuals.\n\nAnother tool to fit this same type of model is the `gls` function of the *nlme* package, which is included with the installation of R.\n\nThis function applies the *generalized least squares* method to fit linear regression models when the residuals are not independent or when the residual variance is not the same for all observations. Since the estimates of the coefficients depend on the estimated correlations between the residuals and the residuals themselves depend on the coefficients, the model is fitted by an iterative algorithm:\n\n1. A classical linear regression model (without correlation) is fitted to obtain residuals.\n\n2. The spatial correlation model (variogram) is fitted with those residuals.\n\n3. The regression coefficients are re-estimated, now taking into account the correlations.\n\nSteps 2 and 3 are repeated until the estimates are stable at a desired precision.\n\nHere is the application of this method to the same model for the magnesium concentration in the `oxford` dataset. In the `correlation` argument of `gls`, we specify an exponential correlation model as a function of our spatial coordinates and we include a possible nugget effect.\n\nIn addition to the exponential correlation `corExp`, the `gls` function can also estimate a Gaussian (`corGaus`) or spherical (`corSpher`) model.\n\n```{r}\nlibrary(nlme)\ngls_mg <- gls(MG1 ~ PH1, oxford, \n correlation = corExp(form = ~ XCOORD + YCOORD, nugget = TRUE))\nsummary(gls_mg)\n```\n\nTo compare this result with the adjusted variogram above, the parameters given by `gls` must be transformed. The range has the same meaning in both cases and corresponds to 478 m for the result of `gls`. The global variance of the residuals is the square of `Residual standard error`. The nugget effect here (0.294) is expressed as a fraction of that variance. Finally, to obtain the partial sill of the exponential part, the nugget effect must be subtracted from the total variance.\n\nAfter performing these calculations, we can give these parameters to the `vgm` function of *gstat* to superimpose this variogram estimated by `gls` on our variogram of the residuals of the classical linear model.\n\n```{r}\ngls_range <- 478\ngls_var <- 53.823^2\ngls_nugget <- 0.294 * gls_var\ngls_psill <- gls_var - gls_nugget\n\ngls_vgm <- vgm(\"Exp\", psill = gls_psill, range = gls_range, nugget = gls_nugget)\n\nplot(var_mg, gls_vgm, col = \"black\", ylim = c(0, 4000))\n```\n\nDoes the model fit the data less well here? In fact, this empirical variogram represented by the points was obtained from the residuals of the linear model ignoring the spatial correlation, so it is a biased estimate of the actual spatial correlations. The method is still adequate to quickly check if spatial correlations are present. However, to simultaneously fit the regression coefficients and the spatial correlation parameters, the generalized least squares (GLS) approach is preferable and will produce more accurate estimates.\n\nFinally, note that the result of the `gls` model also gives the AIC, which we can use to compare the fit of different models (with different predictors or different forms of spatial correlation).\n\n## Exercise\n\nThe [bryo_belg.csv](data/bryo_belg.csv) dataset is adapted from the data of this study:\n\n> Neyens, T., Diggle, P.J., Faes, C., Beenaerts, N., Artois, T. et Giorgi, E. (2019) Mapping species richness using opportunistic samples: a case study on ground-floor bryophyte species richness in the Belgian province of Limburg. *Scientific Reports* 9, 19122. https://doi.org/10.1038/s41598-019-55593-x\n\nThis data frame shows the specific richness of ground bryophytes (*richness*) for different sampling points in the Belgian province of Limburg, with their position *(x, y)* in km, in addition to information on the proportion of forest (*forest*) and wetlands (*wetland*) in a 1 km\\^2\\$ cell containing the sampling point.\n\n```{r}\nbryo_belg <- read.csv(\"data/bryo_belg.csv\")\nhead(bryo_belg)\n```\n\nFor this exercise, we will use the square root of the specific richness as the response variable. The square root transformation often allows to homogenize the variance of the count data in order to apply a linear regression.\n\na) Fit a linear model of the transformed species richness to the proportion of forest and wetlands, without taking into account spatial correlations. What is the effect of the two predictors in this model?\n\nb) Calculate the empirical variogram of the model residuals in (a). Does there appear to be a spatial correlation between the points?\n\n*Note*: The `cutoff` argument to the `variogram` function specifies the maximum distance at which the variogram is calculated. You can manually adjust this value to get a good view of the sill.\n\nc) Re-fit the linear model in (a) with the `gls` function in the *nlme* package, trying different types of spatial correlations (exponential, Gaussian, spherical). Compare the models (including the one without spatial correlation) with the AIC.\n\nd) What is the effect of the proportion of forests and wetlands according to the model in (c)? Explain the differences between the conclusions of this model and the model in (a).\n\n# Kriging\n\nAs mentioned before, a common application of geostatistical models is to predict the value of the response variable at unsampled locations, a form of spatial interpolation called kriging (pronounced with a hard \"g\").\n\nThere are three basic types of kriging based on the assumptions made about the response variable:\n\n- Ordinary kriging: Stationary variable with an unknown mean.\n\n- Simple kriging: Stationary variable with a known mean.\n\n- Universal kriging: Variable with a trend given by a linear or non-linear model.\n\nFor all kriging methods, the predictions at a new point are a weighted mean of the values at known points. These weights are chosen so that kriging provides the best linear unbiased prediction of the response variable, if the model assumptions (in particular the variogram) are correct. That is, among all possible unbiased predictions, the weights are chosen to give the minimum mean square error. Kriging also provides an estimate of the uncertainty of each prediction.\n\nWhile we will not present the detailed kriging equations here, the weights depend on both the correlations (estimated by the variogram) between the sampled points and the new point, as well of the correlations between the sampled points themselves. In other words, sampled points near the new point are given more weight, but isolated sampled points are also given more weight, because sample points close to each other provide redundant information.\n\nKriging is an interpolation method, so the prediction at a sampled point will always be equal to the measured value (the measurement is supposed to have no error, just spatial variation). However, in the presence of a nugget effect, any small displacement from the sampled location will show variability according to the nugget.\n\nIn the example below, we generate a new dataset composed of randomly-generated (x, y) coordinates within the study area as well as randomly-generated pH values based on the `oxford` data. We then apply the function `krige` to predict the magnesium values at these new points. Note that we specify the variogram derived from the GLS results in the `model` argument to `krige`.\n\n```{r}\nset.seed(14)\nnew_points <- data.frame(\n XCOORD = runif(100, min(oxford$XCOORD), max(oxford$XCOORD)),\n YCOORD = runif(100, min(oxford$YCOORD), max(oxford$YCOORD)),\n PH1 = rnorm(100, mean(oxford$PH1), sd(oxford$PH1))\n)\n\npred <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm)\nhead(pred)\n```\n\nThe result of `krige` includes the new point coordinates, the prediction of the variable `var1.pred` along with its estimated variance `var1.var`. In the graph below, we show the mean MG1 predictions from kriging (triangles) along with the measurements (circles).\n\n```{r}\npred$MG1 <- pred$var1.pred\n\nggplot(oxford, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n geom_point(data = pred, shape = 17, size = 2) +\n coord_fixed()\n```\n\nThe estimated mean and variance from kriging can be used to simulate possible values of the variable at each new point, conditional on the sampled values. In the example below, we performed 4 conditional simulations by adding the argument `nsim = 4` to the same `krige` instruction.\n\n```{r}\nsim_mg <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm, nsim = 4)\nhead(sim_mg)\n```\n\n```{r, message = FALSE, warning = FALSE, fig.dim = c(10, 5)}\nlibrary(tidyr)\nsim_mg <- pivot_longer(sim_mg, cols = c(sim1, sim2, sim3, sim4), \n names_to = \"sim\", values_to = \"MG1\")\nggplot(sim_mg, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n coord_fixed() +\n facet_wrap(~ sim)\n```\n\n# Solutions\n\n```{r}\nbryo_lm <- lm(sqrt(richness) ~ forest + wetland, data = bryo_belg)\nsummary(bryo_lm)\n```\n\nThe proportion of forest has a significant positive effect and the proportion of wetlands has a significant negative effect on bryophyte richness.\n\n```{r}\nplot(variogram(sqrt(richness) ~ forest + wetland, locations = ~ x + y,\n data = bryo_belg, cutoff = 50), col = \"black\")\n```\n\nThe variogram is increasing from 0 to at least 40 km, so there appears to be spatial correlations in the model residuals.\n\n```{r}\nbryo_exp <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corExp(form = ~ x + y, nugget = TRUE))\nbryo_gaus <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corGaus(form = ~ x + y, nugget = TRUE))\nbryo_spher <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corSpher(form = ~ x + y, nugget = TRUE))\n```\n\n```{r}\nAIC(bryo_lm)\nAIC(bryo_exp)\nAIC(bryo_gaus)\nAIC(bryo_spher)\n```\n\nThe spherical model has the smallest AIC.\n\n```{r}\nsummary(bryo_spher)\n```\n\nBoth effects are less important in magnitude and the effect of wetlands is not significant anymore. As is the case for other types of non-independent residuals, the \"effective sample size\" here is less than the number of points, since points close to each other provide redundant information. Therefore, the relationship between predictors and response is less clear than given by the model assuming all these points were independent.\n\nNote that the results for all three `gls` models are quite similar, so the choice to include spatial correlations was more important than the exact shape assumed for the variogram.\n\n\n# Areal data {#areal-data}\n\nAreal data are variables measured for regions of space, defined by polygons. This type of data is more common in the social sciences, human geography and epidemiology, where data is often available at the scale of administrative divisions.\n\nThis type of data also appears frequently in natural resource management. For example, the following map shows the forest management units of the Ministère de la Forêt, de la Faune et des Parcs du Québec.\n\n![](images/cartes_unites.png)\n\nSuppose that a variable is available at the level of these management units. How can we model the spatial correlation between units that are spatially close together?\n\nOne option would be to apply the geostatistical methods seen before, for example by calculating the distance between the centers of the polygons.\n\nAnother option, which is more adapted for areal data, is to define a network where each region is connected to neighbouring regions by a link. It is then assumed that the variables are directly correlated between neighbouring regions only. (Note, however, that direct correlations between immediate neighbours also generate indirect correlations for a chain of neighbours).\n\nIn this type of model, the correlation is not necessarily the same from one link to another. In this case, each link in the network can be associated with a *weight* representing its importance for the spatial correlation. We represent these weights by a matrix $W$ where $w_{ij}$ is the weight of the link between regions $i$ and $j$. A region has no link with itself, so $w_{ii} = 0$.\n\nA simple choice for $W$ is to assign a weight equal to 1 if the regions are neighbours, otherwise 0 (binary weight).\n\nIn addition to land divisions represented by polygons, another example of areal data consists of a grid where the variable is calculated for each cell of the grid. In this case, a cell generally has 4 or 8 neighbouring cells, depending on whether diagonals are included or not.\n\n# Moran's I {#moran-i}\n\nBefore discussing spatial autocorrelation models, we present Moran's $I$ statistic, which allows us to test whether a significant correlation is present between neighbouring regions.\n\nMoran's $I$ is a spatial autocorrelation coefficient of $z$, weighted by the $w_{ij}$. It therefore takes values between -1 and 1.\n\n$$I = \\frac{N}{\\sum_i \\sum_j w_{ij}} \\frac{\\sum_i \\sum_j w_{ij} (z_i - \\bar{z}) (z_j - \\bar{z})}{\\sum_i (z_i - \\bar{z})^2}$$\n\nIn this equation, we recognize the expression of a correlation, which is the product of the deviations from the mean for two variables $z_i$ and $z_j$, divided by the product of their standard deviations (it is the same variable here, so we get the variance). The contribution of each pair $(i, j)$ is multiplied by its weight $w_{ij}$ and the term on the left (the number of regions $N$ divided by the sum of the weights) ensures that the result is bounded between -1 and 1.\n\nSince the distribution of $I$ is known in the absence of spatial autocorrelation, this statistic serves to test the null hypothesis that there is no spatial correlation between neighbouring regions.\n\nAlthough we will not see an example in this course, Moran's $I$ can also be applied to point data. In this case, we divide the pairs of points into distance classes and calculate $I$ for each distance class; the weight $w_{ij} = 1$ if the distance between $i$ and $j$ is in the desired distance class, otherwise 0.\n\n# Spatial autoregression models {#spatial-autoreg}\n\nLet us recall the formula for a linear regression with spatial dependence:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nwhere $z$ is the portion of the residual variance that is spatially correlated.\n\nThere are two main types of autoregressive models to represent the spatial dependence of $z$: conditional autoregression (CAR) and simultaneous autoregressive (SAR).\n\n## Conditional autoregressive (CAR) model\n\nIn the conditional autoregressive model, the value of $z_i$ for the region $i$ follows a normal distribution: its mean depends on the value $z_j$ of neighbouring regions, multiplied by the weight $w_{ij}$ and a correlation coefficient $\\rho$; its standard deviation $\\sigma_{z_i}$ may vary from one region to another.\n\n$$z_i \\sim \\text{N}\\left(\\sum_j \\rho w_{ij} z_j,\\sigma_{z_i} \\right)$$\n\nIn this model, if $w_{ij}$ is a binary matrix (0 for non-neighbours, 1 for neighbours), then $\\rho$ is the coefficient of partial correlation between neighbouring regions. This is similar to a first-order autoregressive model in the context of time series, where the autoregression coefficient indicates the partial correlation.\n\n## Simultaneous autoregressive (SAR) model\n\nIn the simultaneous autoregressive model, the value of $z_i$ is given directly by the sum of contributions from neighbouring values $z_j$, multiplied by $\\rho w_{ij}$, with an independent residual $\\nu_i$ of standard deviation $\\sigma_z$.\n\n$$z_i = \\sum_j \\rho w_{ij} z_j + \\nu_i$$\n\nAt first glance, this looks like a temporal autoregressive model. However, there is an important conceptual difference. For temporal models, the causal influence is directed in only one direction: $v(t-2)$ affects $v(t-1)$ which then affects $v(t)$. For a spatial model, each $z_j$ that affects $z_i$ depends in turn on $z_i$. Thus, to determine the joint distribution of $z$, a system of equations must be solved simultaneously (hence the name of the model).\n\nFor this reason, although this model resembles the formula of CAR model, the solutions of the two models differ and in the case of SAR, the coefficient $\\rho$ is not directly equal to the partial correlation due to each neighbouring region.\n\nFor more details on the mathematical aspects of these models, see the article by Ver Hoef et al. (2018) suggested in reference.\n\nFor the moment, we will consider SAR and CAR as two types of possible models to represent a spatial correlation on a network. We can always fit several models and compare them with the AIC to choose the best form of correlation or the best weight matrix.\n\nThe CAR and SAR models share an advantage over geostatistical models in terms of efficiency. In a geostatistical model, spatial correlations are defined between each pair of points, although they become negligible as distance increases. For a CAR or SAR model, only neighbouring regions contribute and most weights are equal to 0, making these models faster to fit than a geostatistical model when the data are massive.\n\n# Analysis of areal data in R {#analysis-areal}\n\nTo illustrate the analysis of areal data in R, we load the packages *sf* (to read geospatial data), *spdep* (to define spatial networks and calculate Moran's $I$) and *spatialreg* (for SAR and CAR models).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nlibrary(spdep)\nlibrary(spatialreg)\n```\n\nAs an example, we will use a dataset that presents some of the results of the 2018 provincial election in Quebec, with population characteristics of each riding. This data is included in a *shapefile* (.shp) file type, which we can read with the `read_sf` function of the *sf* package.\n\n```{r}\nelect2018 <- read_sf(\"data/elect2018.shp\")\nhead(elect2018)\n```\n\n*Note*: The dataset is actually composed of 4 files with the extensions .dbf, .prj, .shp and .shx, but it is sufficient to write the name of the .shp file in `read_sf`.\n\nThe columns of the dataset are, in order:\n\n- the name of the electoral riding (`circ`);\n- four characteristics of the population (`age_moy` = mean age, `pct_frn` = fraction of the population that speaks mainly French at home, `pct_prp` = fraction of households that own their home, `rev_med` = median income);\n- four columns showing the fraction of votes obtained by the main parties (CAQ, PQ, PLQ, QS);\n- a `geometry` column that contains the geometric object (multipolygon) corresponding to the riding.\n\nTo illustrate one of the variables on a map, we call the `plot` function with the name of the column in square brackets and quotation marks.\n\n```{r}\nplot(elect2018[\"rev_med\"])\n```\n\nIn this example, we want to model the fraction of votes obtained by the CAQ based on the characteristics of the population in each riding and taking into account the spatial correlations between neighbouring ridings.\n\n## Definition of the neighbourhood network\n\nThe `poly2nb` function of the *spdep* package defines a neighbourhood network from polygons. The result `vois` is a list of 125 elements where each element contains the indices of the neighbouring (bordering) polygons of a given polygon.\n\n```{r}\nvois <- poly2nb(elect2018)\nvois[[1]]\n```\n\nThus, the first riding (Abitibi-Est) has 6 neighbouring ridings, for which the names can be found as follows:\n\n```{r}\nelect2018$circ[vois[[1]]]\n```\n\nWe can illustrate this network by extracting the coordinates of the center of each district, creating a blank map with `plot(elect2018[\"geometry\"])`, then adding the network as an additional layer with `plot(vois, add = TRUE, coords = coords)`.\n\n```{r, message = FALSE, warning = FALSE}\ncoords <- st_centroid(elect2018) %>%\n st_coordinates()\nplot(elect2018[\"geometry\"])\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nWe can \"zoom\" on southern Québec by choosing the limits `xlim` and `ylim`.\n\n```{r}\nplot(elect2018[\"geometry\"], \n xlim = c(400000, 800000), ylim = c(100000, 500000))\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nWe still have to add weights to each network link with the `nb2listw` function. The style of weights \"B\" corresponds to binary weights, i.e. 1 for the presence of link and 0 for the absence of link between two ridings.\n\nOnce these weights are defined, we can verify with Moran's test whether there is a significant autocorrelation of votes obtained by the CAQ between neighbouring ridings.\n\n```{r}\npoids <- nb2listw(vois, style = \"B\")\n\nmoran.test(elect2018$propCAQ, poids)\n```\n\nThe value $I = 0.68$ is very significant judging by the $p$-value of the test.\n\nLet's verify if the spatial correlation persists after taking into account the four characteristics of the population, therefore by inspecting the residuals of a linear model including these four predictors.\n\n```{r}\nelect_lm <- lm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, data = elect2018)\nsummary(elect_lm)\nmoran.test(residuals(elect_lm), poids)\n```\n\nMoran's $I$ has decreased but remains significant, so some of the previous correlation was induced by these predictors, but there remains a spatial correlation due to other factors.\n\n## Spatial autoregression models\n\nFinally, we fit SAR and CAR models to these data with the `spautolm` (*spatial autoregressive linear model*) function of *spatialreg*. Here is the code for a SAR model including the effect of the same four predictors.\n\n```{r}\nelect_sar <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids)\nsummary(elect_sar)\n```\n\nThe value given by `Lambda` in the summary corresponds to the coefficient $\\rho$ in our description of the model. The likelihood-ratio test (`LR test`) confirms that this residual spatial correlation (after controlling for the effect of predictors) is significant.\n\nThe estimated effects for the predictors are similar to those of the linear model without spatial correlation. The effects of mean age, fraction of francophones and fraction of homeowners remain significant, although their magnitude has decreased somewhat.\n\nTo fit a CAR rather than SAR model, we must specify `family = \"CAR\"`.\n\n```{r}\nelect_car <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids, family = \"CAR\")\nsummary(elect_car)\n```\n\nFor a CAR model with binary weights, the value of `Lambda` (which we called $\\rho$) directly gives the partial correlation coefficient between neighbouring districts. Note that the AIC here is slightly higher than the SAR model, so the latter gave a better fit.\n\n## Exercise\n\nThe `rls_covid` dataset, in *shapefile* format, contains data on detected COVID-19 cases (`cas`), number of cases per 1000 people (`taux_1k`) and the population density (`dens_pop`) in each of Quebec's local health service networks (RLS) (Source: Data downloaded from the Institut national de santé publique du Québec as of January 17, 2021).\n\n```{r}\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nhead(rls_covid)\n```\n\nFit a linear model of the number of cases per 1000 as a function of population density (it is suggested to apply a logarithmic transform to the latter). Check whether the model residuals are correlated between bordering RLS with a Moran's test and then model the same data with a conditional autoregressive model.\n\n## Reference\n\nVer Hoef, J.M., Peterson, E.E., Hooten, M.B., Hanks, E.M. and Fortin, M.-J. (2018) Spatial autoregressive models for statistical inference from ecological data. *Ecological Monographs* 88: 36-59.\n\n```{r setup, include=FALSE}\nset.seed(82)\n```\n\n# GLMM with spatial Gaussian process {#glmm-spatial-gaussian}\n\n## Data\n\nThe `gambia` dataset found in the *geoR* package presents the results of a study of malaria prevalence among children of 65 villages in The Gambia. We will use a slightly transformed version of the data found in the file [gambia.csv](data/gambia.csv).\n\n```{r, warning = FALSE, message = FALSE}\nlibrary(geoR)\n\ngambia <- read.csv(\"data/gambia.csv\")\nhead(gambia)\n```\n\nHere are the fields in that dataset:\n\n- *id_village*: Identifier of the village.\n- *x* and *y*: Spatial coordinates of the village (in kilometers, based on UTM coordinates).\n- *pos*: Binary response, whether the child tested positive for malaria.\n- *age*: Age of the child in days.\n- *netuse*: Whether or not the child sleeps under a bed net.\n- *treated*: Whether or not the bed net is treated.\n- *green*: Remote sensing based measure of greenness of vegetation (measured at the village level).\n- *phc*: Presence or absence of a public health centre for the village.\n\nWe can count the number of positive cases and total children tested by village to map the fraction of positive cases (or prevalence, *prev*).\n\n```{r}\n# Create village-level dataset\ngambia_agg <- group_by(gambia, id_village, x, y, green, phc) %>%\n summarize(pos = sum(pos), total = n()) %>%\n mutate(prev = pos / total) %>%\n ungroup()\nhead(gambia_agg)\n```\n\n```{r, message = FALSE, warning = FALSE}\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nWe use the `gambia.borders` dataset from the *geoR* package to trace the country boundaries with `geom_path`. Since those boundaries are in meters, we divide by 1000 to get the same scale as our points. We also use `coord_fixed` to ensure a 1:1 aspect ratio between the axes and use the `viridis` color scale, which makes it easier to visualize a continuous variable compared with the default gradient scale in *ggplot2*.\n\nBased on this map, there seems to be spatial correlation in malaria prevalence, with the eastern cluster of villages showing more high prevalence values (yellow-green) and the middle cluster showing more low prevalence values (purple).\n\n## Non-spatial GLMM\n\nFor this first example, we will ignore the spatial aspect of the data and model the presence of malaria (*pos*) as a function of the use of a bed net (*netuse*) and the presence of a public health centre (*phc*). Since we have a binary response, we need to use a logistic regression model (a GLM). Since we have predictors at both the individual and village level, and we expect that children of the same village have more similar probabilities of having malaria even after accounting for those predictors, we need to add a random effect of the village. The result is a GLMM that we fit using the `glmer` function in the *lme4* package.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(lme4)\n\nmod_glmm <- glmer(pos ~ netuse + phc + (1 | id_village), \n data = gambia, family = binomial)\nsummary(mod_glmm)\n```\n\nAccording to these results, both *netuse* and *phc* result in a decrease of malaria prevalence, although the effect of *phc* is not significant at a threshold $\\alpha = 0.05$. The intercept (0.149) is the logit of the probability of malaria presence for a child with no bednet and no public health centre, but it is the mean intercept across all villages, and there is a lot of variation between villages, based on the random effect standard deviation of 0.90. We can get the estimated intercept for each village with the function `coef`:\n\n```{r}\nhead(coef(mod_glmm)$id_village)\n```\n\nSo for example, the intercept for village 1 is around 0.94, equivalent to a probability of 72%:\n\n```{r}\nplogis(0.937)\n```\n\nwhile the intercept in village 2 is equivalent to a probability of 52%:\n\n```{r}\nplogis(0.092)\n```\n\nThe [DHARMa package](https://cran.r-project.org/web/packages/DHARMa/vignettes/DHARMa.html) provides a general method for checking whether the residuals of a GLMM are distributed according to the specified model and whether there is any residual trend. The package works by simulating replicates of each observation according to the fitted model and then determining a \"standardized residual\", which is the relative position of the observed value with respect to the simulated values, e.g. 0 if the observation is smaller than all the simulations, 0.5 if it is in the middle, etc. If the model represents the data well, each value of the standardized residual between 0 and 1 should be equally likely, so the standardized residuals should produce a uniform distribution between 0 and 1.\n\nThe `simulateResiduals` function performs the calculation of the standardized residuals, then the `plot` function plots the diagnostic graphs with the results of certain tests.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(DHARMa)\nres_glmm <- simulateResiduals(mod_glmm)\nplot(res_glmm)\n```\n\nThe graph on the left is a quantile-quantile plot of standardized residuals. The results of three statistical tests also also shown: a Kolmogorov-Smirnov (*KS*) test which checks whether there is a deviation from the theoretical distribution, a dispersion test that checks whether there is underdispersion or overdispersion, and an outlier test based on the number of residuals that are more extreme than all the simulations. Here, we get a significant result for the outliers, though the message indicates that this result might have an inflated type I error rate in this case.\n\nOn the right, we generally get a graph of standardized residuals (in *y*) as a function of the rank of the predicted values, in order to check for any leftover trend in the residual. Here, the predictions are binned by quartile, so it might be better to instead aggregate the predictions and residuals by village, which we can do with the `recalculateResiduals` function.\n\n```{r}\nplot(recalculateResiduals(res_glmm, group = gambia$id_village))\n```\n\nThe plot to the right now shows individual points, along with a quantile regression for the 1st quartile, the median and the 3rd quartile. In theory, these three curves should be horizontal straight lines (no leftover trend in the residuals vs. predictions). The curve for the 3rd quartile (in red) is significantly different from a horizontal line, which could indicate some systematic effect that is missing from the model.\n\n## Spatial GLMM with spaMM\n\nThe *spaMM* (spatial mixed models) package is a relatively new R package that can perform approximate maximum likelihood estimation of parameters for GLMM with spatial dependence, modelled either as a Gaussian process or with a CAR (we will see the latter in the last section). The package implements different algorithms, but there is a single `fitme` function that chooses the appropriate algorithm for each model type. For example, here is the same (non-spatial) model as above fit with *spaMM*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spaMM)\n\nmod_spamm_glmm <- fitme(pos ~ netuse + phc + (1 | id_village),\n data = gambia, family = binomial)\nsummary(mod_spamm_glmm)\n```\n\nNote that the estimates of the fixed effects as well as the variance of random effects are nearly identical to those obtained by `glmer` above.\n\nWe can now use *spaMM* to fit the same model with the addition of spatial correlations between villages. In the formula of the model, this is represented as a random effect `Matern(1 | x + y)`, which means that the intercepts are spatially correlated between villages following a Matérn correlation function of coordinates (*x, y*). The Matérn function is a flexible function for spatial correlation that includes a shape parameter $\\nu$ (`nu`), so that when $\\nu = 0.5$ it is equivalent to the exponential correlation but as $\\nu$ grows to large values, it approaches a Gaussian correlation. We could let the function estimate $\\nu$, but here we will fix it to 0.5 with the `fixed` argument of `fitme`.\n\n```{r}\nmod_spamm <- fitme(pos ~ netuse + phc + Matern(1 | x + y) + (1 | id_village),\n data = gambia, family = binomial, fixed = list(nu = 0.5))\nsummary(mod_spamm)\n```\n\nLet's first check the random effects of the model. The spatial correlation function has a parameter `rho` equal to 0.0513. This parameter in *spaMM* is the inverse of the range, so here the range of exponential correlation is 1/0.0513 or around 19.5 km. There are now two variance prameters, the one identified as `x + y` is the long-range variance (i.e. sill) for the exponential correlation model whereas the one identified as `id_village` shows the non-spatially correlated portion of the variation between villages.\n\nIn fact, while we left the random effects `(1 | id_village)` in the formula to represent the non-spatial portion of variation between villages, we could also represent this with a nugget effect in the geostatistical model. In both cases, it would represent the idea that even two villages very close to each other would have different baseline prevalences in the model.\n\nBy default, the `Matern` function has no nugget effect, but we can add one by specifying a non-zero `Nugget` in the initial parameter list `init`.\n\n```{r}\nmod_spamm2 <- fitme(pos ~ netuse + phc + Matern(1 | x + y),\n data = gambia, family = binomial, fixed = list(nu = 0.5),\n init = list(Nugget = 0.1))\nsummary(mod_spamm2)\n```\n\nAs you can see, all estimates are the same, except that the variance of the spatial portion (sill) is now 0.84 and the nugget is equal to a fraction 0.235 of that sill, so a variance of 0.197, which is the same as the `id_village` random effect in the version above. Thus the two formulations are equivalent.\n\nNow, recall the coefficients we obtained for the non-spatial GLMM:\n\n```{r}\nsummary(mod_glmm)$coefficients\n```\n\nIn the spatial version, both fixed effects have moved slightly towards zero, but the standard error of the effect of `phc` has decreased. It is interesting that the inclusion of spatial dependence has allowed us to estimate more precisely the effect of having a public health centre in the village. This would not always be the case: for a predictor that is also strongly correlated in space, spatial correlation in the response makes it harder to estimate the effect of this predictor, since it is confounded with the spatial effect. However, for a predictor that is not correlated in space, including the spatial effect reduces the residual (non-spatial) variance and may thus increase the precision of the predictor's effect.\n\nThe *spaMM* package is also compatible with *DHARMa* for residual diagnostics. (You can in fact ignore the warning that it is not in the class of supported models, this is due to using the `fitme` function rather than a specific algorithm function in *spaMM*.)\n\n```{r}\nres_spamm <- simulateResiduals(mod_spamm2)\nplot(res_spamm)\nplot(recalculateResiduals(res_spamm, group = gambia$id_village))\n```\n\nFinally, while we will show how to make and visualize spatial predictions below, we can produce a quick map of the estimated spatial effects in a *spaMM* model with the `filled.mapMM` function.\n\n```{r}\nfilled.mapMM(mod_spamm2)\n```\n\n## Gaussian process models vs. smoothing splines\n\nIf you are familiar with generalized additive models (GAM), you might think that the spatial variation in malaria prevalence (as shown in the map above) could be represented by a 2D smoothing spline (as a function of $x$ and $y$) within a GAM.\n\nThe code below fits the GAM equivalent of our Gaussian process GLMM above with the `gam` function in the *mgcv* package. The spatial effect is represented by the 2D spline `s(x, y)` whereas the non-spatial random effect of village is represented by `s(id_village, bs = \"re\")`, which is the same as `(1 | id_village)` in the previous models. Note that for the `gam` function, categorical variables must be explicitly converted to factors.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(mgcv)\ngambia$id_village <- as.factor(gambia$id_village)\nmod_gam <- gam(pos ~ netuse + phc + s(id_village, bs = \"re\") + s(x, y), \n data = gambia, family = binomial)\n```\n\nTo visualize the 2D spline, we will use the [*gratia* package](https://fromthebottomoftheheap.net/2018/10/23/introducing-gratia/).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gratia)\ndraw(mod_gam)\n```\n\nNote that the plot of the spline `s(x, y)` (top right) does not extend too far from the locations of the data (other areas are blank). In this graph, we can also see that the village random effects follow the expected Gaussian distribution (top left).\n\nNext, we will use both the spatial GLMM from the previous section and this GAMM to predict the mean prevalence on a spatial grid of points contained in the file [gambia_pred.csv](data/gambia_pred.csv). The graph below adds those prediction points (in black) on the previous map of the data points.\n\n```{r, message = FALSE, warning = FALSE}\ngambia_pred <- read.csv(\"data/gambia_pred.csv\")\n\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(data = gambia_pred) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nTo make predictions from the GAMM model at those points, the code below goes through the following steps:\n\n- All predictors in the model must be in the prediction data frame, so we add constant values of *netuse* and *phc* (both equal to 1) for all points. Thus, we will make predictions of malaria prevalence in the case where a net is used and a public health centre is present. We also add a constant *id_village*, although it will not be used in predictions (see below).\n\n- We call the `predict` function on the output of `gam` to produce predictions at the new data points (argument `newdata`), including standard errors (`se.fit = TRUE`) and excluding the village random effects, so the prediction is made for an \"average village\". The resulting object `gam_pred` will have columns `fit` (mean prediction) and `se.fit` (standard error). Those predictions and standard errors are on the link (logit) scale.\n\n- We add the original prediction data frame to `gam_pred` with `cbind`.\n\n- We add columns for the mean prediction and 50% confidence interval boundaries (mean $\\pm$ 0.674 standard error), converted from the logit scale to the probability scale with `plogis`. We choose a 50% interval since a 95% interval may be too wide here to contrast the different predictions on the map at the end of this section.\n\n```{r}\ngambia_pred <- mutate(gambia_pred, netuse = 1, phc = 1, id_village = 1)\n\ngam_pred <- predict(mod_gam, newdata = gambia_pred, se.fit = TRUE, \n exclude = \"s(id_village)\")\ngam_pred <- cbind(gambia_pred, as.data.frame(gam_pred))\ngam_pred <- mutate(gam_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit), # 50% CI\n hi = plogis(fit + 0.674 * se.fit))\n```\n\n*Note*: The reason we do not make predictions directly on the probability (response) scale is that the normal formula for confidence intervals applies more accurately on the logit scale. Adding a certain number of standard errors around the mean on the probability scale would lead to less accurate intervals and maybe even confidence intervals outside the possible range (0, 1) for a probability.\n\nWe apply the same strategy to make predictions from the *spaMM* spatial GLMM model. There are a few differences in the `predict` method compared with the GAMM case.\n\n- The argument `binding = \"fit\"` means that mean predictions (`fit` column) will be attached to the prediction dataset and returned as `spamm_pred`.\n\n- The `variances = list(linPred = TRUE)` tells `predict` to calculate the variance of the linear predictor (so the square of the standard error). However, it appears as an attribute `predVar` in the output data frame rather than a `se.fit` column, so we move it to a column on the next line.\n\n```{r}\nspamm_pred <- predict(mod_spamm, newdata = gambia_pred, type = \"link\",\n binding = \"fit\", variances = list(linPred = TRUE))\nspamm_pred$se.fit <- sqrt(attr(spamm_pred, \"predVar\"))\nspamm_pred <- mutate(spamm_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit),\n hi = plogis(fit + 0.674 * se.fit))\n```\n\nFinally, we combine both sets of predictions as different rows of a `pred_all` dataset with `bind_rows`. The name of the dataset each prediction originates from (`gam` or `spamm`) will appear in the \"model\" column (argument `.id`). To simplify production of the next plot, we then use `pivot_longer` in the *tidyr* package to change the three columns \"pred\", \"lo\" and \"hi\" to two columns, \"stat\" and \"value\" (`pred_tall` has thus three rows for every row in `pred_all`).\n\n```{r}\npred_all <- bind_rows(gam = gam_pred, spamm = spamm_pred, .id = \"model\")\n\nlibrary(tidyr)\npred_tall <- pivot_longer(pred_all, c(pred, lo, hi), names_to = \"stat\",\n values_to = \"value\")\n```\n\nHaving done these steps, we can finally look at the prediction maps (mean, lower and upper bounds of the 50% confidence interval) with `ggplot`. The original data points are shown in red.\n\n```{r}\nggplot(pred_tall, aes(x = x, y = y)) +\n geom_point(aes(color = value)) +\n geom_point(data = gambia_agg, color = \"red\", size = 0) +\n coord_fixed() +\n facet_grid(stat~model) +\n scale_color_viridis_c() +\n theme_minimal()\n```\n\nWhile both models agree that there is a higher prevalence near the eastern cluster of villages, the GAMM also estimates a higher prevalence at a few points (western edge and around the center) where there is no data. This is an artifact of the shape of the spline fit around the data points, since a spline is meant to fit a global, although nonlinear, trend. In contrast, the geostatistical model represents the spatial effect as local correlations and reverts to the overall mean prevalence when far from any data points, which is a safer assumption. This is one reason to choose a geostatistical / Gaussian process model in this case.\n\n## Bayesian methods for GLMMs with Gaussian processes\n\nBayesian models provide a flexible framework to express models with complex dependence structure among the data, including spatial dependence. However, fitting a Gaussian process model with a fully Bayesian approach can be slow, due the need to compute a spatial covariance matrix between all point pairs at each iteration.\n\nThe INLA (integrated nested Laplace approximation) method performs an approximate calculation of the Bayesian posterior distribution, which makes it suitable for spatial regression problems. We do not cover it in this course, but I recommend the textbook by Paula Moraga (in the references section below) that provides worked examples of using INLA for various geostatistical and areal data models, in the context of epidemiology, including models with both space and time dependence. The book presents the same Gambia malaria data as an example of a geostatistical dataset, which inspired its use in this course.\n\n# GLMM with spatial autoregression {#glmm-spatial-autoreg}\n\nWe return to the last example of the previous part, where we modelled the rate of COVID-19 cases (cases / 1000) for administrative health network divisions (RLS) in Quebec as a function of their population density. The rate is given by the \"taux_1k\" column in the `rls_covid` shapefile.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nrls_covid <- rls_covid[!is.na(rls_covid$dens_pop), ]\nplot(rls_covid[\"taux_1k\"])\n```\n\nPreviously, we modelled the logarithm of this rate as a linear function of the logarithm of population density, with the residual variance correlated among neighbouring units via a CAR (conditional autoregression) structure, as shown in the code below.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spdep)\nlibrary(spatialreg)\n\nrls_nb <- poly2nb(rls_covid)\nrls_w <- nb2listw(rls_nb, style = \"B\")\n\ncar_lm <- spautolm(log(taux_1k) ~ log(dens_pop), data = rls_covid,\n listw = rls_w, family = \"CAR\")\nsummary(car_lm)\n```\n\nAs a reminder, the `poly2nb` function in the *spdep* package creates a list of neighbours based on bordering polygons in a shapefile, then the `nb2listw` converts it to a list of weights, here binary weights (`style = \"B\"`) so that each bordering region receives the same weight of 1 in the autoregressive model.\n\nInstead of using the rates, it would be possible to model the cases directly (column \"cas\" in the dataset) with a Poisson regression, which is appropriate for count data. To account for the fact that if the risk per person were equal, cases would be proportional to population, we can add the unit's population `pop` as an *offset* in the Poisson regression. Therefore, the model would look like: `cas ~ log(dens_pop) + offset(log(pop))`. Note that since the Poisson regression uses a logarithmic link, that model with `log(pop)` as an offset assumes that `log(cas / pop)` (so the log rate) is proportional to `log(dens_pop)`, just like the linear model above, but it has the advantage of modelling the stochasticity of the raw data (the number of cases) directly with a Poisson distribution.\n\nWe do not have the population in this data, but we can estimate it from the cases and the rate (cases / 1000) as follows:\n\n```{r}\nrls_covid$pop <- rls_covid$cas / rls_covid$taux_1k * 1000\n```\n\nTo define a CAR model in *spaMM*, we need a weights matrix rather than a list of weights as in the *spatialreg* package. Fortunately, the *spdep* package also includes a function `nb2mat` to convert the neighbours list to a matrix of weights, here again using binary weights. To avoid a warning, we specify the row and column names of that matrix to be equal to the IDs associated with each unit (`RLS_code`). Then, we add a term `adjacency(1 | RLS_code)` to the model to specify that the residual variation between different groups defined by `RLS_code` is spatially correlated with a CAR structure (here, each group has only one observation since we have one data point by RLS unit).\n\n```{r}\nlibrary(spaMM)\n\nrls_mat <- nb2mat(rls_nb, style = \"B\")\nrownames(rls_mat) <- rls_covid$RLS_code\ncolnames(rls_mat) <- rls_covid$RLS_code\n\nrls_spamm <- fitme(cas ~ log(dens_pop) + offset(log(pop)) + adjacency(1 | RLS_code),\n data = rls_covid, adjMatrix = rls_mat, family = poisson)\nsummary(rls_spamm)\n```\n\nNote that the spatial correlation coefficient `rho` (0.158) is similar to the equivalent quantity in the `spautolm` model above, where it was called `Lambda`. The effect of `log(dens_pop)` is also approximately 0.2 in both models.\n\n## Reference\n\nMoraga, Paula (2019) Geospatial Health Data: Modeling and Visualization with R-INLA and Shiny. Chapman & Hall/CRC Biostatistics Series. Available online at .\n\n------------------------------------------------------------------------\n\n# Statistiques spatiales en écologie {#statistiques-spatiales-en-écologie}\n\nBIOS² a organisé une session de formation en ligne sur l'analyse statistique des données spatiales en écologie, animée par le Pr. Philippe Marchand (UQAT). Cette formation de 12 heures s'est déroulée en 4 sessions : 12, 14, 19 & 21 janvier (2021) de 13h00 à 16h00 HNE.\n\nLe contenu comprenait trois types d'analyses statistiques spatiales et leurs applications en écologie : (1) l'analyse des patrons de points qui permet d'étudier la distribution d'individus ou d'événements dans l'espace; (2) les modèles géostatistiques qui représentent la corrélation spatiale de variables échantillonnées à des points géoréférencés; et (3) les modèles de données aréales, qui s'appliquent aux mesures prises sur des régions de l'espace et qui représentent les liens spatiaux par le biais de réseaux de voisinage. La formation comprenait également des exercices pratiques utilisant l'environnement de programmation statistique R.\n\n[Philippe Marchand](https://github.com/pmarchand1) est professeur d'écologie et de biostatistique à l'Institut de recherche sur les forêts, Université du Québec en Abitibi-Témiscamingue (UQAT) et membre académique de BIOS². Ses travaux de recherche portent sur la modélisation de processus qui influencent la distribution spatiale des populations, incluant: la dispersion des graines et l'établissement des semis, le mouvement des animaux, et la propagation des épidémies forestières.\n\n**Si vous souhaitez consulter le matériel pédagogique et suivre les exercices à votre propre rythme, vous pouvez y accéder par [ce lien](https://bios2.github.io/Marchand.html#category:FR). Une connaissance de base des modèles de régression linéaire et une expérience de l'ajustement de ces modèles dans R sont recommandées. Le repositoire original se trouve [ici](https://github.com/pmarchand1/BIOS2-spatial-stats).**\n\n## Plan du cours\n\n| Jour | Sujets | \n|-----------------|:--------------------------|\n| 1 | • [Introduction aux statistiques spatiales](#introduction-fr)
• [Analyse des patrons de points](#point-pattern-fr)
|\n| 2 | • [Corrélation spatiale d'une variable](#spatial-correlation-fr)
• [Modèles géostatistiques](#geostat-models-fr) | \n| 3 | • [Données aréales](#areal-data-fr)
• [Indice de Moran](#moran-i-fr)
• [Modèles d'autorégression spatiale](#spatial-autoreg-fr)
• [Analyse des données aréales dans R](#analysis-areal-fr) |\n| 4 | • [GLMM avec processus spatial gaussien](#glmm-spatial-gaussian-fr)
• [GLMM avec autorégression spatiale](#glmm-spatial-autoreg-fr)| \n\n# Introduction aux statistiques spatiales {#introduction-fr}\n\n## Types d'analyses spatiales\n\nDans le cadre de cette formation, nous discuterons de trois types d'analyses spatiales: l'analyse des patrons de points, les modèles géostatistiques et les modèles de données aréales.\n\nDans l'**analyse des patrons de points**, nous avons des données ponctuelles représentant la position d'individus ou d'événements dans une région d'étude et nous supposons que tous les individus ou événements ont été recensés dans cette région. Cette analyse s'intéresse à la distribution des positions des points eux-mêmes. Voici quelques questions typiques de l'analyse des patrons de points:\n\n- Les points sont-ils disposés aléatoirement ou agglomérés?\n\n- Deux types de points sont-ils disposés indépendamment?\n\nLes **modèles géostatistiques** visent à représenter la distribution spatiale de variables continues qui sont mesurés à certains points d'échantillonnage. Ils supposent que les mesures de ces variables à différents points sont corrélées en fonction de la distance entre ces points. Parmi les applications des modèles géostatistiques, notons le lissage des données spatiales (ex.: produire une carte d'une variable sur l'ensemble d'une région en fonction des mesures ponctuelles) et la prédiction de ces variables pour des points non-échantillonnés.\n\nLes **données aréales** sont des mesures prises non pas à des points, mais pour des régions de l'espace représentées par des polygones (ex.: divisions du territoire, cellules d'une grille). Les modèles représentant ces types de données définissent un réseau de voisinage reliant les régions et incluent une corrélation spatiale entre régions voisines. \n\n## Stationnarité et isotropie\n\nPlusieurs analyses spatiales supposent que les variables sont **stationnaires** dans l'espace. Comme pour la stationnarité dans le domaine temporel, cette propriété signifie que les statistiques sommaires (moyenne, variance et corrélations entre mesures d'une variable) ne varient pas avec une translation dans l'espace. Par exemple, la corrélation spatiale entre deux points peut dépendre de la distance les séparant, mais pas de leur position absolue.\n\nEn particulier, il ne peut pas y avoir de tendance à grande échelle (souvent appelée *gradient* dans un contexte spatial), ou bien cette tendance doit être prise en compte afin de modéliser la corrélation spatiale des résidus.\n\nDans le cas de l'analyse des patrons de points, la stationnarité (aussi appelée homogénéité dans ce contexte) signifie que la densité des points ne suit pas de tendance à grande échelle.\n\nDans un modèle statistique **isotropique**, les corrélations spatiales entre les mesures à deux points dépendent seulement de la distance entre ces points, pas de la direction. Dans ce cas, les statistiques sommaires ne varient pas si on effectue une rotation dans l'espace.\n\n## Données géoréférencées\n\nLes études environnementales utilisent de plus en plus de données provenant de sources de données géospatiales, c'est-à-dire des variables mesurées sur une grande partie du globe (ex.: climat, télédétection). Le traitement de ces données requiert des concepts liés aux systèmes d'information géographique (SIG), qui ne sont pas couverts dans cet atelier, alors que nous nous concentrons sur les aspects statistiques de données variant dans l'espace.\n\nL'utilisation de données géospatiales ne signifie pas nécessairement qu'il faut avoir recours à des statistiques spatiales. Par exemple, il est courant d'extraire les valeurs de ces variables géographiques à des points d'étude pour expliquer une réponse biologique observée sur le terrain. Dans ce cas, l'utilisation de statistiques spatiales est seulement nécessaire en présence d'une corrélation spatiale dans les résidus, après avoir tenu compte de l'effet des prédicteurs.\n\n\n# Analyse des patrons de points {#point-pattern-fr}\n\n## Patron de points et processus ponctuel\n\nUn patron de points (*point pattern*) décrit la position spatiale (le plus souvent en 2D) d'individus ou d'événements, représentés par des points, dans une aire d'étude donnée, souvent appelée la *fenêtre* d'observation. \n\nOn suppose que chaque point a une étendue spatiale négligeable par rapport aux distances entre les points. Des méthodes plus complexes existent pour traiter des patrons spatiaux d'objets qui ont une largeur non-néligeable, mais ce sujet dépasse la portée de cet atelier.\n\nUn processus ponctuel (*point process*) est un modèle statistique qui peut être utilisé pour simuler des patrons de points ou expliquer un patron de points observé.\n\n## Structure spatiale totalement aléatoire\n\nUne structure spatiale totalement aléatoire (*complete spatial randomness*) est un des patrons les plus simples, qui sert de modèle nul pour évaluer les caractéristiques de patrons de points réels. Dans ce patron, la présence d'un point à une position donnée est indépendante de la présence de points dans un voisinage. \n\nLe processus créant ce patron est un processus de Poisson homogène. Selon ce modèle, le nombre de points dans toute région de superficie $A$ suit une distribution de Poisson: $N(A) \\sim \\text{Pois}(\\lambda A)$, où $\\lambda$ est l'*intensité* du processus (i.e. la densité de points). $N$ est indépendant entre deux régions disjointes, peu importe comment ces régions sont définies.\n\nDans le graphique ci-dessous, seul le patron à droite est totalement aléatoire. Le patron à gauche montre une agrégation des points (probabilité plus grande d'observer un point si on est à proximité d'un autre point), tandis que le patron du centre montre une répulsion (faible probabilité d'observer un point très près d'un autre).\n\n```{r, include = FALSE}\nlibrary(spatstat)\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\nset.seed(82)\ncsrp <- rpoispp(lambda = 100)\naggp <- rMatClust(20, 0.1, 5)\nevenp <- rMaternII(150, 0.05)\npar(mfrow = c(1, 3))\nplot(aggp, main = \"Agrégation\", pch = 19)\nplot(evenp, main = \"Répulsion\", pch = 19)\nplot(csrp, main = \"Aléatoire\", pch = 19)\n```\n\n## Analyse exploratoire ou inférentielle pour un patron de points\n\nPlusieurs statistiques sommaires sont utilisées pour décrire les caractéristiques un patron de points. La plus simple est l'**intensité** $\\lambda$, qui comme mentionné plus haut représente la densité de points par unité de surface. Si le patron de points est hétérogène, l'intensité n'est pas constante, mais dépend de la position: $\\lambda(x, y)$.\n\nPar rapport à l'intensité qui est une statistique dite de premier ordre, les statistiques de second ordre décrivent comment la probabilité de présence d'un point dans une région dépend de la présence d'autres points. L'indice $K$ de Ripley présenté dans la prochaine section est un exemple de statistique sommaire de second ordre.\n\nLes inférences statistiques réalisées sur des patrons de points consistent habituellement à tester l'hypothèse que le patron de points correspond à un modèle nul donné, par exemple une structure spatiale totalement aléatoire, ou un modèle nul plus complexe. Même pour les modèles nuls les plus simples, nous connaissons rarement la distribution théorique pour une statistique sommaire du patron de points sous le modèle nul. Les tests d'hypothèses sur les patrons de points sont donc réalisés par simulation: on simule un grand nombre de patrons de points à partir du modèle nul et on compare la distribution des statistiques sommaires qui nous intéressent pour ces simulations à la valeur des statistiques pour le patron de points observé.\n\n## Indice $K$ de Ripley\n\nL'indice de Ripley $K(r)$ est défini comme le nombre moyen de points se trouvant dans un cercle de rayon $r$ donné autour d'un point du patron, normalisé par l'intensité $\\lambda$. \n\nPour un patron totalement aléatoire, le nombre moyen de points dans un cercle de rayon $r$ est $\\lambda \\pi r^2$, donc en théorie $K(r) = \\pi r^2$ pour ce modèle nul. Une valeur de $K(r)$ supérieure signifie qu'il y a agrégation des points à l'échelle $r$, tandis qu'une valeur inférieure signifie qu'il y a une répulsion.\n\nEn pratique, $K(r)$ est estimé pour un patron de points donné par l'équation:\n\n$$ K(r) = \\frac{A}{n(n-1)} \\sum_i \\sum_{j > i} I \\left( d_{ij} \\le r \\right) w_{ij}$$\n\noù $A$ est l'aire de la fenêtre d'observation et $n$ est le nombre de points du patron, donc $n(n-1)$ est le nombre de paires de points distinctes. On fait la somme pour toutes les paires de points de la fonction indicatrice $I$, qui prend une valeur de 1 si la distance entre les points $i$ et $j$ est inférieure ou égale à $r$. Finalement, le terme $w_{ij}$ permet de donner un poids supplémentaire à certaines paires de points pour tenir compte des effets de bordure, tel que discuté dans la section suivante.\n\nPar exemple, les graphiques ci-dessous présentent la fonction estimée $K(r)$ pour les patrons illustrés ci-dessus, pour des valeurs de $r$ allant jusqu'à 1/4 de la largeur de la fenêtre. La courbe pointillée rouge indique la valeur théorique pour une structure spatiale totalement aléatoire et la zone grise est une \"enveloppe\" produite par 99 simulations de ce modèle nul. Le patron agrégé montre un excès de voisins jusqu'à $r = 0.25$ et le patron avec répulsion montre un déficit significatif de voisins pour les petites valeurs de $r$. \n\n```{r, include = FALSE}\nkagg <- envelope(aggp, Kest, correction = \"iso\") \nkeven <- envelope(evenp, Kest, correction = \"iso\")\nkcsr <- envelope(csrp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE, fig.dim = c(9, 3)}\npar(mfrow = c(1, 3))\nplot(kagg, main = \"Agrégation\", legend = FALSE)\nplot(keven, main = \"Répulsion\", legend = FALSE)\nplot(kcsr, main = \"Aléatoire\", legend = FALSE)\n```\n\nOutre le $K$, il existe d'autres statistiques pour décrire les propriétés de second ordre du patron, par exemple la distance moyenne entre un point et ses $N$ plus proches voisins. Vous pouvez consulter le manuel de Wiegand et Moloney (2013) suggéré en référence pour en apprendre plus sur différentes statistiques sommaires des patrons de points.\n\n## Effets de bordure\n\nDans le contexte de l'analyse de patrons de points, l'effet de bordure (\"edge effect\") est dû au fait que nous avons une connaissance incomplète du voisinage des points près du bord de la fenêtre d'observation, ce qui peut induire un biais dans le calcul des statistiques comme le $K$ de Ripley. \n\nDifférentes méthodes ont été développées pour corriger le biais dû aux effets de bordure. Selon la méthode de Ripley, la contribution d'un voisin $j$ situé à une distance $r$ d'un point $i$ reçoit un poids $w_{ij} = 1/\\phi_i(r)$, où $\\phi_i(r)$ est la fraction du cercle de rayon $r$ autour de $i$ contenu dans la fenêtre d'observation. Par exemple, si 2/3 du cercle se trouve dans la fenêtre, ce voisin compte pour 3/2 voisins dans le calcul d'une statistique comme $K$.\n\n![](images/ripley_edge.png)\n\nLa méthode de Ripley est une des plus simples pour corriger les effets de bordure, mais n'est pas nécessairement la plus efficace; notamment, les poids plus grands donnés à certaines paires de points tend à accroître la variance du calcul de la statistique. D'autres méthodes de correction sont présentées dans les manuels spécialisés, comme celui de Wiegand et Moloney (2013) en référence.\n\n## Exemple\n\nPour cet exemple, nous utilisons le jeu de données [semis_xy.csv](data/semis_xy.csv), qui représente les coordonnées $(x, y)$ de semis de deux espèces (*sp*, B = bouleau et P = peuplier) dans une placette de 15 x 15 m.\n\n```{r}\nsemis <- read.csv(\"data/semis_xy.csv\")\nhead(semis)\n```\n\nLe package *spatstat* permet d'effectuer des analyses de patrons de point dans R. La première étape consiste à transformer notre tableau de données en objet `ppp` (patron de points) avec la fonction du même nom. Dans cette fonction, nous spécifions quelles colonnes contiennent les coordonnées *x* et *y* ainsi que les marques (`marks`), qui seront ici les codes d'espèce. Il faut aussi spécifier une fenêtre d'observation (`window`) à l'aide de la fonction `owin`, à laquelle nous indiquons les limites de la placette en *x* et *y*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spatstat)\n\nsemis <- ppp(x = semis$x, y = semis$y, marks = as.factor(semis$sp),\n window = owin(xrange = c(0, 15), yrange = c(0, 15)))\nsemis\n```\n\nLes marques peuvent être numériques ou catégorielles. Notez que pour des marques catégorielles comme c'est le cas ici, il faut convertir explicitement la variable en facteur.\n\nLa fonction `plot` appliquée à un patron de points montre un diagramme du patron.\n\n```{r}\nplot(semis)\n```\n\nLa fonction `intensity` calcule la densité des points de chaque espèce par unité de surface, ici en $m^2$.\n\n```{r}\nintensity(semis)\n```\n\nPour analyser d'abord séparément la distribution de chaque espèce, nous séparons le patron avec `split`. Puisque le patron contient des marques catégorielles, la séparation se fait automatiquement en fonction de la valeur des marques. Le résultat est une liste de deux patrons de points.\n\n```{r}\nsemis_split <- split(semis)\nplot(semis_split)\n```\n\nLa fonction `Kest` calcule le $K$ de Ripley pour une série de distances allant (par défaut) jusqu'à 1/4 de la largeur de la fenêtre. Ici, nous l'appliquons au premier patron (bouleau) en choisissant `semis_split[[1]]`. Notez que les doubles crochets sont nécessaires pour choisir un élément d'une liste dans R.\n\nL'argument `correction = \"iso\"` indique d'appliquer la méthode de Ripley pour corriger les effets de bordure.\n\n```{r}\nk <- Kest(semis_split[[1]], correction = \"iso\")\nplot(k)\n```\n\nSelon ce graphique, il semble y avoir une excès de voisins à partir d'un rayon de 1 m. Pour vérifier s'il s'agit d'un écart significatif, nous produisons une enveloppe de simulation avec la fonction `envelope`. Le permier argument d'`envelope` est un patron de point auquel les simulations seront comparées, le deuxième une fonction à calculer (ici, `Kest`) pour chaque patron simulé, puis on y ajoute les arguments de la fonction `Kest` (ici, seulement `correction`).\n\n```{r}\nplot(envelope(semis_split[[1]], Kest, correction = \"iso\"))\n```\n\nTel qu'indiqué par le message, cette fonction effectue par défaut 99 simulations de l'hypothèse nulle correspondant à une structure spatiale totalement aléatoire (CSR, pour *complete spatial randomness*).\n\nLa courbe observée sort de l'enveloppe des 99 simulations près de $r = 2$. Il faut être prudent de ne pas interpréter trop rapidement un résultat sortant de l'enveloppe. Même s'il y a environ une probabilité de 1% d'obtenir un résultat plus extrême selon l'hypothèse nulle à une distance donnée, l'enveloppe est calculée pour un grand nombre de valeurs de la distance et nous n'effectuons pas de correction pour les comparaisons multiples. Ainsi, un écart significatif pour une très petite plage de valeurs de $r$ peut être simplement dû au hasard.\n\n\n### Exercice 1\n\nEn regardant le graphique du deuxième patron de points (semis de peuplier), pouvez-vous prédire où se situera le $K$ de Ripley par rapport à l'hypothèse nulle d'une structure spatiale totalement aléatoire? Vérifiez votre prédiction en calculant le $K$ de Ripley pour ce patron de points dans R.\n\n\n## Effet de l'hétérogénéité\n\nLe graphique ci-dessous illustre un patron de points *hétérogène*, c'est-à-dire qu'il présente un gradient d'intensité (plus de points à gauche qu'à droite).\n\n```{r, include = FALSE}\nlam_gr <- function(x, y) ifelse(x < 0.5, 500*(1-x), 200*(1-x))\nhetp <- rpoispp(lam_gr)\nkhet <- envelope(hetp, Kest, correction = \"iso\")\n```\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nplot(hetp, pch = 19, main = \"\")\nplot(khet, main = \"\", legend = FALSE)\n```\n\nUn gradient de densité peut être confondu avec une agrégation des points, comme on peut voir sur le graphique du $K$ de Ripley correspondant. En théorie, il s'agit de deux processus différents:\n\n- Hétérogénéité: La densité de points varie dans la région d'étude, par exemple dû au fait que certaines conditions locales sont plus propices à la présence de l'espèce étudiée.\n\n- Agrégation: La densité moyenne des points est homogène, mais la présence d'un point augmente la présence d'autre points dans son voisinage, par exemple en raison d'interactions positives entre les individus.\n\nCependant, il peut être difficile de différencier les deux en pratique, surtout que certains patrons peuvent être à la fois hétérogènes et agrégés.\n\nPrenons l'exemple des semis de peuplier de l'exercice précédent. La fonction `density` appliquée à un patron de points effectue une estimation par noyau (*kernel density estimation*) de la densité des semis à travers la placette. Par défaut, cette fonction utilise un noyau gaussien avec un écart-type `sigma` spécifié dans la fonction, qui détermine l'échelle à laquelle les fluctuations de densité sont \"lissées\". Ici, nous utilisons une valeur de 2 m pour `sigma` et nous représentons d'abord la densité estimée avec `plot`, avant d'y superposer les points (`add = TRUE` signifie que les points sont ajoutés au graphique existant plutôt que de créer un nouveau graphique).\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 2)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n```\n\nPour mesurer l'agrégation ou la répulsion des points d'un patron hétérogène, nous devons utilisé la version non-homogène de la statistique $K$ (`Kinhom` dans *spatstat*). Cette statistique est toujours égale au nombre moyen de voisins dans un rayon $r$ d'un point du patron, mais plutôt que de normaliser ce nombre par l'intensité globale du patron, il est normalisé par l'estimation locale de la densité de points. Comme ci-dessus, nous spécifions `sigma = 2` pour contrôler le niveau de lissage de l'estimation de la densité variable.\n\n```{r}\nplot(Kinhom(semis_split[[2]], sigma = 2, correction = \"iso\"))\n```\n\nEn tenant compte de l'hétérogénéité du patron à une échelle `sigma` de 2 m, il semble donc y avoir un déficit de voisins à partir d'environ 1.5 m des points du patron. Il reste à voir si cette déviation est significative.\n\nComme précédemment, nous utilisons `envelope` pour simuler la statistique `Kinhom` sous le modèle nul. Cependant, ici le modèle nul n'est pas un processus de Poisson homogène (structure spatiale totalement aléatoire). Il s'agit plutôt d'un processus de Poisson hétérogène simulé par la fonction `rpoispp(dens_p)`, c'est-à-dire que les points sont indépendants les uns des autres, mais leur densité est hétérogène et donnée par `dens_p`. L'argument `simulate` de la fonction `envelope` permet de spécifier une fonction utilisée pour les simulations sous le modèle nul; cette fonction doit avoir un argument, ici `x`, même s'il n'est pas utilisé.\n\nFinalement, en plus des arguments nécessaires pour `Kinhom`, soit `sigma` et `correction`, nous spécifions aussi `nsim = 199` pour réaliser 199 simulations et `nrank = 5` pour éliminer les 5 résultats les plus extrêmes de chaque côté de l'enveloppe, donc les 10 plus extrêmes sur 199, pour réaliser un intervalle contenant environ 95% de la probabilité sous l'hypothèse nulle.\n\n```{r}\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 2, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\n*Note*: Pour un test d'hypothèse basé sur des simulations d'une hypothèse nulle, la valeur $p$ est estimée par $(m + 1)/(n + 1)$, où $n$ est le nombre de simulations et $m$ est le nombre de simulations où la valeur de la statistique est plus extrême que celle des données observées. C'est pour cette raison qu'on choisit un nombre de simulations comme 99, 199, etc.\n\n### Exercice 2\n\nRépétez l'estimation de la densité hétérogène et le calcul de `Kinhom` avec un écart-type `sigma` de 5 plutôt que 2. Comment le niveau de lissage pour la densité influence-t-il les conclusions?\n\nPour différencier une variation de densité des points et d'une interaction (agrégation ou répulsion) entre ces points avec ce type d'analyse, il faut généralement supposer que les deux processus opèrent à différentes échelles. Typiquement, nous pouvons tester si les points sont agrégés à petite échelle après avoir tenu compte d'une variation de la densité à une échelle plus grande.\n\n\n## Relation entre deux patrons de points\n\nConsidérons un cas où nous avons deux patrons de points, par exemple la position des arbres de deux espèces dans une parcelle (points oranges et verts dans le graphique ci-dessous). Chacun des deux patrons peut présenter ou non des agrégations de points. \n\n```{r, echo = FALSE}\ndata(lansing)\nlansing <- subset(lansing, marks %in% c(\"maple\", \"redoak\"), drop = TRUE)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"\", legend = FALSE)\n```\n\nSans égard à cette agrégation au niveau de l'espèce, nous voulons déterminer si les deux espèces sont disposées indépendamment. Autrement dit, la probabilité d'observer un arbre d'une espèce dépend-elle de la présence d'un arbre de l'autre espèce à une distance donnée?\n\nLa version bivariée du $K$ de Ripley permet de répondre à cette question. Pour deux patrons désignés 1 et 2, l'indice $K_{12}(r)$ calcule le nombre moyen de points du patron 2 dans un rayon $r$ autour d'un point du patron 1, normalisé par la densité du patron 2.\n\nEn théorie, cet indice est symétrique, donc $K_{12}(r) = K_{21}(r)$ et le résultat serait le même si on choisit les points du patron 1 ou 2 comme points \"focaux\" pour l'analyse. Cependant, l'estimation des deux quantités pour un patron observé peut différer, notamment en raison des effets de bord. La variabilité peut aussi être différente pour $K_{12}$ et $K_{21}$ entre les simulations d'un modèle nul, donc le test de l'hypothèse nulle peut avoir une puissance différente selon le choix de l'espèce focale.\n\nLe choix d'un modèle nul approprié est important ici. Afin de déterminer s'il existe une attraction ou une répulsion significative entre les deux patrons, il faut déplacer aléatoirement la position d'un des patrons relative à celle de l'autre patron, tout en conservant la structure spatiale de chaque patron pris isolément.\n\nUne des façons d'effectuer cette randomisation consiste à décaler l'un des deux patrons horizontalement et/ou verticalement d'une distance aléatoire. La partie du patron qui \"sort\" d'un côté de la fenêtre est rattachée de l'autre côté. Cette méthode s'appelle une translation toroïdale (*toroidal shift*), car en connectant le haut et le bas ainsi que la gauche et la droite d'une surface rectangulaire, on obtient la forme d'un tore (un \"beigne\" en trois dimensions).\n\n```{r, echo = FALSE}\npar(mfrow = c(1, 2))\nset.seed(35)\nrsh <- rshift(lansing, which = 1, width = 0.5, height = 0)\nplot(lansing, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Original\", legend = FALSE)\nrect(xleft = 1 - rsh$x[8], xright = 1, ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\nplot(rsh, chars = 20, cols = c(\"#1b9e77\", \"#d95f02\"), main = \"Après translation\", legend = FALSE)\nrect(xleft = 0, xright = rsh$x[8], ybottom = 0, ytop = 1, \n col = rgb(0, 0, 0, alpha = 0.1))\n```\n\nLe graphique ci-dessus illustre une translation du patron vert vers la droite, tandis que le patron orange reste au même endroit. Les points verts dans la zone ombragée sont ramenés de l'autre côté. Notez que si cette méthode préserve de façon générale la structure de chaque patron tout en randomisant leur position relative, elle peut comporter certains inconvénients, comme de diviser des amas de points qui se trouvent près du point de coupure.\n\nVérifions maintenant s'il y a une dépendance entre la position des deux espèces (bouleau et peuplier) dans notre placette. La fonction `Kcross` calcule l'indice bivarié $K_{ij}$, il faut spécifier quel type de point est considéré comme l'espèce focale $i$ et l'espèce voisine $j$.\n\n```{r}\nplot(Kcross(semis, i = \"P\", j = \"B\", correction = \"iso\"))\n```\n\nIci, le $K$ observé est inférieur à la valeur théorique, indiquant une répulsion possible des deux patrons.\n\nPour déterminer l'enveloppe du $K$ selon l'hypothèse nulle d'indépendance des deux patrons, nous devons spécifier que les simulations doivent être basées sur une translation des patrons. Nous indiquons que les simulations doivent utiliser la fonction `rshift` (translation aléatoire) avec l'argument `simulate = function(x) rshift(x, which = \"B\")`; ici, l'argument `x` de `simulate` correspond au patron de points original et l'argument `which` indique quel type de points subit la translation. Comme pour le cas précédent, il faut répéter dans la fonction `envelope` les arguments nécessaires pour `Kcross`, soit `i`, `j` et `correction`. \n\n```{r}\nplot(envelope(semis, Kcross, i = \"P\", j = \"B\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = function(x) rshift(x, which = \"B\")))\n```\n\nIci, la courbe observée se situe totalement dans l'enveloppe, donc nous ne rejetons pas l'hypothèse nulle d'indépendance des deux patrons.\n\n### Questions\n\n1. Quelle raison pourrait justifier ici notre choix d'effectuer la translation des points du bouleau plutôt que du peuplier?\n\n2. Est-ce que les simulations générées par translation aléatoire constitueraient un bon modèle nul si les deux patrons étaient hétérogènes?\n\n\n## Patrons de points marqués\n\nLe jeu de données [fir.csv](data/fir.csv) contient les coordonnées $(x, y)$ de 822 sapins dans une placette d'un hectare et leur statut (A = vivant, D = mort) suivant une épidémie de tordeuse des bourgeons de l'épinette.\n\n```{r}\nfir <- read.csv(\"data/fir.csv\")\nhead(fir)\n```\n\n```{r}\nfir <- ppp(x = fir$x, y = fir$y, marks = as.factor(fir$status),\n window = owin(xrange = c(0, 100), yrange = c(0, 100)))\nplot(fir)\n```\n\nSupposons que nous voulons vérifier si la mortalité des sapins est indépendante ou corrélée entre arbres rapprochés. En quoi cette question diffère-t-elle de l'exemple précédent où nous voulions savoir si la position des points de deux espèces était indépendante?\n\nDans l'exemple précédent, l'indépendance ou l'interaction entre les espèces référait à la formation du patron lui-même (que des semis d'une espèce s'établissent ou non à proximité de ceux de l'autre espèce). Ici, la caractéristique qui nous intéresse (survie des sapins) est postérieure à l'établissement du patron, en supposant que tous ces arbres étaient vivants d'abord et que certains sont morts suite à l'épidémie. Donc nous prenons la position des arbres comme fixe et nous voulons savoir si la distribution des statuts (mort, vivant) entre ces arbres est aléatoire ou présente un patron spatial.\n\nDans le manuel de Wiegand et Moloney, la première situation (établissement de semis de deux espèces) est appelé patron bivarié, donc il s'agit vraiment de deux patrons qui interagissent, tandis que la deuxième est un seul patron avec une *marque* qualitative. Le package *spatstat* dans R ne fait pas de différences entre les deux au niveau de la définition du patron (les types de points sont toujours représentés par l'argument `marks`), mais les méthodes d'analyse appliquées aux deux questions diffèrent.\n\nDans le cas d'un patron avec une marque qualitative, nous pouvons définir une fonction de connexion de marques (*mark connection function*) $p_{ij}(r)$. Pour deux points séparés par une distance $r$, cette fonction donne la probabilité que le premier point porte la marque $i$ et le deuxième la marque $j$. Selon l'hypothèse nulle où les marques sont indépendantes, cette probabilité est égale au produit des proportions de chaque marque dans le patron entier, $p_{ij}(r) = p_i p_j$ indépendamment de $r$.\n\nDans *spatstat*, la fonction de connexion de marques est calculée avec la fonction `markconnect`, où il faut spécifier les marques $i$ et $j$ ainsi que le type de correction des effets de bord. Dans notre exemple, nous voyons que deux points rapprochés ont moins de chance d'avoir une statut différent (A et D) que prévu selon l'hypothèse de distribution aléatoire et indépendante des marques (ligne rouge pointillée).\n\n```{r}\nplot(markconnect(fir, i = \"A\", j = \"D\", correction = \"iso\"))\n```\n\nDans ce graphique, les ondulations dans la fonction sont dues à l'erreur d'estimation d'une fonction continue de $r$ à partir d'un nombre limité de paires de points discrètes.\n\nPour simuler le modèle nul dans ce cas-ci, nous utilisons la fonction `rlabel` qui réassigne aléatoirement les marques parmi les points du patron, en maintenant la position des points.\n\n```{r}\nplot(envelope(fir, markconnect, i = \"A\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nNotez que puisque la fonction `rlabel` a un seul argument obligatoire correspondant au patron de points original, il n'était pas nécessaire de spécifier au long: `simulate = function(x) rlabel(x)`.\n\nVoici les résultats pour les paires d'arbres du même statut A ou D:\n\n```{r, fig.dim = c(10, 5)}\npar(mfrow = c(1, 2))\nplot(envelope(fir, markconnect, i = \"A\", j = \"A\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\nplot(envelope(fir, markconnect, i = \"D\", j = \"D\", correction = \"iso\", \n nsim = 199, nrank = 5, simulate = rlabel))\n```\n\nIl semble donc que la mortalité des sapins due à cette épidémie est agrégée spatialement, puisque les arbres situés à proximité l'un de l'autre ont une plus grande probabilité de partager le même statut que prévu par l'hypothèse nulle.\n\n## Références\n\nFortin, M.-J. et Dale, M.R.T. (2005) *Spatial Analysis: A Guide for Ecologists*. Cambridge University Press: Cambridge, UK. \n\nWiegand, T. et Moloney, K.A. (2013) *Handbook of Spatial Point-Pattern Analysis in Ecology*, CRC Press.\n\nLe jeu de données du dernier exemple est tiré des données de la Forêt d'enseignement et de recherche du Lac Duparquet (FERLD), disponibles sur Dryad en suivant [ce lien](https://doi.org/10.5061/dryad.tqjq2bvwz).\n\n\n# Solutions\n\n### Exercice 1\n\n```{r}\nplot(envelope(semis_split[[2]], Kest, correction = \"iso\"))\n```\n\nLes semis de peuplier semblent significativement agrégés selon la valeur du $K$.\n\n### Exercice 2\n\n```{r}\ndens_p <- density(semis_split[[2]], sigma = 5)\nplot(dens_p)\nplot(semis_split[[2]], add = TRUE)\n\nkhet_p <- envelope(semis_split[[2]], Kinhom, sigma = 5, correction = \"iso\",\n nsim = 199, nrank = 5, simulate = function(x) rpoispp(dens_p))\nplot(khet_p)\n```\n\nIci, puisque nous estimons la variation de densité à une plus grande échelle, même après avoir tenu compte de cette variation, les semis de peuplier semblent agrégés à petite échelle.\n\n\n# Corrélation spatiale d'une variable {#spatial-correlation-fr}\n\nLa corrélation entre les mesures d'une variable prises à des points rapprochés est une caractéristique dans de nombreux jeux de données. Ce principe est parfois appelé \"première loi de la géographie\" et exprimé par la citation de Waldo Tobler: \"Everything is related to everything else, but near things are more related than distant things.\" (Tout est relié, mais les choses rapprochées le sont davantage que celles éloignées).\n\nEn statistique, nous parlons souvent d'*autocorrélation* pour désigner la corrélation qui existe entre les mesures d'une même variable prises à différents moments (autocorrélation temporelle) ou différents lieux (autocorrélation spatiale).\n\n## Dépendance intrinsèque ou induite\n\nIl existe deux types fondamentaux de dépendance spatiale sur une variable mesurée $y$: une dépendance *intrinsèque* à $y$, ou une dépendance *induite* par des variables externes influençant $y$, qui sont elles-mêmes corrélées dans l'espace.\n\nPar exemple, supposons que l'abondance d'une espèce soit corrélée entre deux sites rapprochés:\n\n- cette dépendance spatiale peut être induite si elle est due à une corrélation spatiale des facteurs d'habitat qui favorisent ou défavorisent l'espèce;\n\n- ou elle peut être intrinsèque si elle est due à la dispersion d'individus entre sites rapprochés.\n\nDans plusieurs cas, les deux types de dépendance affectent une variable donnée.\n\nSi la dépendance est simplement induite et que les variables externes qui en sont la cause sont incluses dans le modèle expliquant $y$, alors les résidus du modèle seront indépendants et nous pouvons utiliser toutes les méthodes déjà vues qui ignorent la dépendance spatiale.\n\nCependant, si la dépendance est intrinsèque ou due à des influences externes non-mesurées, alors il faudra tenir compte de la dépendance spatiale des résidus dans le modèle.\n\n## Différentes façons de modéliser les effets spatiaux\n\nDans cette formation, nous modéliserons directement les corrélations spatiales de nos données. Il est utile de comparer cette approche à d'autres façons d'inclure des aspects spatiaux dans un modèle statistique.\n\nD'abord, nous pourrions inclure des prédicteurs dans le modèle qui représentent la position (ex.: longitude, latitude). De tels prédicteurs peuvent être utiles pour détecter une tendance ou un gradient systématique à grande échelle, que cette tendance soit linéaire ou non (par exemple, avec un modèle additif généralisé).\n\nEn contraste à cette approche, les modèles que nous verrons maintenant servent à modéliser une corrélation spatiale dans les fluctuations aléatoires d'une variable (i.e., dans les résidus après avoir enlevé tout effet systématique).\n\nLes modèles mixtes utilisent des effets aléatoires pour représenter la non-indépendance de données sur la base de leur groupement, c'est-à-dire qu'après avoir tenu compte des effets fixes systématiques, les données d'un même groupe sont plus semblables (leur variation résiduelle est corrélée) par rapport aux données de groupes différents. Ces groupes étaient parfois définis selon des critères spatiaux (observations regroupées en sites).\n\nCependant, dans un contexte d'effet aléatoire de groupe, tous les groupes sont aussi différents les uns des autres, ex.: deux sites à 100 km l'un de l'autre ne sont pas plus ou moins semblables que deux sites distants de 2 km.\n\nLes méthodes que nous verrons ici et dans les prochains parties de la formation nous permettent donc ce modéliser la non-indépendance sur une échelle continue (plus proche = plus corrélé) plutôt que seulement discrète (hiérarchie de groupements).\n\n\n# Modèles géostatistiques {#geostat-models-fr}\n\nLa géostatistique désigne un groupe de techniques tirant leur origine en sciences de la Terre. Elle s'intéresse à des variables distribuées de façon continue dans l'espace, dont on cherche à estimer la distribution en échantillonnant un nombre de points. Un exemple classique de ces techniques provient du domaine minier, où l'on cherchait à créer une carte de la concentration du minerai sur un site à partir d'échantillons pris à différents points du site.\n\nPour ces modèles, nous supposerons que $z(x, y)$ est une variable spatiale stationnaire mesurée selon les coordonnées $x$ et $y$.\n\n## Variogramme\n\nUn aspect central de la géostatistique est l'estimation du variogramme $\\gamma_z$ de la variable $z$. Le variogramme est égal à la moitié de l'écart carré moyen entre les valeurs de $z$ pour deux points $(x_i, y_i)$ et $(x_j, y_j)$ séparés par une distance $h$.\n\n$$\\gamma_z(h) = \\frac{1}{2} \\text{E} \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h}$$\n\nDans cette équation, la fonction $\\text{E}$ avec l'indice $d_{ij}=h$ désigne l'espérance statistique (autrement dit, la moyenne) de l'écart au carré entre les valeurs de $z$ pour les points séparés par une distance $h$.\n\nSi on préfère exprimer l'autocorrélation $\\rho_z(h)$ entre mesures de $z$ séparées par une distance $h$, celle-ci est reliée au variogramme par l'équation:\n\n$$\\gamma_z = \\sigma_z^2(1 - \\rho_z)$$ ,\n\noù $\\sigma_z^2$ est la variance globale de $z$. \n\nNotez que $\\gamma_z = \\sigma_z^2$ si nous sommes à une distance où les mesures de $z$ sont indépendantes, donc $\\rho_z = 0$. Dans ce cas, on voit bien que $\\gamma_z$ s'apparente à une variance, même s'il est parfois appelé \"semivariogramme\" ou \"semivariance\" en raison du facteur 1/2 dans l'équation ci-dessus.\n\n## Modèles théoriques du variogramme\n\nPlusieurs modèles paramétriques ont été proposés pour représenter la corrélation spatiale en fonction de la distance entre points d'échantillonnage. Considérons d'abord une corrélation qui diminue de façon exponentielle: \n\n$$\\rho_z(h) = e^{-h/r}$$\n\nIci, $\\rho_z = 1$ pour $h = 0$ et la corréaltion est multipliée par $1/e \\approx 0.37$ pour chaque augmentation de $r$ de la distance. Dans ce contexte, $r$ se nomme la portée (*range*) de la corrélation.\n\nÀ partir de l'équation ci-dessus, nous pouvons calculer le variogramme correspondant.\n\n$$\\gamma_z(h) = \\sigma_z^2 (1 - e^{-h/r})$$\n\nVoici une représentation graphique de ce variogramme.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 5*(1-exp(-1)),\n yend = 5*(1-exp(-1))), \n arrow = arrow(length = unit(0.05, \"inches\"), ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 3.5, label = \"portée (range)\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"palier (sill)\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nEn raison de la fonction exponentielle, la valeur de $\\gamma$ à des grandes distances s'approche de la variance globale $\\sigma_z^2$ sans exactement l'atteindre. Cette asymptote est appelée palier (*sill*) dans le contexte géostatistique et représentée par le symbole $s$.\n\nFinalement, il n'est parfois pas réaliste de supposer une corrélation parfaite lorsque la distance tend vers 0, en raison d'une variation possible de $z$ à très petite échelle. On peut ajouter au modèle un effet de pépite (*nugget*), noté $n$, pour que $\\gamma$ s'approche de $n$ (plutôt que 0) si $h$ tend vers 0. Le terme pépite provient de l'origine minière de ces techniques, où une pépite d'un minerai pourrait être la source d'une variation abrupte de la concentration à petite échelle.\n\nEn ajoutant l'effet de pépite, le reste du variogramme est \"compressé\" pour conserver le même palier, ce qui résulte en l'équation suivante.\n\n$$\\gamma_z(h) = n + (s - n) (1 - e^{-h/r})$$\n\nDans le package *gstat* que nous utiliserons ci-dessous, le terme $(s - n)$ est le palier partiel (*partial sill*, ou `psill`) pour la partie exponentielle.\n\n```{r, echo = FALSE}\nggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma)) +\n stat_function(fun = function(x) 4 * (1 - exp(-x/3)) + 1,\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\") +\n geom_segment(aes(x = 0, xend = 2.8, y = 4*(1-exp(-1)) + 1,\n yend = 4*(1-exp(-1)) + 1), \n arrow = arrow(length = unit(0.05, \"inches\"), \n ends = \"both\", type = \"closed\")) +\n geom_segment(aes(x = 0, xend = 0, y = 0, yend = 0.9),\n arrow = arrow(length = unit(0.05, \"inches\"),\n ends = \"both\", type = \"closed\")) +\n annotate(\"text\", x = 1.5, y = 4, label = \"portée (range)\") +\n annotate(\"text\", x = 9, y = 5.5, label = \"palier (sill)\") +\n annotate(\"text\", x = 1.5, y = 0.5, label = \"pépite (nugget)\") +\n scale_y_continuous(limits = c(0, 6))\n```\n\nEn plus du modèle exponentiel, deux autres modèles théoriques courants pour le variogramme sont le modèle gaussien (où la corrélation suit une courbe demi-normale), ainsi que le modèle sphérique (où le variogramme augmente de façon linéaire au départ pour ensuite courber et atteindre le palier à une distance égale à sa portée $r$). Le modèle sphérique permet donc à la corrélation d'être exactement 0 à grande distance, plutôt que de s'approcher graduellement de zéro dans le cas des autres modèles.\n\n Modèle | $\\rho(h)$ | $\\gamma(h)$\n-------|-----------|-------------\nExponentiel | $\\exp\\left(-\\frac{h}{r}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h}{r}\\right)\\right)$\nGaussien | $\\exp\\left(-\\frac{h^2}{r^2}\\right)$ | $s \\left(1 - \\exp\\left(-\\frac{h^2}{r^2}\\right)\\right)$\nSphérique $(h < r)$ * | $1 - \\frac{3}{2}\\frac{h}{r} + \\frac{1}{2}\\frac{h^3}{r^3}$ | $s \\left(\\frac{3}{2}\\frac{h}{r} - \\frac{1}{2}\\frac{h^3}{r^3} \\right)$\n\n\\* Pour le modèle sphérique, $\\rho = 0$ et $\\gamma = s$ si $h \\ge r$.\n\n\n```{r, echo = FALSE, fig.dim = c(9, 4)}\nvexp <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Exponentiel\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x/3)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n \n\nvgau <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Gaussien\") +\n stat_function(fun = function(x) 5 * (1 - exp(-x^2/4^2)),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nvsph <- ggplot(NULL) + xlim(0, 10) +\n labs(x = \"h\", y = expression(gamma), title = \"Sphérique\") +\n stat_function(fun = function(x) ifelse(x < 8, 5 * (1.5*x/8 - 0.5*x^3/8^3), 5),\n geom = \"line\", color = \"#b3452c\", size = 1) +\n geom_hline(yintercept = 5, linetype = \"dotted\")\n\nplot_grid(vexp, vgau, vsph, nrow = 1)\n```\n\n## Variogramme empirique\n\nPour estimer $\\gamma_z(h)$ à partir de données empiriques, nous devons définir des classes de distance, donc grouper différentes distances dans une marge $\\pm \\delta$ autour d'une distance $h$, puis calculer l'écart-carré moyen pour les paires de points dans cette classe de distance.\n\n$$\\hat{\\gamma_z}(h) = \\frac{1}{2 N_{\\text{paires}}} \\sum \\left[ \\left( z(x_i, y_i) - z(x_j, y_j) \\right)^2 \\right]_{d_{ij} = h \\pm \\delta}$$\n\nNous verrons dans la partie suivante comment estimer un variogramme dans R.\n\n## Modèle de régression avec corrélation spatiale\n\nL'équation suivante représente une régression linéaire multiple incluant une corrélation spatiale résiduelle:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\nIci, $v$ désigne la variable réponse et $u$ les prédicteurs, pour ne pas confondre avec les coordonnées spatiales $x$ et $y$. \n\nEn plus du résidu $\\epsilon$ qui est indépendant entre les observations, le modèle inclut un terme $z$ qui représente la portion spatialement corrélée de la variance résiduelle.\n\nVoici une suggestions d'étapes à suivre pour appliquer ce type de modèle:\n\n1. Ajuster le modèle de régression sans corrélation spatiale.\n\n2. Vérifier la présence de corrélation spatiale à partir du variogramme empirique des résidus.\n\n3. Ajuster un ou plusieurs modèles de régression avec corrélation spatiale et choisir celui qui montre le meilleur ajustement aux données. \n\n# Modèles géostatistiques dans R\n\nLe package *gstat* contient des fonctions liées à la géostatistique. Pour cet exemple, nous utiliserons le jeu de données `oxford` de ce package, qui contient des mesures de propriétés physiques et chimiques pour 126 échantillons du sol d'un site, ainsi que leurs coordonnées `XCOORD` et `YCOORD`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gstat)\n\ndata(oxford)\nstr(oxford)\n```\n\nSupposons que nous souhaitons modéliser la concentration de magnésium (`MG1`), représentée en fonction de la position spatiale dans le graphique suivant.\n\n```{r}\nlibrary(ggplot2)\nggplot(oxford, aes(x = YCOORD, y = XCOORD, size = MG1)) +\n geom_point() +\n coord_fixed()\n```\n\nNotez que les axes $x$ et $y$ ont été inversés par souci d'espace. La fonction `coord_fixed()` de *ggplot2* assure que l'échelle soit la même sur les deux axes, ce qui est utile pour représenter des données spatiales. \n\nNous voyons tout de suite que ces mesures ont été prises sur une grille de 100 m de côté. Il semble que la concentration de magnésium soit spatialement corrélée, bien qu'il puisse s'agir d'une corrélation induite par une autre variable. Nous savons notamment que la concentration de magnésium est reliée négativement au pH du sol (`PH1`).\n\n```{r}\nggplot(oxford, aes(x = PH1, y = MG1)) +\n geom_point()\n```\n\nLa fonction `variogram` de *gstat* sert à estimer un variogramme à partir de données empiriques. Voici le résultat obtenu pour la variable `MG1`.\n\n```{r}\nvar_mg <- variogram(MG1 ~ 1, locations = ~ XCOORD + YCOORD, data = oxford)\nvar_mg\n```\n\nLa formule `MG1 ~ 1` indique qu'aucun prédicteur linéaire n'est inclus dans ce modèle, tandis que l'argument `locations` indique quelles variables du tableau correspondent aux coordonnées spatiales. \n\nDans le tableau obtenu, `gamma` est la valeur du variogramme pour la classe de distance centrée sur `dist`, tandis que `np` est le nombre de paires de points dans cette classe. Ici, puisque les points sont situés sur une grille, nous obtenons des classes de distance régulières (ex.: 100 m pour les points voisins sur la grille, 141 m pour les voisins en diagonale, etc.).\n\nNous nous limitons ici à l'estimation de variogrammes isotropiques, c'est-à-dire que le variogramme dépend seulement de la distance entre les deux points et non de la direction. Bien que nous n'ayons pas le temps de le voir aujourd'hui, il est possible avec *gstat* d'estimer séparément le variogramme dans différentes directions.\n\nNous pouvons illustrer le variogramme avec `plot`.\n\n```{r}\nplot(var_mg, col = \"black\")\n```\n\nSi nous voulons estimer la corrélation spatiale résiduelle de `MG1` après avoir inclus l'effet de `PH1`, nous pouvons ajouter ce prédicteur à la formule.\n\n```{r}\nvar_mg <- variogram(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford)\nplot(var_mg, col = \"black\")\n```\n\nEn incluant l'effet du pH, la portée de la corrélation spatiale semble diminuer, alors que le plateau est atteint autour de 300 m. Il semble même que le variogramme diminue au-delà de 400 m. En général, nous supposons que la variance entre deux points ne diminue pas avec la distance, à moins d'avoir un patron spatial périodique.\n\nLa fonction `fit.variogram` accepte comme arguments un variogramme estimé à partir des données, ainsi qu'un modèle théorique décrit dans une fonction `vgm`, puis estime les paramètres de ce modèle en fonction des données. L'ajustement se fait par la méthode des moindres carrés.\n\nPar exemple, `vgm(\"Exp\")` indique d'ajuster un modèle exponentiel. \n\n```{r}\nvfit <- fit.variogram(var_mg, vgm(\"Exp\"))\nvfit\n```\n\nIl n'y a aucun effet de pépite, car `psill = 0` pour la partie `Nug` (*nugget*) du modèle. La partie exponentielle a un palier à 1951 et une portée de 95 m.\n\nPour comparer différents modèles, on peut donner un vecteur de noms de modèles à `vgm`. Dans l'exemple suivant, nous incluons les modèles exponentiel, gaussien (\"Gau\") et sphérique (\"Sph\").\n\n```{r, warning = FALSE, message = FALSE}\nvfit <- fit.variogram(var_mg, vgm(c(\"Exp\", \"Gau\", \"Sph\")))\nvfit\n```\n\nLa fonction nous donne le résultat du modèle le mieux ajusté (plus faible somme des écarts au carré), qui est ici le même modèle exponentiel.\n\nFinalement, nous pouvons superposer le modèle théorique et le variogramme empirique sur un même graphique.\n\n```{r}\nplot(var_mg, vfit, col = \"black\")\n```\n\n## Régression avec corrélation spatiale\n\nNous avons vu ci-dessus que le package *gstat* permet d'estimer le variogramme des résidus d'un modèle linéaire. Dans notre exemple, la concentration de magnésium était modélisée en fonction du pH, avec des résidus spatialement corrélés.\n\nUn autre outil pour ajuster ce même type de modèle est la fonction `gls` du package *nlme*, qui est inclus avec l'installation de R. \n\nCette fonction applique la méthode des moindres carrés généralisés (*generalized least squares*) pour ajuster des modèles de régression linéaire lorsque les résidus ne sont pas indépendants ou lorsque la variance résiduelle n'est pas la même pour toutes les observations. Comme les estimés des coefficients dépendent de l'estimé des corrélations entre les résidus et que ces derniers dépendent eux-mêmes des coefficients, le modèle est ajusté par un algorithme itératif:\n\n1. On ajuste un modèle de régression linéaire classique (sans corrélation) pour obtenir des résidus.\n\n2. On ajuste le modèle de corrélation spatiale (variogramme) avec ses résidus.\n\n3. On ré-estime les coefficients de la régression en tenant compte maintenant des corrélations.\n\nLes étapes 2 et 3 sont répétées jusqu'à ce que les estimés soient stables à une précision voulue.\n\nVoici l'application de cette méthode au même modèle pour la concentration de magnésium dans le jeu de données `oxford`. Dans l'argument `correlation` de `gls`, nous spécifions un modèle de corrélation exponentielle en fonction de nos coordonnées spatiales et indiquons que nous voulons aussi estimer un effet de pépite.\n\nEn plus de la corrélation exponentielle `corExp`, la fonction `gls` peut aussi estimer un modèle gaussien (`corGaus`) ou sphérique (`corSpher`).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(nlme)\ngls_mg <- gls(MG1 ~ PH1, oxford, \n correlation = corExp(form = ~ XCOORD + YCOORD, nugget = TRUE))\nsummary(gls_mg)\n```\n\nPour comparer ce résultat au variogramme ajusté ci-dessus, il faut transformer les paramètres donnés par `gls`. La portée (range) a le même sens dans les deux cas et correspond à 478 m pour le résultat de `gls`. La variance globale des résidus est le carré de `Residual standard error`. L'effet de pépite ici (0.294) est exprimé comme fraction de cette variance. Finalement, pour obtenir le palier partiel de la partie exponentielle, il faut soustraire l'effet de pépite de la variance totale. \n\nAprès avoir réalisé ces calculs, nous pouvons donner ces paramètres à la fonction `vgm` de *gstat* pour superposer ce variogramme estimé par `gls` à notre variogramme des résidus du modèle linéaire classique.\n\n```{r}\ngls_range <- 478\ngls_var <- 53.823^2\ngls_nugget <- 0.294 * gls_var\ngls_psill <- gls_var - gls_nugget\n\ngls_vgm <- vgm(\"Exp\", psill = gls_psill, range = gls_range, nugget = gls_nugget)\n\nplot(var_mg, gls_vgm, col = \"black\", ylim = c(0, 4000))\n```\n\nEst-ce que le modèle est moins bien ajusté aux données ici? En fait, ce variogramme empirique représenté par les points avait été obtenu à partir des résidus du modèle linéaire ignorant la corrélation spatiale, donc c'est un estimé biaisé des corrélations spatiales réelles. La méthode est quand même adéquate pour vérifier rapidement s'il y a présence de corrélations spatiales. Toutefois, pour ajuster simultanément les coefficients de la régression et les paramètres de corrélation spatiale, l'approche des moindres carrés généralisés (GLS) est préférable et produira des estimés plus justes.\n\nFinalement, notez que le résultat du modèle `gls` donne aussi l'AIC, que nous pouvons utiliser pour comparer l'ajustement de différents modèles (avec différents prédicteurs ou différentes formes de corrélation spatiale).\n\n## Exercice\n\nLe fichier [bryo_belg.csv](data/bryo_belg.csv) est adapté des données de l'étude: \n\n> Neyens, T., Diggle, P.J., Faes, C., Beenaerts, N., Artois, T. et Giorgi, E. (2019) Mapping species richness using opportunistic samples: a case study on ground-floor bryophyte species richness in the Belgian province of Limburg. *Scientific Reports* 9, 19122. https://doi.org/10.1038/s41598-019-55593-x\n\nCe tableau de données indique la richesse spécifique des bryophytes au sol (*richness*) pour différents points d'échantillonnage de la province belge de Limbourg, avec leur position *(x, y)* en km, en plus de l'information sur la proportion de forêts (*forest*) et de milieux humides (*wetland*) dans une cellule de 1 km$^2$ contenant le point d'échantillonnage.\n\n```{r}\nbryo_belg <- read.csv(\"data/bryo_belg.csv\")\nhead(bryo_belg)\n```\n\nPour cet exercice, nous utiliserons la racine carrée de la richesse spécifique comme variable réponse. La transformation racine carrée permet souvent d'homogénéiser la variance des données de comptage afin d'y appliquer une régression linéaire. \n\na) Ajustez un modèle linéaire de la richesse spécifique transformée en fonction de la fraction de forêt et de milieux humides, sans tenir compte des corrélations spatiales. Quel est l'effet des deux prédicteurs selon ce modèle?\n\nb) Calculez le variogramme empirique des résidus du modèle en (a). Semble-t-il y avoir une corrélation spatiale entre les points?\n\n*Note*: L'argument `cutoff` de la fonction `variogram` spécifie la distance maximale à laquelle le variogramme est calculé. Vous pouvez ajuster manuellement cette valeur pour bien voir le palier.\n\nc) Ré-ajustez le modèle linéaire en (a) avec la fonction `gls` du package *nlme*, en essayant différents types de corrélations spatiales (exponentielle, gaussienne, sphérique). Comparez les modèles (incluant celui sans corrélation spatiale) avec l'AIC.\n\nd) Quel est l'effet de la fraction de forêts et de milieux humides selon le modèle en (c)? Expliquez les différences entre les conclusions de ce modèle et du modèle en (a).\n\n\n# Krigeage\n\nTel que mentionné précédemment, une application courante des modèles géostatistiques consiste à prédire la valeur de la variable de réponse à des points non-échantillonnés, une forme d'interpolation spatiale appelée krigeage (*kriging*).\n\nIl existe trois principaux types de krigeage selon les suppositions faites au sujet de la variable réponse:\n\n- Krigeage ordinaire: variable stationnaire avec une moyenne inconnue.\n\n- Krigeage simple: Variable stationnaire avec une moyenne connue.\n\n- Krigeage universel: Variable dont la tendance est donnée par un modèle linéaire ou non linéaire.\n\nPour toutes les méthodes de krigeage, les prédictions à un nouveau point sont une moyenne pondérée des valeurs à des points connus. Ces pondérations sont choisies de manière à ce que le krigeage fournisse la meilleure prédiction linéaire non biaisée de la variable de réponse, si les hypothèses du modèle (en particulier le variogramme) sont correctes. C'est-à-dire que, parmi toutes les prédictions non biaisées possibles, les poids sont choisis de manière à donner l'erreur quadratique moyenne minimale. Le krigeage fournit également une estimation de l'incertitude de chaque prédiction.\n\nBien que nous ne présentions pas ici les équations détaillées du krigeage, les poids dépendent à la fois des corrélations (estimées par le variogramme) entre les points échantillonnés et le nouveau point, ainsi que des corrélations entre les points échantillonnés eux-mêmes. Autrement dit, les points échantillonnés proches du nouveau point ont plus de poids, mais les points échantillonnés isolés ont également plus de poids, car les points échantillonnés proches les uns des autres fournissent une informations redondante.\n\nLe krigeage est une méthode d'interpolation, donc la prédiction à un point échantillonné sera toujours égale à la valeur mesurée (la variable est supposée être mesurée sans erreur, elle varie seulement entre les points). Cependant, en présence d'un effet de pépite, tout petit déplacement par rapport à l'endroit échantillonné présentera une variabilité en fonction de la pépite.\n\nDans l'exemple ci-dessous, nous générons un nouvel ensemble de données composé de coordonnées (x, y) générées de façon aléatoire dans la zone d'étude ainsi que des valeurs de pH générées de façon aléatoire sur la base des données `oxford`. Nous appliquons ensuite la fonction `krige` pour prédire les valeurs de magnésium à ces nouveaux points. Notez que nous spécifions le variogramme dérivé des résultats du `gls` dans l'argument `model` de `krige`.\n\n```{r}\nset.seed(14)\nnew_points <- data.frame(\n XCOORD = runif(100, min(oxford$XCOORD), max(oxford$XCOORD)),\n YCOORD = runif(100, min(oxford$YCOORD), max(oxford$YCOORD)),\n PH1 = rnorm(100, mean(oxford$PH1), sd(oxford$PH1))\n)\n\npred <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm)\nhead(pred)\n```\n\nLe résultat de `krige` comprend les nouvelles coordonnées du point, la prédiction de la variable `var1.pred` ainsi que sa variance estimée `var1.var`. Dans le graphique ci-dessous, nous montrons les prédictions moyennes de MG1 à partir du krigeage (triangles) ainsi que les mesures (cercles).\n\n```{r}\npred$MG1 <- pred$var1.pred\n\nggplot(oxford, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n geom_point(data = pred, shape = 17, size = 2) +\n coord_fixed()\n```\n\nLa moyenne et la variance estimées par krigeage peuvent être utilisées pour simuler les valeurs possibles de la variable à chaque nouveau point, conditionnellement aux valeurs échantillonnées. Dans l'exemple ci-dessous, nous avons effectué 4 simulations conditionnelles en ajoutant l'argument `nsim = 4` à la même instruction `krige`.\n\n```{r}\nsim_mg <- krige(MG1 ~ PH1, locations = ~ XCOORD + YCOORD, data = oxford,\n newdata = new_points, model = gls_vgm, nsim = 4)\nhead(sim_mg)\n```\n\n```{r, message = FALSE, warning = FALSE, fig.dim = c(10, 5)}\nlibrary(tidyr)\nsim_mg <- pivot_longer(sim_mg, cols = c(sim1, sim2, sim3, sim4), \n names_to = \"sim\", values_to = \"MG1\")\nggplot(sim_mg, aes(x = YCOORD, y = XCOORD, color = MG1)) +\n geom_point() +\n coord_fixed() +\n facet_wrap(~ sim)\n```\n\n\n# Solutions\n\n```{r}\nbryo_lm <- lm(sqrt(richness) ~ forest + wetland, data = bryo_belg)\nsummary(bryo_lm)\n```\n\nLa proportion de forêts a un effet positif significatif et la proportion de milieux humides a un effet négatif significatif sur la richesse des bryophytes.\n\n```{r}\nplot(variogram(sqrt(richness) ~ forest + wetland, locations = ~ x + y,\n data = bryo_belg, cutoff = 50), col = \"black\")\n```\n\nLe variogramme augmente au moins jusqu'à une distance de 40 km, il semble donc y avoir des corrélations spatiales dans les résidus du modèle.\n\n```{r}\nbryo_exp <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corExp(form = ~ x + y, nugget = TRUE))\nbryo_gaus <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corGaus(form = ~ x + y, nugget = TRUE))\nbryo_spher <- gls(sqrt(richness) ~ forest + wetland, data = bryo_belg,\n correlation = corSpher(form = ~ x + y, nugget = TRUE))\n```\n\n```{r}\nAIC(bryo_lm)\nAIC(bryo_exp)\nAIC(bryo_gaus)\nAIC(bryo_spher)\n```\n\nLe modèle sphérique a l'AIC le plus faible.\n\n```{r}\nsummary(bryo_spher)\n```\n\nLa magnitude des deux effets est moins importante et l'effet des milieux humides n'est plus significatif. Comme c'est le cas pour d'autres types de résidus non indépendants, la \"taille effective\" de l'échantillon est ici inférieure au nombre de points, car des points proches les uns des autres fournissent une information redondante. Par conséquent, la relation entre les prédicteurs et la réponse est moins claire que celle donnée par le modèle supposant que tous ces points étaient indépendants.\n\nNotez que les résultats pour les trois modèles `gls` sont assez similaires, donc le choix d'inclure des corrélations spatiales était plus important que la forme exacte supposée pour le variogramme.\n\n\n# Données aréales {#areal-data-fr}\n\nLes données aréales sont des variables mesurées pour des régions de l'espace; ces régions sont définies par des polygones. Ce type de données est plus courant en sciences sociales, en géographie humaine et en épidémiologie, où les données sont souvent disponibles à l'échelle de divisions administratives du territoire. \n\nCe type de données apparaît aussi fréquemment dans la gestion des ressources naturelles. Par exemple, la carte suivante montre les unités d'aménagement forestier du Ministère de la Forêts, de la Faune et des Parcs du Québec.\n\n![](images/cartes_unites.png)\n\nSupposons qu'une certaine variable soit disponible au niveau de ces divisions du territoire. Comment pouvons-nous modéliser la corrélation spatiale entre les unités qui sont spatialement rapprochées?\n\nUne option serait d'appliquer les méthodes géostatistiques vues précédemment, en calculant par exemple la distance entre les centres des polygones.\n\nUne autre option, qui est davantage privilégiée pour les données aréales, consiste à définir un réseau où chaque région est connectée aux régions voisines par un lien. On suppose ensuite que les variables sont directement corrélées entre régions voisines seulement. (Notons toutefois que les corrélations directes entre voisins immédiats génèrent aussi des corrélations indirectes pour une chaîne de voisins.)\n\nDans ce type de modèle, la corrélation n'est pas nécessairement la même d'un lien à un autre. Dans ce cas, chaque lien du réseau peut être associé à un *poids* représentant son importance pour la corrélation spatiale. Nous représentons ces poids par une matrice $W$ où $w_{ij}$ est le poids du lien entre les régions $i$ et $j$. Une région n'a pas de lien avec elle-même, donc $w_{ii} = 0$.\n\nUn choix simple pour $W$ consiste à assigner un poids égal à 1 si les régions sont voisines, sinon 0 (poids binaires).\n\nOutre les divisions du territoire en polygones, un autre exemple de données aréales consiste en une grille où la variable est compilée pour chaque cellule de la grille. Dans ce cas, une cellule a généralement 4 ou 8 cellules voisines, selon que les diagonales soient incluses ou non.\n\n# Indice de Moran {#moran-i-fr}\n\nAvant de discuter des modèles d'autocorrélation spatiale, nous présentons l'indice $I$ de Moran, qui permet de tester si une corrélation significative est présente entre régions voisines. \n\nL'indice de Moran est un coefficient d'autocorrélation spatiale des $z$, pondéré par les poids $w_{ij}$. Il prend donc des valeurs entre -1 et 1.\n\n$$I = \\frac{N}{\\sum_i \\sum_j w_{ij}} \\frac{\\sum_i \\sum_j w_{ij} (z_i - \\bar{z}) (z_j - \\bar{z})}{\\sum_i (z_i - \\bar{z})^2}$$\n\nDans cette équation, nous reconnaissons l'expression d'une corrélation, soit le produit des écarts à la moyenne de deux variables $z_i$ et $z_j$, divisé par le produit de leurs écarts-types (qui est le même, donc on obtient la variance). La contribution de chaque paire $(i, j)$ est multipliée par son poids $w_{ij}$ et le terme à gauche (le nombre de régions $N$ divisé par la somme des poids) assure que le résultat soit borné entre -1 et 1.\n\nPuisque la distribution de $I$ est connue en l'absence d'autocorrélation spatiale, cette statistique permet de tester l'hypothèse nulle selon laquelle il n'y a pas de corrélation spatiale entre régions voisines.\n\nBien que nous ne verrons pas d'exemple dans ce cours-ci, l'indice de Moran peut aussi être appliqué aux données ponctuelles. Dans ce cas, on divise les paires de points en classes de distance et on calcule $I$ pour chaque classe de distance; le poids $w_{ij} = 1$ si la distance entre $i$ et $j$ se trouve dans la classe de distance voulue, 0 autrement.\n\n# Modèles d'autorégression spatiale {#spatial-autoreg-fr}\n\nRappelons-nous la formule pour une régression linéaire avec dépendance spatiale:\n\n$$v = \\beta_0 + \\sum_i \\beta_i u_i + z + \\epsilon$$\n\noù $z$ est la portion de la variance résiduelle qui est spatialement corrélée.\n\nIl existe deux principaux types de modèles autorégressifs pour représenter la dépendance spatiale de $z$: l'autorégression conditionnelle (CAR) et l'autorégression simultanée (SAR).\n\n## Autorégression conditionnelle (CAR)\n\nDans le modèle d'autorégression conditionnelle, la valeur de $z_i$ pour la région $i$ suit une distribution normale: sa moyenne dépend de la valeur $z_j$ des régions voisines, multipliée par le poids $w_{ij}$ et un coefficient de corrélation $\\rho$; son écart-type $\\sigma_{z_i}$ peut varier d'une région à l'autre.\n\n$$z_i \\sim \\text{N}\\left(\\sum_j \\rho w_{ij} z_j,\\sigma_{z_i} \\right)$$\n\nDans ce modèle, si $w_{ij}$ est une matrice binaire (0 pour les non-voisins, 1 pour les voisins), alors $\\rho$ est le coefficient de corrélation partielle entre régions voisines. Cela est semblable à un modèle autorégressif d'ordre 1 dans le contexte de séries temporelles, où le coefficient d'autorégression indique la corrélation partielle.\n\n## Autorégression simultanée (SAR)\n\nDans le modèle d'autorégression simultanée, la valeur de $z_i$ est donnée directement par la somme de contributions des valeurs voisines $z_j$, multipliées par $\\rho w_{ij}$, avec un résidu indépendant $\\nu_i$ d'écart-type $\\sigma_z$.\n\n$$z_i = \\sum_j \\rho w_{ij} z_j + \\nu_i$$\n\nÀ première vue, cela ressemble à un modèle autorégressif temporel. Il existe cependant une différence conceptuelle importante. Pour les modèles temporels, l'influence causale est dirigée dans une seule direction: $v(t-2)$ affecte $v(t-1)$ qui affecte ensuite $v(t)$. Pour un modèle spatial, chaque $z_j$ qui affecte $z_i$ dépend à son tour de $z_i$. Ainsi, pour déterminer la distribution conjointe des $z$, il faut résoudre simultanément (d'où le nom du modèle) un système d'équations. \n\nPour cette raison, même si ce modèle ressemble à la formule du modèle conditionnel (CAR), les solutions des deux modèles diffèrent et dans le cas du SAR, le coefficient $\\rho$ n'est pas directement égal à la corrélation partielle due à chaque région voisine.\n\nPour plus de détails sur les aspects mathématiques de ces modèles, vous pouvez consulter l'article de Ver Hoef et al. (2018) suggéré en référence. \n\nPour l'instant, nous considérerons les SAR et les CAR comme deux types de modèles possibles pour représenter une corrélation spatiale sur un réseau. Nous pouvons toujours ajuster plusieurs modèles et les comparer avec l'AIC pour choisir la meilleure forme de la corrélation ou la meilleure matrice de poids.\n\nLes modèles CAR et SAR partagent un avantage sur les modèles géostatistiques au niveau de l'efficacité. Dans un modèle géostatistique, les corrélations spatiales sont définies entre chaque paire de points, même si elles deviennent négligeables lorsque la distance augmente. Pour un modèle CAR ou SAR, seules les régions voisines contribuent et la plupart des poids sont égaux à 0, ce qui rend ces modèles plus rapides à ajuster qu'un modèle géostatistique lorsque les données sont massives.\n\n# Analyse des données aréales dans R {#analysis-areal-fr}\n\nPour illustrer l'analyse de données aréales dans R, nous chargeons les packages *sf* (pour lire des données géospatiales), *spdep* (pour définir des réseaux spatiaux et calculer l'indice de Moran) et *spatialreg* (pour les modèles SAR et CAR).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nlibrary(spdep)\nlibrary(spatialreg)\n```\n\nNous utiliserons comme exemple un jeu de données qui présente une partie des résultats de l'élection provinciale de 2018 au Québec, avec des caractéristiques de la population de chaque circonscription. Ces données sont inclues dans un fichier de type *shapefile* (.shp), que nous pouvons lire avec la fonction `read_sf` du package *sf*.\n\n```{r}\nelect2018 <- read_sf(\"data/elect2018.shp\")\nhead(elect2018)\n```\n\n*Note*: Le jeu de données est en fait composé de 4 fichiers avec les extensions .dbf, .prj, .shp et .shx, mais il suffit d'inscrire le nom du fichier .shp dans `read_sf`.\n\nLes colonnes du jeu de données sont dans l'ordre:\n\n- le nom de la circonscription électorale;\n- quatre caractéristiques de la population (âge moyen, fraction de la population qui parle principalement français à la maison, fraction des ménages qui sont propriétaires de leur logement, revenu médian);\n- quatre colonnes montrant la fraction des votes obtenues par les principaux partis (CAQ, PQ, PLQ, QS);\n- une colonne `geometry` qui contient l'objet géométrique (multipolygone) correspondant à la circonscription.\n\nPour illustrer une des variables sur une carte, nous appelons la fonction `plot` avec le nom de la colonne entre crochets et guillemets. \n\n```{r}\nplot(elect2018[\"rev_med\"])\n```\n\nDans cet exemple, nous voulons modéliser la fraction des votes obtenue par la CAQ en fonction des caractéristiques de la population dans chaque circonscription et en tenant compte des corrélations spatiales entre circonscriptions voisines.\n\n## Définition du réseau de voisinage\n\nLa fonction `poly2nb` du package *spdep* définit un réseau de voisinage à partir de polygones. Le résultat `vois` est une liste de 125 éléments où chaque élément contient les indices des polygones voisins (limitrophes) d'un polygone donné.\n\n```{r}\nvois <- poly2nb(elect2018)\nvois[[1]]\n```\n\nAinsi, la première circonscription (Abitibi-Est) a 6 circonscriptions voisines, dont on peut trouver les noms ainsi:\n\n```{r}\nelect2018$circ[vois[[1]]]\n```\n\nNous pouvons illustrer ce réseau en faisant l'extraction des coordonnées du centre de chaque circonscription, en créant une carte muette avec `plot(elect2018[\"geometry\"])`, puis en ajoutant le réseau comme couche additionnelle avec `plot(vois, add = TRUE, coords = coords)`.\n\n```{r, message = FALSE, warning = FALSE}\ncoords <- st_centroid(elect2018) %>%\n st_coordinates()\nplot(elect2018[\"geometry\"])\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nOn peut faire un \"zoom\" sur le sud du Québec en choisissant les limites `xlim` et `ylim` appropriées.\n\n```{r}\nplot(elect2018[\"geometry\"], \n xlim = c(400000, 800000), ylim = c(100000, 500000))\nplot(vois, add = TRUE, col = \"red\", coords = coords)\n```\n\nIl nous reste à ajouter des poids à chaque lien du réseau avec la fonction `nb2listw`. Le style de poids \"B\" correspond aux poids binaires, soit 1 pour la présence de lien et 0 pour l'absence de lien entre deux circonscriptions.\n\nUne fois ces poids définis, nous pouvons vérifier avec le test de Moran s'il y a une autocorrélation significative des votes obtenus par la CAQ entre circonscriptions voisines.\n\n```{r}\npoids <- nb2listw(vois, style = \"B\")\n\nmoran.test(elect2018$propCAQ, poids)\n```\n\nLa valeur de $I = 0.68$ est très significative à en juger par la valeur $p$ du test.\n\nVérifions si la corrélation spatiale persiste après avoir tenu compte des quatre caractéristiques de la population, donc en inspectant les résidus d'un modèle linéaire incluant ces quatre prédicteurs.\n\n```{r}\nelect_lm <- lm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, data = elect2018)\nsummary(elect_lm)\nmoran.test(residuals(elect_lm), poids)\n```\n\nL'indice de Moran a diminué mais demeure significatif, donc une partie de la corrélation précédente était induite par ces prédicteurs, mais il reste une corrélation spatiale due à d'autres facteurs. \n\n## Modèles d'autorégression spatiale\n\nFinalement, nous ajustons des modèles SAR et CAR à ces données avec la fonction `spautolm` (*spatial autoregressive linear model*) de *spatialreg*. Voici le code pour un modèle SAR incluant l'effet des même quatre prédicteurs. \n\n```{r}\nelect_sar <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids)\nsummary(elect_sar)\n```\n\nLa valeur donnée par `Lambda` dans le sommaire correspond au coefficient $\\rho$ dans notre description du modèle. Le test du rapport de vraisemblance (`LR test`) confirme que cette corrélation spatiale résiduelle (après avoir tenu compte de l'effet des prédicteurs) est significative.\n\nLes effets estimés pour les prédicteurs sont semblables à ceux du modèle linéaire sans corrélation spatiale. Les effets de l'âge moyen, de la fraction de francophones et la fraction de propriétaires demeurent significatifs, bien que leur magnitude ait un peu diminué.\n\nPour évaluer un modèle CAR plutôt que SAR, nous devons spécifier `family = \"CAR\"`.\n\n```{r}\nelect_car <- spautolm(propCAQ ~ age_moy + pct_frn + pct_prp + rev_med, \n data = elect2018, listw = poids, family = \"CAR\")\nsummary(elect_car)\n```\n\nPour un modèle CAR avec des poids binaires, la valeur de `Lambda` (que nous avions appelé $\\rho$) donne directement le coefficient de corrélation partielle entre circonscriptions voisines. Notez que l'AIC ici est légèrement supérieur au modèle SAR, donc ce dernier donnait un meilleur ajustement.\n\n## Exercice\n\nLe jeu de données `rls_covid`, en format *shapefile*, contient des données sur les cas de COVID-19 détectés, le nombre de cas par 1000 personnes (`taux_1k`) et la densité de population (`dens_pop`) dans chacun des réseaux locaux de service de santé (RLS) du Québec. (Source: Données téléchargées de l'Institut national de santé publique du Québec en date du 17 janvier 2021.)\n\n```{r}\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nhead(rls_covid)\n```\n\nAjustez un modèle linéaire du nombre de cas par 1000 en fonction de la densité de population (il est suggéré d'appliquer une transformation logarithmique à cette dernière). Vérifiez si les résidus du modèle sont corrélés entre RLS limitrophes avec un test de Moran, puis modélisez les mêmes données avec un modèle autorégressif conditionnel.\n\n## Référence\n\nVer Hoef, J.M., Peterson, E.E., Hooten, M.B., Hanks, E.M. et Fortin, M.-J. (2018) Spatial autoregressive models for statistical inference from ecological data. *Ecological Monographs* 88: 36-59.\n\n\n# GLMM avec processus spatial gaussien {#glmm-spatial-gaussian-fr}\n\nDans les parties précédentes, nous avons vu comment tenir compte de la dépendance spatiale dans les modèles de régression linéaire avec des modèles géostatistiques (également appelés processus gaussiens) ou des modèles d'autocorrélation spatiale (CAR/SAR). Dans cette dernière partie, nous verrons comment combiner ces caractéristiques avec des modèles de régression plus complexes, en particulier les modèles linéaires généralisés à effets mixtes (GLMM).\n\n## Données\n\nLe jeu de données `gambia` inclus avec le package *geoR* présente les résultats d'une étude sur la prévalence du paludisme chez les enfants de 65 villages en Gambie. Nous utiliserons une version légèrement transformée des données contenues dans le fichier [gambia.csv](data/gambia.csv).\n\n```{r, warning = FALSE, message = FALSE}\nlibrary(geoR)\n\ngambia <- read.csv(\"data/gambia.csv\")\nhead(gambia)\n```\n\nVoici les champs de ce jeu de données:\n\n- *id_village*: Identifiant du village.\n- *x* and *y*: Coordonnées spatiales du village (en km, basé sur les coordonnées UTM).\n- *pos*: Réponse binaire, si l'enfant a eu un test positif du paludisme.\n- *age*: Âge de l'enfant en jours.\n- *netuse*: Si l'enfant dort sous un moustiquaire ou non.\n- *treated*: Si le moustiquaire est traité ou non.\n- *green*: Mesure de la végétation basée sur les données de télédétection (disponible à l'échelle du village).\n- *phc*: Présence ou absence d'un centre de santé publique pour le village.\n\nNous pouvons compter le nombre de cas positifs et le nombre total d'enfants testés par village pour cartographier la fraction des cas positifs (ou prévalence, *prev*).\n\n```{r}\n# Jeu de données à l'échelle du village\ngambia_agg <- group_by(gambia, id_village, x, y, green, phc) %>%\n summarize(pos = sum(pos), total = n()) %>%\n mutate(prev = pos / total) %>%\n ungroup()\nhead(gambia_agg)\n```\n\n\n```{r, message = FALSE, warning = FALSE}\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nNous utilisons le jeu de données `gambia.borders` du package *geoR* pour tracer les frontières des pays avec `geom_path`. Comme ces frontières sont en mètres, nous les divisons par 1000 pour obtenir la même échelle que nos points. Nous utilisons également `coord_fixed` pour assurer un rapport d'aspect de 1:1 entre les axes et utilisons la palette de couleur `viridis`, qui permet de visualiser plus facilement une variable continue par rapport à la palette par défaut dans *ggplot2*.\n\nSur la base de cette carte, il semble y avoir une corrélation spatiale dans la prévalence du paludisme, le groupe de villages de l'est montrant des valeurs de prévalence plus élevées (jaune-vert) et le groupe du milieu montrant des valeurs de prévalence plus faibles (violet).\n\n## GLMM non spatial\n\nPour ce premier exemple, nous allons ignorer l'aspect spatial des données et modéliser la présence du paludisme (*pos*) en fonction de l'utilisation d'une moustiquaire (*netuse*) et de la présence d'un centre de santé publique (*phc*). Comme nous avons une réponse binaire, nous devons utiliser un modèle de régression logistique (un GLM). Comme nous avons des prédicteurs au niveau individuel et au niveau du village et que nous nous attendons à ce que les enfants d'un même village aient une probabilité plus similaire d'avoir le paludisme même après avoir pris en compte ces prédicteurs, nous devons ajouter un effet aléatoire du village. Le résultat est un GLMM que nous ajustons en utilisant la fonction `glmer` du package *lme4*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(lme4)\n\nmod_glmm <- glmer(pos ~ netuse + phc + (1 | id_village), \n data = gambia, family = binomial)\nsummary(mod_glmm)\n```\n\nD'après ces résultats, les variables *netuse* et *phc* sont toutes deux associées à une diminution de la prévalence du paludisme, bien que l'effet de *phc* ne soit pas significatif à un seuil $\\alpha = 0.05$. L'ordonnée à l'origine (0.149) est le logit de la probabilité de présence du paludisme pour un enfant sans moustiquaire et sans centre de santé publique, mais c'est l'ordonnée à l'origine moyenne pour tous les villages. Il y a beaucoup de variation entre les villages selon l'écart-type de l'effet aléatoire (0.90). Nous pouvons obtenir l'ordonnée à l'origine estimée pour chaque village avec la fonction `coef`:\n\n```{r}\nhead(coef(mod_glmm)$id_village)\n```\n\nPar exemple, l'ordonnée à l'origine pour le village 1 est environ 0.94, équivalente à une probabilité de 72%:\n\n```{r}\nplogis(0.937)\n```\n\ntandis que celle pour le village 2 est équivalente à une probabilité de 52%:\n\n```{r}\nplogis(0.092)\n```\n\nLe [package DHARMa](https://cran.r-project.org/web/packages/DHARMa/vignettes/DHARMa.html) fournit une méthode générale pour vérifier si les résidus d'un GLMM sont distribués selon le modèle spécifié et s'il existe une tendance résiduelle. Il simule des réplicats de chaque observation selon le modèle ajusté et détermine ensuite un \"résidu standardisé\", qui est la position relative de la valeur observée par rapport aux valeurs simulées, par exemple 0 si l'observation est plus petite que toutes les simulations, 0.5 si elle se trouve au milieu, etc. Si le modèle représente bien les données, chaque valeur du résidu standardisé entre 0 et 1 doit avoir la même probabilité, de sorte que les résidus standardisés doivent produire une distribution uniforme entre 0 et 1.\n\nLa fonction `simulateResiduals` effectue le calcul des résidus standardisés, puis la fonction `plot` trace les graphiques de diagnostic avec les résultats de certains tests.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(DHARMa)\nres_glmm <- simulateResiduals(mod_glmm)\nplot(res_glmm)\n```\n\nLe graphique de gauche est un graphique quantile-quantile des résidus standardisés. Les résultats de trois tests statistiques sont également présentés: un test de Kolmogorov-Smirnov (*KS*) qui vérifie s'il y a un écart par rapport à la distribution théorique, un test de dispersion qui vérifie s'il y a une sous-dispersion ou une surdispersion et un test de valeurs aberrantes (*outlier*) basé sur le nombre de résidus qui sont plus extrêmes que toutes les simulations. Ici, nous obtenons un résultat significatif pour les valeurs aberrantes, bien que le message indique que ce résultat pourrait avoir un taux d'erreur de type I plus grand que prévu dans ce cas.\n\nÀ droite, nous obtenons généralement un graphique des résidus standardisés (en *y*) en fonction du rang des valeurs prédites, afin de vérifier l'absence de tendance résiduelle. Ici, les prédictions sont regroupées par quartile, il serait donc préférable d'agréger les prédictions et les résidus par village, ce que nous pouvons faire avec la fonction `recalculateResiduals`.\n\n```{r}\nplot(recalculateResiduals(res_glmm, group = gambia$id_village))\n```\n\nLe graphique de droite montre les points individuels, ainsi qu'une régression quantile pour le 1er quartile, la médiane et le 3e quartile. En théorie, ces trois courbes devraient être des lignes droites horizontales (pas de tendance des résidus par rapport aux prévisions). La courbe pour le 3e quartile (en rouge) est significativement différente d'une ligne horizontale, ce qui pourrait indiquer un effet systématique manquant dans le modèle.\n\n## GLMM spatial avec spaMM\n\nLe package *spaMM* (modèles mixtes spatiaux) est un package R relativement récent qui permet d'effectuer une estimation approximative du maximum de vraisemblance des paramètres pour les GLM avec dépendance spatiale, modélisés soit comme un processus gaussien, soit avec un CAR (nous verrons ce dernier dans la dernière section). Le package implémente différents algorithmes, mais il existe une fonction unique `fitme` qui choisit l'algorithme approprié pour chaque type de modèle. Par exemple, voici le même modèle (non spatial) que nous avons vu ci-dessus, ajusté avec *spaMM*.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spaMM)\n\nmod_spamm_glmm <- fitme(pos ~ netuse + phc + (1 | id_village),\n data = gambia, family = binomial)\nsummary(mod_spamm_glmm)\n```\n\nNotez que les estimés des effets fixes ainsi que la variance des effets aléatoires sont presque identiques à ceeux obtenues par `glmer` ci-dessus.\n\nNous pouvons maintenant utiliser *spaMM* pour ajuster le même modèle avec l'ajout de corrélations spatiales entre les villages. Dans la formule du modèle, ceci est représenté comme un effet aléatoire `Matern(1 | x + y)`, ce qui signifie que les ordonnées à l'origine sont spatialement corrélées entre les villages suivant une fonction de corrélation de Matérn des coordonnées (*x, y*). La fonction de Matérn est une fonction flexible de corrélation spatiale qui comprend un paramètre de forme $\\nu$ (`nu`), de sorte que lorsque $\\nu = 0,5$, elle est équivalente à la corrélation exponentielle, mais quand $\\nu$ prend de grandes valeurs, elle se rapproche d'une corrélation gaussienne. Nous pourrions laisser la fonction estimer $\\nu$, mais ici nous le fixons à 0.5 avec l'argument `fixed` de `fitme`.\n\n```{r}\nmod_spamm <- fitme(pos ~ netuse + phc + Matern(1 | x + y) + (1 | id_village),\n data = gambia, family = binomial, fixed = list(nu = 0.5))\nsummary(mod_spamm)\n```\n\nCommençons par vérifier les effets aléatoires du modèle. La fonction de corrélation spatiale a un paramètre `rho` égal à 0.0513. Ce paramètre dans *spaMM* est l'inverse de la portée, donc ici la portée de la corrélation exponentielle est de 1/0.0513 ou environ 19.5 km. Il y a maintenant deux pramètres de variance, celui identifié comme `x + y` est la variance à longue distance (i.e. le palier) pour le modèle de corrélation exponentielle alors que celui identifié comme `id_village` montre la portion non corrélée de la variation entre les villages.\n\nSi nous avions ici laissé les effets aléatoires `(1 | id_village)` dans la formule pour représenter la partie non spatiale de la variation entre les villages, nous pourrions également représenter ceci avec un effet de pépite dans le modèle géostatistique. Dans les deux cas, cela représenterait l'idée que même deux villages très proches l'un de l'autre auraient des prévalences de base différentes dans le modèle.\n\nPar défaut, la fonction `Matern` n'a pas d'effet de pépite, mais nous pouvons en ajouter un en spécifiant une `pépite` non nulle dans la liste initiale des paramètres `init`.\n\n```{r}\nmod_spamm2 <- fitme(pos ~ netuse + phc + Matern(1 | x + y),\n data = gambia, family = binomial, fixed = list(nu = 0.5),\n init = list(Nugget = 0.1))\nsummary(mod_spamm2)\n```\n\nComme vous pouvez le voir, toutes les estimations sont les mêmes, sauf que la variance de la portion spatiale (palier) est maintenant de 0.84 et que la pépite est égale à une fraction 0.235 de ce palier, soit une variance de 0.197, ce qui est identique à l'effet aléatoire `id_village` dans la version ci-dessus. Les deux formulations sont donc équivalentes.\n\nMaintenant, rappelons les coefficients que nous avions obtenus pour le GLMM non spatial :\n\n```{r}\nsummary(mod_glmm)$coefficients\n```\n\nDans la version spatiale, les deux effets fixes se sont légèrement rapprochés de zéro, mais l'erreur-type de l'effet de `phc` a diminué. Il est intéressant de noter que l'inclusion de la dépendance spatiale nous a permis d'estimer plus précisément l'effet de la présence d'un centre de santé publique dans le village. Ce ne serait pas toujours le cas: pour un prédicteur qui est également fortement corrélé dans l'espace, la corrélation spatiale dans la réponse rend plus difficile l'estimation de l'effet de ce prédicteur, puisqu'il est confondu avec l'effet spatial. Cependant, pour un prédicteur qui n'est pas corrélé dans l'espace, l'inclusion de l'effet spatial réduit la variance résiduelle (non spatiale) et peut donc augmenter la précision de l'effet du prédicteur.\n\nLe package *spaMM* est également compatible avec *DHARMa* pour les diagnostics résiduels. (Vous pouvez ignorer l'avertissement selon lequel il ne fait pas partie de la classe des modèles pris en charge, cela est dû à l'utilisation de la fonction `fitme` plutôt que d'une fonction d'algorithme spécifique dans *spaMM*).\n\n```{r}\nres_spamm <- simulateResiduals(mod_spamm2)\nplot(res_spamm)\nplot(recalculateResiduals(res_spamm, group = gambia$id_village))\n```\n\nEnfin, bien que nous allons montrer comment calculer et visualiser des prédictions spatiales ci-dessous, nous pouvons produire une carte rapide des effets spatiaux estimés dans un modèle *spaMM* avec la fonction `filled.mapMM`.\n\n```{r}\nfilled.mapMM(mod_spamm2)\n```\n\n## Processus gaussiens vs. splines de lissage\n\nSi vous connaissez bien les modèles additifs généralisés (GAM), vous avez peut-être pensé à représenter la variation spatiale de la prévalence du paludisme (comme le montre la carte ci-dessus) par une spline de lissage en 2D (en fonction de $x$ et $y$) dans un GAM.\n\nLe code ci-dessous correspond à l'équivalent GAM de notre GLMM avec processus gaussien ci-dessus, ajusté avec la fonction `gam` du package *mgcv*. L'effet spatial est représenté par la spline 2D `s(x, y)` alors que l'effet aléatoire non spatial de village est représenté par `s(id_village, bs = \"re\")`, qui est équivalent à `(1 | id_village)` dans les modèles précédents. Notez que pour la fonction `gam`, les variables catégorielles doivent être explicitement converties en facteurs.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(mgcv)\ngambia$id_village <- as.factor(gambia$id_village)\nmod_gam <- gam(pos ~ netuse + phc + s(id_village, bs = \"re\") + s(x, y), \n data = gambia, family = binomial)\n```\n\nPour visualiser la spline en 2D, nous utiliserons le package [*gratia*](https://fromthebottomoftheheap.net/2018/10/23/introducing-gratia/).\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(gratia)\ndraw(mod_gam)\n```\n\nNotez que le graphique de la spline `s(x, y)` (en haut à droite) ne s'étend pas trop loin des emplacements des données (les autres zones sont vides). Dans ce graphique, on peut également voir que les effets aléatoires des villages suivent la distribution gaussienne attendue (en haut à gauche).\n\nEnsuite, nous utiliserons à la fois le GLMM spatial de la section précédente et ce GAMM pour prédire la prévalence moyenne sur une grille spatiale de points contenue dans le fichier [gambia_pred.csv](data/gambia_pred.csv). Le graphique ci-dessous ajoute ces points de prédiction (en noir) sur la carte précédente des points de données.\n\n```{r, message = FALSE, warning = FALSE}\ngambia_pred <- read.csv(\"data/gambia_pred.csv\")\n\nggplot(gambia_agg, aes(x = x, y = y)) +\n geom_point(data = gambia_pred) +\n geom_point(aes(color = prev)) +\n geom_path(data = gambia.borders, aes(x = x / 1000, y = y / 1000)) +\n coord_fixed() +\n theme_minimal() +\n scale_color_viridis_c()\n```\n\nPour faire des prédictions à partir du modèle GAMM à ces endroits, le code ci-dessous effectue les étapes suivantes:\n\n- Tous les prédicteurs du modèle doivent se trouver dans le tableau de données de prédiction, nous ajoutons donc des valeurs constantes de *netuse* et *phc* (toutes deux égales à 1) pour tous les points. Ainsi, nous ferons des prédictions sur la prévalence du paludisme dans le cas où un moustiquaire est utilisée et où un centre de santé publique est présent. Nous ajoutons également un *id_village* constant, bien qu'il ne soit pas utilisé dans les prédictions (voir ci-dessous).\n\n- Nous appelons la fonction `predict` à la sortie de `gam` pour produire des prédictions aux nouveaux points de données (argument `newdata`), en incluant les erreurs-types (`se.fit = TRUE`) et en excluant les effets aléatoires du village, donc la prédiction est faite pour un \"village moyen\". L'objet résultant `gam_pred` aura des colonnes `fit` (prédiction moyenne) et `se.fit` (erreur-type). Ces prédictions et erreurs-types sont sur l'échelle du lien (logit).\n\n- Nous rattachons le jeu de données de prédiction original à `gam_pred` avec `cbind`. \n\n- Nous ajoutons des colonnes pour la prédiction moyenne et les limites de l'intervalle de confiance à 50% (moyenne $\\pm$ 0.674 erreur-type), converties de l'échelle logit à l'échelle de probabilité avec `plogis`. Nous choisissons un intervalle de 50% car un intervalle de 95% peut être trop large ici pour contraster les différentes prédictions sur la carte à la fin de cette section.\n\n```{r}\ngambia_pred <- mutate(gambia_pred, netuse = 1, phc = 1, id_village = 1)\n\ngam_pred <- predict(mod_gam, newdata = gambia_pred, se.fit = TRUE, \n exclude = \"s(id_village)\")\ngam_pred <- cbind(gambia_pred, as.data.frame(gam_pred))\ngam_pred <- mutate(gam_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit), # 50% CI\n hi = plogis(fit + 0.674 * se.fit))\n```\n\n*Note* : La raison pour laquelle nous ne faisons pas de prédictions directement sur l'échelle de probabilité (réponse) est que la formule normale des intervalles de confiance s'applique plus précisément sur l'échelle logit. L'ajout d'un certain nombre d'erreurs-types autour de la moyenne sur l'échelle de probabilité conduirait à des intervalles moins précis et peut-être même à des intervalles de confiance en dehors de la plage de valeurs possible (0, 1) pour une probabilité.\n\nNous appliquons la même stratégie pour faire des prédictions à partir du GLMM spatial avec *spaMM*. Il y a quelques différences dans la méthode `predict` par rapport au cas du GAMM.\n\n- L'argument `binding = \"fit\"` signifie que les prédictions moyennes (colonne `fit`) seront attachées à l'ensemble de données de prédiction et retournées sous forme de tableau de données `spamm_pred`.\n\n- L'argument `variances = list(linPred = TRUE)` indique à `predict` de calculer la variance du prédicteur linéaire (donc le carré de l'erreur-type). Cependant, il apparaît comme un attribut `predVar` dans le tableau de données de sortie plutôt que dans une colonne `se.fit`, donc nous le déplaçons vers une colonne sur la ligne suivante. \n\n```{r}\nspamm_pred <- predict(mod_spamm, newdata = gambia_pred, type = \"link\",\n binding = \"fit\", variances = list(linPred = TRUE))\nspamm_pred$se.fit <- sqrt(attr(spamm_pred, \"predVar\"))\nspamm_pred <- mutate(spamm_pred, pred = plogis(fit), \n lo = plogis(fit - 0.674 * se.fit),\n hi = plogis(fit + 0.674 * se.fit))\n```\n\nEnfin, nous combinons les deux ensembles de prédictions sous la forme de différentes rangées d'un tableau de données `pred_all` avec `bind_rows`. Le nom du tableau de données d'où provient chaque prédiction (`gam` ou `spamm`) apparaîtra dans la colonne \"model\" (argument `.id`). Pour simplifier la production du prochain graphique, nous utilisons ensuite `pivot_longer` dans le package *tidyr* pour changer les trois colonnes \"pred\", \"lo\" et \"hi\" en deux colonnes, \"stat\" et \"value\" (`pred_tall` a donc trois rangées pour chaque rangée dans `pred_all`).\n\n```{r}\npred_all <- bind_rows(gam = gam_pred, spamm = spamm_pred, .id = \"model\")\n\nlibrary(tidyr)\npred_tall <- pivot_longer(pred_all, c(pred, lo, hi), names_to = \"stat\",\n values_to = \"value\")\n```\n\nUne fois ces étapes franchies, nous pouvons enfin examiner les cartes de prédiction (moyenne, limites inférieure et supérieure de l'intervalle de confiance à 50 %) à l'aide d'un graphique `ggplot`. Les points de données originaux sont indiqués en rouge.\n\n```{r}\nggplot(pred_tall, aes(x = x, y = y)) +\n geom_point(aes(color = value)) +\n geom_point(data = gambia_agg, color = \"red\", size = 0) +\n coord_fixed() +\n facet_grid(stat~model) +\n scale_color_viridis_c() +\n theme_minimal()\n```\n\nBien que les deux modèles s'accordent à dire que la prévalence est plus élevée près du groupe de villages de l'est, le GAMM estime également une prévalence plus élevée en quelques points (bord ouest et autour du centre) où il n'y a pas de données. Il s'agit d'un artefact de la forme de la spline autour des points de données, puisqu'une spline est censée correspondre à une tendance globale, bien que non linéaire. En revanche, le modèle géostatistique représente l'effet spatial sous forme de corrélations locales et revient à la prévalence moyenne globale lorsqu'il est éloigné de tout point de données, ce qui est une supposition plus sûre. C'est l'une des raisons pour lesquelles il est préférable de choisir un modèle géostatistique / processus gaussien dans ce cas.\n\n## Méthodes bayésiennes pour les GLMM avec processus gaussiens\n\nLes modèles bayésiens fournissent un cadre flexible pour exprimer des modèles avec une structure de dépendance complexe entre les données, y compris la dépendance spatiale. Cependant, l'ajustement d'un modèle de processus gaussien avec une approche entièrement bayésienne peut être lent, en raison de la nécessité de calculer une matrice de covariance spatiale entre toutes les paires de points à chaque itération. \n\nLa méthode INLA (pour *integrated nested Laplace approximation*) effectue un calcul approximatif de la distribution postérieure bayésienne, ce qui la rend adaptée aux problèmes de régression spatiale. Nous ne l'abordons pas dans ce cours, mais je recommande le manuel de Paula Moraga (dans la section des références ci-dessous) qui fournit des exemples concrets d'utilisation de la méthode INLA pour divers modèles de données géostatistiques et aréales, dans le contexte de l'épidémiologie, y compris des modèles avec une dépendance à la fois spatiale et temporelle. Le livre présente les mêmes données sur le paludisme en Gambie comme exemple d'un ensemble de données géostatistiques, ce qui a inspiré son utilisation dans ce cours.\n\n# GLMM avec autorégression spatiale {#glmm-spatial-autoreg-fr}\n\nNous revenons au dernier exemple de la partie précédente, où nous avions modélisé le taux de cas de COVID-19 (cas / 1000) pour les divisions administratives du réseau de la santé (RLS) au Québec en fonction de leur densité de population. Le taux est donné par la colonne \"taux_1k\" dans le *shapefile* `rls_covid`.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(sf)\nrls_covid <- read_sf(\"data/rls_covid.shp\")\nrls_covid <- rls_covid[!is.na(rls_covid$dens_pop), ]\nplot(rls_covid[\"taux_1k\"])\n```\n\nAuparavant, nous avions modélisé le logarithme de ce taux comme une fonction linéaire du logarithme de la densité de population, la variance résiduelle étant corrélée entre les unités voisines via une structure CAR (autorégression conditionnelle), comme le montre le code ci-dessous.\n\n```{r, message = FALSE, warning = FALSE}\nlibrary(spdep)\nlibrary(spatialreg)\n\nrls_nb <- poly2nb(rls_covid)\nrls_w <- nb2listw(rls_nb, style = \"B\")\n\ncar_lm <- spautolm(log(taux_1k) ~ log(dens_pop), data = rls_covid,\n listw = rls_w, family = \"CAR\")\nsummary(car_lm)\n```\n\n*Rappel*: La fonction `poly2nb` du package *spdep* crée une liste de voisins basée sur les polygones limitrophes dans un *shapefile*, puis `nb2listw` la convertit en une liste de poids, ici des poids binaires (`style = \"B\"`) de sorte que chaque région limitrophe reçoive le même poids de 1 dans le modèle autorégressif.\n\nAu lieu d'utiliser les taux, il serait possible de modéliser directement les cas avec une régression de Poisson, qui est appropriée pour les données de comptage. Pour tenir compte du fait que si le risque par personne était égal, les cas seraient proportionnels à la population, nous pouvons ajouter la population de l'unité `pop` comme *offset* dans la régression de Poisson. Par conséquent, le modèle ressemblerait à : `cas ~ log(dens_pop) + offset(log(pop))`. Notez que puisque la régression de Poisson utilise un lien logarithmique, ce modèle avec `log(pop)` comme *offset* suppose que `log(cas / pop)` (donc le taux logarithmique) est proportionnel à `log(dens_pop)`, tout comme le modèle linéaire ci-dessus, mais il a l'avantage de modéliser la variabilité des données brutes (le nombre de cas) directement avec une distribution de Poisson.\n\nNous n'avons pas la population dans ces données, mais nous pouvons l'estimer à partir des cas et du taux (cas / 1000) comme suit:\n\n```{r}\nrls_covid$pop <- rls_covid$cas / rls_covid$taux_1k * 1000\n```\n\nPour définir un modèle CAR dans *spaMM*, nous avons besoin d'une matrice de poids plutôt que d'une liste de poids comme dans le package *spatialreg*. Heureusement, le package *spdep* comprend également une fonction `nb2mat` pour convertir la liste des voisins en une matrice de poids, là encore en utilisant des poids binaires. Pour éviter un avertissement dans R, nous spécifions que les noms des lignes et des colonnes de cette matrice doivent être égaux aux identifiants associés à chaque unité (`RLS_code`). Ensuite, nous ajoutons un terme `adjacency(1 | RLS_code)` au modèle pour spécifier que la variation résiduelle entre les différents groupes définis par `RLS_code` est spatialement corrélée avec une structure CAR (ici, chaque groupe n'a qu'une observation puisque nous avons un point de données par unité RLS).\n\n```{r}\nlibrary(spaMM)\n\nrls_mat <- nb2mat(rls_nb, style = \"B\")\nrownames(rls_mat) <- rls_covid$RLS_code\ncolnames(rls_mat) <- rls_covid$RLS_code\n\nrls_spamm <- fitme(cas ~ log(dens_pop) + offset(log(pop)) + adjacency(1 | RLS_code),\n data = rls_covid, adjMatrix = rls_mat, family = poisson)\nsummary(rls_spamm)\n```\n\nNotez que le coefficient de corrélation spatiale `rho` (0.158) est similaire à la quantité équivalente dans le modèle `spautolm` ci-dessus, où il était appelé `Lambda`. L'effet de `log(dens_pop)` est également d'environ 0.2 dans les deux modèles.\n\n\n## Référence\n\nMoraga, Paula (2019) Geospatial Health Data: Modeling and Visualization with R-INLA and Shiny. Chapman & Hall/CRC Biostatistics Series. Disponible en ligne: [https://www.paulamoraga.com/book-geospatial/](https://www.paulamoraga.com/book-geospatial/). \n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":true,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"knitr"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Spatial Statistics in Ecology","description":"Training session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). |\nSession de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n","author":"Philippe Marchand","categories":["FR","EN","Technical"],"date":"2021-01-12","image":"image.jpg","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file diff --git a/.quarto/idx/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd.json b/.quarto/idx/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd.json index c62b37b..f9258d2 100644 --- a/.quarto/idx/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd.json +++ b/.quarto/idx/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd.json @@ -1 +1 @@ -{"title":"Introduction to EDI concepts in a scientific context","markdown":{"yaml":{"title":"Introduction to EDI concepts in a scientific context","description":"A short introduction to EDI concepts in a scientific context.\n","author":[{"name":"Agathe Riallan","affiliation":"Faculté des Sciences à Université de Sherbrooke"},{"name":"Marie-José Naud","affiliation":"Centre d’études nordiques (CEN)"}],"categories":["Transversal competencies","FR","EN"],"date":"01-22-2021","image":"image.jpg","toc":true,"number-sections":true,"number-depth":1},"headingText":"Introduction to EDI concepts in a scientific context","containsRefs":false,"markdown":"\n\nTexte en français [à la suite](#introduction-aux-concepts-edi-en-contexte-scientifique).\n\n\nIn 2021, the BIOS2 training program will be holding a series of training and reflection activities on equity, diversity and inclusion issues. The goal is to develop an EDI action plan for the program in order to consolidate a more inclusive, respectful and open environment.\n\nThe objectives of this workshop are:\n\n- Define the concepts of equity, diversity and inclusion\n- Identify the benefits and challenges of EDI in the university context\n- Recongnize how to become an EDI bearer during one's university career\n- Raise awareness of intercultural communication (professional competence of tomorrow)\n\nThe workshop is developed by Agathe Riallan, Faculty Coordinator for Equity, Diversity and Inclusion (EDI) at the Faculty of Science, Université de Sherbrooke, in collaboration with Marie-José Naud, Equity, Diversity and Inclusion Advisor and Coordinator at the Centre d'études nordiques (CEN).\n\n\n\n




\n\n------------------------------------------------------------------------\n\n# Introduction aux concepts EDI en contexte scientifique {#introduction-aux-concepts-edi-en-contexte-scientifique}\n\nEn 2021, nous aurons une série de formations et d'activités de réflexion sur les questions d'équité, diversité et d'inclusion. Notre objectif est de mettre en place un plan d'action EDI pour le programme afin de consolider un environnement plus inclusif, respectueux et ouvert.\n\nLes objectifs de cet ateliers sont:\n\n- Définir les concepts d'équité, de diversité et d'inclusion\n- Identifier les avantages et les défis de l'ÉDI en contexte universitaire\n- Identifier comment être porteuse ou porteur de l'ÉDI lors de son parcours universitaire\n- Se sensibiliser à la communication interculturelle (compétence professionnelle de demain)\n\nL'atelier est développé par Agathe Riallan, Coordinatrice facultaire de l'Équité, de la Diversité et de l'Inclusion (ÉDI) de la Faculté des Sciences à Université de Sherbrooke, en collaboration avec Marie-José Naud, Conseillère en équité, diversité et inclusion et coordonnatrice au Centre d'études nordiques (CEN).\n\n\n\n



\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Introduction to EDI concepts in a scientific context","description":"A short introduction to EDI concepts in a scientific context.\n","author":[{"name":"Agathe Riallan","affiliation":"Faculté des Sciences à Université de Sherbrooke"},{"name":"Marie-José Naud","affiliation":"Centre d’études nordiques (CEN)"}],"categories":["Transversal competencies","FR","EN"],"date":"01-22-2021","image":"image.jpg","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file +{"title":"Introduction to EDI Concepts in a Scientific Context","markdown":{"yaml":{"title":"Introduction to EDI Concepts in a Scientific Context","description":"A short introduction to EDI concepts in a scientific context.\n","author":[{"name":"Agathe Riallan","affiliation":"Faculté des Sciences à Université de Sherbrooke"},{"name":"Marie-José Naud","affiliation":"Centre d’études nordiques (CEN)"}],"categories":["Transversal competencies","FR","EN"],"date":"01-22-2021","image":"image.jpg","toc":true,"number-sections":true,"number-depth":1},"headingText":"Introduction to EDI Concepts in a Scientific Context","containsRefs":false,"markdown":"\n\nTexte en français [à la suite](#introduction-aux-concepts-edi-en-contexte-scientifique).\n\n\nIn 2021, the BIOS2 training program will be holding a series of training and reflection activities on equity, diversity and inclusion issues. The goal is to develop an EDI action plan for the program in order to consolidate a more inclusive, respectful and open environment.\n\nThe objectives of this workshop are:\n\n- Define the concepts of equity, diversity and inclusion\n- Identify the benefits and challenges of EDI in the university context\n- Recongnize how to become an EDI bearer during one's university career\n- Raise awareness of intercultural communication (professional competence of tomorrow)\n\nThe workshop is developed by Agathe Riallan, Faculty Coordinator for Equity, Diversity and Inclusion (EDI) at the Faculty of Science, Université de Sherbrooke, in collaboration with Marie-José Naud, Equity, Diversity and Inclusion Advisor and Coordinator at the Centre d'études nordiques (CEN).\n\n\n\n




\n\n------------------------------------------------------------------------\n\n# Introduction aux concepts EDI en contexte scientifique {#introduction-aux-concepts-edi-en-contexte-scientifique}\n\nEn 2021, nous aurons une série de formations et d'activités de réflexion sur les questions d'équité, diversité et d'inclusion. Notre objectif est de mettre en place un plan d'action EDI pour le programme afin de consolider un environnement plus inclusif, respectueux et ouvert.\n\nLes objectifs de cet ateliers sont:\n\n- Définir les concepts d'équité, de diversité et d'inclusion\n- Identifier les avantages et les défis de l'ÉDI en contexte universitaire\n- Identifier comment être porteuse ou porteur de l'ÉDI lors de son parcours universitaire\n- Se sensibiliser à la communication interculturelle (compétence professionnelle de demain)\n\nL'atelier est développé par Agathe Riallan, Coordinatrice facultaire de l'Équité, de la Diversité et de l'Inclusion (ÉDI) de la Faculté des Sciences à Université de Sherbrooke, en collaboration avec Marie-José Naud, Conseillère en équité, diversité et inclusion et coordonnatrice au Centre d'études nordiques (CEN).\n\n\n\n



\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"markdown"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Introduction to EDI Concepts in a Scientific Context","description":"A short introduction to EDI concepts in a scientific context.\n","author":[{"name":"Agathe Riallan","affiliation":"Faculté des Sciences à Université de Sherbrooke"},{"name":"Marie-José Naud","affiliation":"Centre d’études nordiques (CEN)"}],"categories":["Transversal competencies","FR","EN"],"date":"01-22-2021","image":"image.jpg","number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file diff --git a/.quarto/idx/posts/2021-05-04-building-r-packages/index.qmd.json b/.quarto/idx/posts/2021-05-04-building-r-packages/index.qmd.json index 0dfa0d4..c71cadb 100644 --- a/.quarto/idx/posts/2021-05-04-building-r-packages/index.qmd.json +++ b/.quarto/idx/posts/2021-05-04-building-r-packages/index.qmd.json @@ -1 +1 @@ -{"title":"Building R packages","markdown":{"yaml":{"title":"Building R packages","description":"This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n","author":"Andrew MacDonald","date":"2021-05-04","image":"altumcode-PNbDkQ2DDgM-unsplash.jpeg","categories":["Technical","EN"],"toc":true,"number-sections":true,"number-depth":1},"headingText":"*Mise en place* : development environment","containsRefs":false,"markdown":"\n\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(echo = FALSE)\n```\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles taht R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n```{r}\nusethis::use_build_ignore(\"development.R\")\n```\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"knitr"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Building R packages","description":"This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n","author":"Andrew MacDonald","date":"2021-05-04","image":"altumcode-PNbDkQ2DDgM-unsplash.jpeg","categories":["Technical","EN"],"number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file +{"title":"Building R packages","markdown":{"yaml":{"title":"Building R packages","description":"This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n","author":"Andrew MacDonald","date":"2021-05-04","image":"altumcode-PNbDkQ2DDgM-unsplash.jpeg","categories":["Technical","EN"],"toc":true,"number-sections":true,"number-depth":1},"headingText":"*Mise en place* : development environment","containsRefs":false,"markdown":"\n\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(echo = FALSE, message = FALSE)\n```\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles that R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n```{r, message=FALSE}\nusethis::use_build_ignore(\"development.R\")\n```\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n"},"formats":{"html":{"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"knitr"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[]},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["../../styles.css"],"toc":true,"number-sections":true,"output-file":"index.html"},"language":{},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.2.253","editor":"source","theme":"flatly","title-block-banner":true,"title":"Building R packages","description":"This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n","author":"Andrew MacDonald","date":"2021-05-04","image":"altumcode-PNbDkQ2DDgM-unsplash.jpeg","categories":["Technical","EN"],"number-depth":1},"extensions":{"book":{"multiFile":true}}}}} \ No newline at end of file diff --git a/.quarto/xref/1893bfdc b/.quarto/xref/1893bfdc index 6abc991..8cb276d 100644 --- a/.quarto/xref/1893bfdc +++ b/.quarto/xref/1893bfdc @@ -1 +1 @@ -{"entries":[],"headings":["instructor","outline","get-course-materials","install-required-software","get-the-notes","useful-resources","references","license"]} \ No newline at end of file +{"headings":["instructor","outline","get-course-materials","install-required-software","get-the-notes","useful-resources","references","license"],"entries":[]} \ No newline at end of file diff --git a/.quarto/xref/442bc2ed b/.quarto/xref/442bc2ed index fafdf78..c4b6de6 100644 --- a/.quarto/xref/442bc2ed +++ b/.quarto/xref/442bc2ed @@ -1 +1 @@ -{"headings":["spatial-statistics-in-ecology","course-outline","introduction","types-of-spatial-analyses","stationarity-and-isotropy","georeferenced-data","point-pattern","point-pattern-and-point-process","complete-spatial-randomness","exploratory-or-inferential-analysis-for-a-point-pattern","ripleys-k-function","edge-effects","example","exercise-1","effect-of-heterogeneity","exercise-2","relationship-between-two-point-patterns","questions","marked-point-patterns","references","solutions","exercise-1-1","exercise-2-1","spatial-correlation","intrinsic-or-induced-dependence","different-ways-to-model-spatial-effects","geostat-models","variogram","theoretical-models-for-the-variogram","empirical-variogram","regression-model-with-spatial-correlation","geostatistical-models-in-r","regression-with-spatial-correlation","exercise","kriging","solutions-1","areal-data","moran-i","spatial-autoreg","conditional-autoregressive-car-model","simultaneous-autoregressive-sar-model","analysis-areal","definition-of-the-neighbourhood-network","spatial-autoregression-models","exercise-3","reference","glmm-spatial-gaussian","data","non-spatial-glmm","spatial-glmm-with-spamm","gaussian-process-models-vs.-smoothing-splines","bayesian-methods-for-glmms-with-gaussian-processes","glmm-spatial-autoreg","reference-1","statistiques-spatiales-en-écologie","plan-du-cours","introduction-fr","types-danalyses-spatiales","stationnarité-et-isotropie","données-géoréférencées","point-pattern-fr","patron-de-points-et-processus-ponctuel","structure-spatiale-totalement-aléatoire","analyse-exploratoire-ou-inférentielle-pour-un-patron-de-points","indice-k-de-ripley","effets-de-bordure","exemple","exercice-1","effet-de-lhétérogénéité","exercice-2","relation-entre-deux-patrons-de-points","questions-1","patrons-de-points-marqués","références","solutions-2","exercice-1-1","exercice-2-1","spatial-correlation-fr","dépendance-intrinsèque-ou-induite","différentes-façons-de-modéliser-les-effets-spatiaux","geostat-models-fr","variogramme","modèles-théoriques-du-variogramme","variogramme-empirique","modèle-de-régression-avec-corrélation-spatiale","modèles-géostatistiques-dans-r","régression-avec-corrélation-spatiale","exercice","krigeage","solutions-3","areal-data-fr","moran-i-fr","spatial-autoreg-fr","autorégression-conditionnelle-car","autorégression-simultanée-sar","analysis-areal-fr","définition-du-réseau-de-voisinage","modèles-dautorégression-spatiale","exercice-3","référence","glmm-spatial-gaussian-fr","données","glmm-non-spatial","glmm-spatial-avec-spamm","processus-gaussiens-vs.-splines-de-lissage","méthodes-bayésiennes-pour-les-glmm-avec-processus-gaussiens","glmm-spatial-autoreg-fr","référence-1"],"entries":[]} \ No newline at end of file +{"entries":[],"headings":["spatial-statistics-in-ecology","course-outline","introduction","types-of-spatial-analyses","stationarity-and-isotropy","georeferenced-data","point-pattern","point-pattern-and-point-process","complete-spatial-randomness","exploratory-or-inferential-analysis-for-a-point-pattern","ripleys-k-function","edge-effects","example","exercise-1","effect-of-heterogeneity","exercise-2","relationship-between-two-point-patterns","questions","marked-point-patterns","references","solutions","exercise-1-1","exercise-2-1","spatial-correlation","intrinsic-or-induced-dependence","different-ways-to-model-spatial-effects","geostat-models","variogram","theoretical-models-for-the-variogram","empirical-variogram","regression-model-with-spatial-correlation","geostatistical-models-in-r","regression-with-spatial-correlation","exercise","kriging","solutions-1","areal-data","moran-i","spatial-autoreg","conditional-autoregressive-car-model","simultaneous-autoregressive-sar-model","analysis-areal","definition-of-the-neighbourhood-network","spatial-autoregression-models","exercise-3","reference","glmm-spatial-gaussian","data","non-spatial-glmm","spatial-glmm-with-spamm","gaussian-process-models-vs.-smoothing-splines","bayesian-methods-for-glmms-with-gaussian-processes","glmm-spatial-autoreg","reference-1","statistiques-spatiales-en-écologie","plan-du-cours","introduction-fr","types-danalyses-spatiales","stationnarité-et-isotropie","données-géoréférencées","point-pattern-fr","patron-de-points-et-processus-ponctuel","structure-spatiale-totalement-aléatoire","analyse-exploratoire-ou-inférentielle-pour-un-patron-de-points","indice-k-de-ripley","effets-de-bordure","exemple","exercice-1","effet-de-lhétérogénéité","exercice-2","relation-entre-deux-patrons-de-points","questions-1","patrons-de-points-marqués","références","solutions-2","exercice-1-1","exercice-2-1","spatial-correlation-fr","dépendance-intrinsèque-ou-induite","différentes-façons-de-modéliser-les-effets-spatiaux","geostat-models-fr","variogramme","modèles-théoriques-du-variogramme","variogramme-empirique","modèle-de-régression-avec-corrélation-spatiale","modèles-géostatistiques-dans-r","régression-avec-corrélation-spatiale","exercice","krigeage","solutions-3","areal-data-fr","moran-i-fr","spatial-autoreg-fr","autorégression-conditionnelle-car","autorégression-simultanée-sar","analysis-areal-fr","définition-du-réseau-de-voisinage","modèles-dautorégression-spatiale","exercice-3","référence","glmm-spatial-gaussian-fr","données","glmm-non-spatial","glmm-spatial-avec-spamm","processus-gaussiens-vs.-splines-de-lissage","méthodes-bayésiennes-pour-les-glmm-avec-processus-gaussiens","glmm-spatial-autoreg-fr","référence-1"]} \ No newline at end of file diff --git a/.quarto/xref/a07a8c4b b/.quarto/xref/a07a8c4b index 9d3d9c7..1acf430 100644 --- a/.quarto/xref/a07a8c4b +++ b/.quarto/xref/a07a8c4b @@ -1 +1 @@ -{"entries":[],"headings":["why-do-you-want-to-use-shiny","hello-shiny","how-a-shiny-app-works","building-blocks","ids","organisation","plots","user-interface","server","the-shiny-app","customising-the-theme","using-built-in-themes","using-a-custom-theme","customizing-a-theme","constructing-a-shiny-app-using-shinydashboards","taking-advantage-of-good-defaults","using-shinydashboard","populating-the-layout","challenge","see-the-completed-app","constructing-a-shiny-app-using-golem","golem-modules","selecting-the-volcanoes","barplot-of-continents"]} \ No newline at end of file +{"headings":["why-do-you-want-to-use-shiny","hello-shiny","how-a-shiny-app-works","building-blocks","ids","organisation","plots","user-interface","server","the-shiny-app","customising-the-theme","using-built-in-themes","using-a-custom-theme","customizing-a-theme","constructing-a-shiny-app-using-shinydashboards","taking-advantage-of-good-defaults","using-shinydashboard","populating-the-layout","challenge","see-the-completed-app","constructing-a-shiny-app-using-golem","golem-modules","selecting-the-volcanoes","barplot-of-continents"],"entries":[]} \ No newline at end of file diff --git a/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json b/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json index f40d397..5d646d1 100644 --- a/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json +++ b/_freeze/posts/2021-05-04-building-r-packages/index/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "df96dd7b0c06e257f0066e58be1df75f", + "hash": "2759d1707cdb7cd48df6fad351b0353b", "result": { - "markdown": "---\ntitle: \"Building R packages\"\ndescription: |\n This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\nauthor: Andrew MacDonald\ndate: \"2021-05-04\"\ncategories: [Technical, EN]\ntoc: true\nnumber-sections: true\nnumber-depth: 1\n---\n\n\n\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n### *Mise en place* : development environment\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles taht R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stderr}\n```\n✔ Setting active project to '/Users/katherine/Documents/GitHub/bios2.github.io-quarto'\n✔ Adding '^development\\\\.R$' to 'posts/2021-05-04-building-r-packages/.Rbuildignore'\n```\n:::\n:::\n\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n", + "markdown": "---\ntitle: \"Building R packages\"\ndescription: |\n This practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\nauthor: Andrew MacDonald\ndate: \"2021-05-04\"\nimage: altumcode-PNbDkQ2DDgM-unsplash.jpeg\ncategories: [Technical, EN]\ntoc: true\nnumber-sections: true\nnumber-depth: 1\n---\n\n\n\n\n\n\n

via GIPHY

\n\nR packages! they are kind of like cookies:\n\n- Almost everyone enjoys them\n\n- delicious when homemade\n\n- Lots of storebought options available\n\n- Great skill to have\n\n- not necessary to sell them!\n\n \n\nBut most of all: cookies are delicious for what they *contain*: chocolate chunks, candy, oats, cocoa. However, all cookies share some fundamental ingredients and nearly identical structure. Flour, saturated with fat and sugar hydrated only with an egg, flavoured with vanilla and salt. The basic formula is invariant and admits only slight deviation -- otherwise, it becomes something other than a cookie.\n\nThis workshop is devoted to the study of cookie dough.\n\n### *Mise en place* : development environment\n\nWe'll explore a few useful packages in this workshop. The first two in particular are very popular tools for modern-day R package development:\n\n``` r\ninstall.packages(\"devtools\")\ninstall.packages(\"usethis\")\ninstall.packages(\"testthat\")\ninstall.packages(\"assertthat\")\n```\n\nBuilding an R package also requires specific tools for compiling the finished package. Run the following line to make sure you have the development environment:\n\n``` r\ndevtools::has_devel()\n```\n\nIf you do not have the software to build R packages, you should see a message which will help you find the correct links to download what you need!\n\nWindows will need RTools. First do the check above to see if you are already set up. If not then [download the software here](https://cran.r-project.org/bin/windows/Rtools/).\n\nand Install. After that, open R and run the following:\n\n``` r\nwriteLines('PATH=\"${RTOOLS40_HOME}\\\\usr\\\\bin;${PATH}\"', con = \"~/.Renviron\")\n```\n\nand restart R. Then run the check above once more to confirm\n\n\n\n## The structure: flour and sugar\n\n> No cookies without carbs\n\nAn R package is essentially a folder on your computer with specific structure. We will begin by creating an empty R package and taking a tour!\n\nOpen your R code editor, and find out where you are:\n\n``` r\ngetwd()\n```\n\nThis is to prepare for the next step, where we will choose a location for our R package folder. Please be intentional about where you place your R package! Do not place it in the same space as another package, Rstudio project or other project. Create a new and isolated location for it.\n\nI am working from an existing R project in my typical R Projects folder, so I go up one level:\n\n``` r\nusethis::create_package(\"../netwerk\")\n```\n\n\n\n![](start_pkg.png)\n\nLet's run R CMD CHECK right away. We will do this MANY TIMES.\n\n``` r\ndevtools::check()\n```\n\nWe should see some warnings! let's keep these in mind as we continue our tour.\n\n### The DESCRIPTION file\n\nThe most important file to notice is the DESCRIPTION. This gives general information about the entire package. It is written in a specific file format\n\n``` dcf\nPackage: netwerk\nTitle: Werks with Networks\nVersion: 0.0.0.9000\nAuthors@R: \n person(given = \"Andrew\",\n family = \"MacDonald\",\n role = c(\"aut\", \"cre\"),\n email = \"\")\nDescription: it does networks.\nLicense: MIT + file LICENSE\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.1.1\nSuggests: \n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\n```\n\nHere are some things to edit *manually* in `DESCRIPTION`:\n\n- package name \\[tk naming of R packages\\] -- make it short and convenient if you can!\n- Title: write this part In Title Case. Don't end the title with a period.\n- Description: Describe the package in a short block of text. This *should* end with a period.\n- Authors: Add your name here and the name of anyone building the package with you. `usethis` will have done the first step for you, and filled in the structure. Only \"aut\" (author) and \"cre\" (creator) are essential. [but many others are possible](https://www.loc.gov/marc/relators/relaterm.html)\n\nAdd your name here.\n\nAdd a license\n\n``` r\nusethis::use_mit_license(copyright_holder = \"\")\n```\n\nnote about the different roles that R package authors can have. Funny ones. but creator and maintainer are the key ones.\n\nNote the R folder. We'll get much more into that later\n\n- Rbuildignore\n\n## Keeping notes\n\ncreate an R file\n\n``` r\nusethis::use_build_ignore(\"dev.R\")\n```\n\nthe docs folder\n\nhere we have a very minimal version of an R packages we're going to be adding to it as the course progresses.\n\nOne thing we can do right away is build and check the R package\n\nWhat exactly is happining here? slide from R package tutorial.\n\nLots of checkpoints and progress confrimations along the way.\n\nOK so what is that all about? we have compiled the R package and it has gone to where the R packages on our computer go.\n\nThere is a natural cycle to how the different steps in an R package workflow proceed -- see the documentation for this lesson -- we will be following this process (TK another pictures?\n\nOk so now that we ahve the basic structure, let's talk about some content for the R package. I received the donation of a little R function already that we can use to create this workflow in a nice way\n\nThis R function (explain what the function does)\n\nOK so let's focus on just one part of this function.\n\nload all -- shortcut\n\n> how do we do this in VScode?\n\n> how to add something to the .Rbuildignore? it would be nice to have a little .dev script as a space to create all the ohter dependencies that are involved in making an R package.\n\n\n::: {.cell}\n\n:::\n\n\n## Useful links\n\nThis workshop borrows heavily from some excellent sources:\n\n- the [R packages book](https://r-pkgs.org/index.html) especially the [\"Whole Game\"](https://r-pkgs.org/whole-game.html#whole-game) chapter!\n- [rOpenSci Packages: Development, Maintenance, and Peer Review](https://devguide.ropensci.org/index.html)\n\nhttps://builder.r-hub.io/about.html\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/docs/index.html b/docs/index.html index 84f978b..b0fab39 100644 --- a/docs/index.html +++ b/docs/index.html @@ -341,7 +341,7 @@

-
+
@@ -417,14 +417,14 @@

-
+
-
+
-
+
-
+
@@ -693,7 +693,7 @@

Jan 14, 2020

-Dr Sarah P. Otto +Sarah P. Otto
diff --git a/docs/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.html b/docs/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.html index 0f83e42..8364607 100644 --- a/docs/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.html +++ b/docs/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.html @@ -6,7 +6,7 @@ - + @@ -229,7 +229,7 @@

Mathematical Modeling in Ecology and Evolution

- Dr Sarah P. Otto + Sarah P. Otto

diff --git a/docs/posts/2020-12-07-making-websites-with-hugo/index.html b/docs/posts/2020-12-07-making-websites-with-hugo/index.html index 7b20be2..6fb2842 100644 --- a/docs/posts/2020-12-07-making-websites-with-hugo/index.html +++ b/docs/posts/2020-12-07-making-websites-with-hugo/index.html @@ -11,7 +11,7 @@ -BIOS² Education resources - Making websites with HUGO +BIOS² Education resources - Making Websites with HUGO \n\n\n

Main title

\n
Main content goes here
\n\n\n\nA divider, used to organize content into blocks\n
\n\n\nA span, used to organize content or text into sections with different styles. Usually on the same line.\n\n\n\nA paragraph\n

\n\n\nHeadings at different levels\n

Main title

\n

Second level

\n

Third level

\n\n\nAn image\n\n\n\nA link\nGreat website here!" }, { "objectID": "posts/2020-12-07-making-websites-with-hugo/index.html#link-between-html-and-css", "href": "posts/2020-12-07-making-websites-with-hugo/index.html#link-between-html-and-css", - "title": "Making websites with HUGO", + "title": "Making Websites with HUGO", "section": "Link between HTML and CSS", "text": "Link between HTML and CSS\n\nIn html\nid is always unique. Class is not.\n
\nOne great div!\n
\n\n\nIn CSS\n“#” is applied to id and “.” is applied to class. When nothing is specified, applies to tag.\n#this-div-only{\n font-size:24px;\n}\n\n.this-type-of-div{\n color: #bb0000;\n}\n\ndiv{\n display:block;\n}" }, { "objectID": "posts/2020-12-07-making-websites-with-hugo/index.html#basics-of-css", "href": "posts/2020-12-07-making-websites-with-hugo/index.html#basics-of-css", - "title": "Making websites with HUGO", + "title": "Making Websites with HUGO", "section": "Basics of CSS", "text": "Basics of CSS\nW3 Schools CSS reference\n\n\n\n\n\n\n\n\nProperty\nDescription\nExample\n\n\n\n\nwidth, height\nwidth of item\n200px, 200pt, 100%, 100vw/vh\n\n\nmin-width, min-height\nminimum size of item\n200px, 200pt, 100%, 100vw\n\n\ncolor\nfont color\n#aa0000, red or rgb(255,0,0)\n\n\nbackground-color\ncolor of background\n#aa0000, red or rgb(255,0,0)\n\n\nborder-color\ncolor of border\n#aa0000, red or rgb(255,0,0)\n\n\nborder\nsize, type and color of border\n1px solid black\n\n\nmargin\nmargin around item (top right bottom left)\n1px, or 1px 2px 2px 1px\n\n\npadding\npadding within item, inside div for example\n10px\n\n\nfont-family\nname of font\nVerdana, Arial\n\n\nfont-size\nsize of text\n14px, 2em\n\n\ndisplay\nshould item be on the same line, or in a separate block?\ninline, block, inline-block, flex, …\n\n\n\n\nExercise 2\n\nCreate a file named custom.css under template-site/my-site/static/css/.\nRight-click on elements on the web page that you want to modify, then click on Inspect element and try to find CSS properties that you could modify to improve the look of the page. Then, choosing the proper class, add entries in the custom.css file that start with a dot (.) followed by the proper class names.\n\n.this-class {\n font-size:28px;\n}" }, { "objectID": "posts/2020-12-07-making-websites-with-hugo/index.html#partials", "href": "posts/2020-12-07-making-websites-with-hugo/index.html#partials", - "title": "Making websites with HUGO", + "title": "Making Websites with HUGO", "section": "Partials", "text": "Partials\nPartials are snippets of HTML code that could be reused on different places on the website. For example, you will see that the layouts/index.html file in the template-site folder lists all the partials that create the home page.\nAn important point to remember is that Hugo will look for files first in the site’s folders, and if it doesn’t find the files there, it will look for them in the theme’s folder. So site folder layouts and CSS take priority over the theme folder.\n\nExercise 3\n\nCreate a new folder template-site/my-site/layouts. In this folder, create a new file named index.html and copy the content of the template-site/layouts/index.html file into it. Remove the testimonials section from the newly created file.\nCreate a new folder template-site/my-site/layouts/partials. In this folder, create a new file named featured-species.html put the following content into it, replacing the information with the species you selected.\n\n
\n\"\"\n
\n

Red-Eyed Tree Frog

\n

This frog can be found in the tropical rain forests of Costa Rica.

\n
\n
\n\nThen, add this section to the index.html file created above.\n\n\n{{ partial \"featured_species.html\" . }}\n\nYou will probably need to restart the Hugo server to see the changes appear on the site.\nNow, you need to edit the CSS! In your custom.css file, add the following lines.\n\n\n.featured-species{\n height:300px;\n background-color: #1d1f20;\n color:white;\n}\n\n.species-image{\n height:300px;\n float:left;\n}\n\n.featured-species h3{\n color:white;\n font-size:1.5em;\n}\n\n.species-description{\n float:left;\n padding:20px;\n font-size:2em;\n}\nModify this as you see fit!" }, { "objectID": "posts/2020-12-07-making-websites-with-hugo/index.html#now-a-bit-of-go-lang-to-make-the-featured-species-different.", "href": "posts/2020-12-07-making-websites-with-hugo/index.html#now-a-bit-of-go-lang-to-make-the-featured-species-different.", - "title": "Making websites with HUGO", + "title": "Making Websites with HUGO", "section": "Now a bit of GO lang to make the featured species different.", "text": "Now a bit of GO lang to make the featured species different.\nIntroduction to Hugo templating\n\nExercise 4\n\nReplace your partial featured-species.html content with this one\n\n{{ range .Site.Data.species }}\n {{ if eq (.enable) true }}\n
\n \"\"\n
\n

{{ .name }}

\n

{{ .description }}

\n
\n
\n {{end}}\n{{end}}\n\nNow, create a new folder /template-site/my-site/data/species.\nIn this folder, create new file named frog.yaml with the following content.\n\nenable: true\nname: \"Red-eyed tree frog\"\ndescription: \"This frog can be found in the forests of Costa Rica\"\nimage: \"frog.jpg\"\n\nFind other species photos and add them to the img folder. Then you can add new .yaml files in the data/species folder for each species." }, { "objectID": "posts/2020-12-07-making-websites-with-hugo/index.html#iframes", "href": "posts/2020-12-07-making-websites-with-hugo/index.html#iframes", - "title": "Making websites with HUGO", + "title": "Making Websites with HUGO", "section": "iFrames", "text": "iFrames\nAn iFrame is a HTML tag that essentially allows you to embed another web page inside of your site.\n\nExercise 5\nFind a Youtube video and click on the share option below the video. Find the Embed option and copy the code that starts with \n
\nEdit the custom.css file and add this section\n.video{\n width:100%;\n background-color:black;\n text-align:center;\n}" }, { "objectID": "posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.html", "href": "posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.html", - "title": "Introduction to EDI concepts in a scientific context", + "title": "Introduction to EDI Concepts in a Scientific Context", "section": "", - "text": "Texte en français à la suite.\n\n1 Introduction to EDI concepts in a scientific context\nIn 2021, the BIOS2 training program will be holding a series of training and reflection activities on equity, diversity and inclusion issues. The goal is to develop an EDI action plan for the program in order to consolidate a more inclusive, respectful and open environment.\nThe objectives of this workshop are:\n\nDefine the concepts of equity, diversity and inclusion\nIdentify the benefits and challenges of EDI in the university context\nRecongnize how to become an EDI bearer during one’s university career\nRaise awareness of intercultural communication (professional competence of tomorrow)\n\nThe workshop is developed by Agathe Riallan, Faculty Coordinator for Equity, Diversity and Inclusion (EDI) at the Faculty of Science, Université de Sherbrooke, in collaboration with Marie-José Naud, Equity, Diversity and Inclusion Advisor and Coordinator at the Centre d’études nordiques (CEN).\n\n\n \n\n\n\n2 Introduction aux concepts EDI en contexte scientifique\nEn 2021, nous aurons une série de formations et d’activités de réflexion sur les questions d’équité, diversité et d’inclusion. Notre objectif est de mettre en place un plan d’action EDI pour le programme afin de consolider un environnement plus inclusif, respectueux et ouvert.\nLes objectifs de cet ateliers sont:\n\nDéfinir les concepts d’équité, de diversité et d’inclusion\nIdentifier les avantages et les défis de l’ÉDI en contexte universitaire\nIdentifier comment être porteuse ou porteur de l’ÉDI lors de son parcours universitaire\nSe sensibiliser à la communication interculturelle (compétence professionnelle de demain)\n\nL’atelier est développé par Agathe Riallan, Coordinatrice facultaire de l’Équité, de la Diversité et de l’Inclusion (ÉDI) de la Faculté des Sciences à Université de Sherbrooke, en collaboration avec Marie-José Naud, Conseillère en équité, diversité et inclusion et coordonnatrice au Centre d’études nordiques (CEN)." + "text": "Texte en français à la suite.\n\n1 Introduction to EDI Concepts in a Scientific Context\nIn 2021, the BIOS2 training program will be holding a series of training and reflection activities on equity, diversity and inclusion issues. The goal is to develop an EDI action plan for the program in order to consolidate a more inclusive, respectful and open environment.\nThe objectives of this workshop are:\n\nDefine the concepts of equity, diversity and inclusion\nIdentify the benefits and challenges of EDI in the university context\nRecongnize how to become an EDI bearer during one’s university career\nRaise awareness of intercultural communication (professional competence of tomorrow)\n\nThe workshop is developed by Agathe Riallan, Faculty Coordinator for Equity, Diversity and Inclusion (EDI) at the Faculty of Science, Université de Sherbrooke, in collaboration with Marie-José Naud, Equity, Diversity and Inclusion Advisor and Coordinator at the Centre d’études nordiques (CEN).\n\n\n \n\n\n\n2 Introduction aux concepts EDI en contexte scientifique\nEn 2021, nous aurons une série de formations et d’activités de réflexion sur les questions d’équité, diversité et d’inclusion. Notre objectif est de mettre en place un plan d’action EDI pour le programme afin de consolider un environnement plus inclusif, respectueux et ouvert.\nLes objectifs de cet ateliers sont:\n\nDéfinir les concepts d’équité, de diversité et d’inclusion\nIdentifier les avantages et les défis de l’ÉDI en contexte universitaire\nIdentifier comment être porteuse ou porteur de l’ÉDI lors de son parcours universitaire\nSe sensibiliser à la communication interculturelle (compétence professionnelle de demain)\n\nL’atelier est développé par Agathe Riallan, Coordinatrice facultaire de l’Équité, de la Diversité et de l’Inclusion (ÉDI) de la Faculté des Sciences à Université de Sherbrooke, en collaboration avec Marie-José Naud, Conseillère en équité, diversité et inclusion et coordonnatrice au Centre d’études nordiques (CEN)." }, { "objectID": "posts/2021-03-25-point-count-data-analysis/index.html", @@ -907,7 +907,7 @@ "href": "index.html", "title": "BIOS² Education resources", "section": "", - "text": "Introduction to Microbiome Analysis\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis workshop will give an overview of the theory and practice of using metabarcoding approaches to study the diversity of microbial communities. The workshop will give participants an understanding of 1) the current methods for microbiome diversity quantification using metabarcoding/amplicon sequencing approaches and 2) the normalization and diversity analysis approaches that can be used to quantify the diversity of microbial communities.\n\n\n\n\n\n\nMay 19, 2022\n\n\nSteven Kembel, Zihui Wang, Salix Dubois\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to Generalized Additive Models (GAMs)\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nTo address the increase in both quantity and complexity of available data, ecologists require flexible, robust statistical models, as well as software to perform such analyses. This workshop will focus on how a single tool, the R mgcv package, can be used to fit Generalized Additive Models (GAMs) to data from a wide range of sources.\n\n\n\n\n\n\nNov 2, 2021\n\n\nEric Pedersen\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to Shiny Apps\n\n\n\n\n\n\n\nTechnical\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nIntroduction to interactive app development with R Shiny.\n\n\n\n\n\n\nJun 22, 2021\n\n\nKatherine Hébert, Andrew MacDonald, Jake Lawlor, Vincent Bellevance\n\n\n\n\n\n\n \n\n\n\n\nGeneralized Linear Models for Community Ecology\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nIn this workshop we will explore, discuss, and apply generalized linear models to combine information on species distributions, traits, phylogenies, environmental and landscape variation. We will also discuss inference under spatial and phylogenetic autocorrelation under fixed and random effects implementations. We will discuss technical elements and cover implementations using R.\n\n\n\n\n\n\nMay 17, 2021\n\n\nPedro Peres-Neto\n\n\n\n\n\n\n \n\n\n\n\nBuilding R packages\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n\n\n\n\n\n\nMay 4, 2021\n\n\nAndrew MacDonald\n\n\n\n\n\n\n \n\n\n\n\nPoint-count Data Analysis\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nAnalysis of point-count data in the presence of variable survey methodologies and detection error offered by Peter Solymos to BIOS2 Fellows in March 2021.\n\n\n\n\n\n\nMar 25, 2021\n\n\nPeter Solymos\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to EDI concepts in a scientific context\n\n\n\n\n\n\n\nTransversal competencies\n\n\nFR\n\n\nEN\n\n\n\n\nA short introduction to EDI concepts in a scientific context.\n\n\n\n\n\n\nJan 22, 2021\n\n\nAgathe Riallan, Marie-José Naud\n\n\n\n\n\n\n \n\n\n\n\n4-Day Training in Spatial Statistics with Philippe Marchand\n\n\n\n\n\n\n\nFR\n\n\nEN\n\n\nTechnical\n\n\n\n\nTraining session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). | Session de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n\n\n\n\n\n\nJan 12, 2021\n\n\nPhilippe Marchand\n\n\n\n\n\n\n \n\n\n\n\nMaking websites with HUGO\n\n\n\n\n\n\n\nTechnical\n\n\nTransversal competencies\n\n\nEN\n\n\n\n\nThis workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n\n\n\n\n\n\nDec 7, 2020\n\n\nDominique Gravel, Guillaume Larocque\n\n\n\n\n\n\n \n\n\n\n\nData Visualization\n\n\n\n\n\n\n\nTechnical\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nGeneral principles of visualization and graphic design, and techniques of tailored visualization. This training was developed and delivered by Alex Arkilanian and Katherine Hébert on September 21st and 22nd, 2020.\n\n\n\n\n\n\nSep 21, 2020\n\n\nAlex Arkilanian, Katherine Hébert\n\n\n\n\n\n\n \n\n\n\n\nScience Communication\n\n\n\n\n\n\n\nCareer\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nRecordings, content and handouts from a 6-hour Science Communication workshop held over two days on 15 and 16 June 2020.\n\n\n\n\n\n\nJun 15, 2020\n\n\nGracielle Higino, Katherine Hébert\n\n\n\n\n\n\n \n\n\n\n\nSensibilisation aux réalités autochtones et recherche collaborative\n\n\n\n\n\n\n\nTransversal competencies\n\n\nFR\n\n\n\n\nSérie de deux webinaires sur la sensibilisation aux réalités autochtones et la recherche en collaboration avec les Autochtones, offert du 28 au 30 avril 2020 par Catherine-Alexandra Gagnon, PhD.\n\n\n\n\n\n\nApr 28, 2020\n\n\nDr Catherine-Alexandra Gagnon\n\n\n\n\n\n\n \n\n\n\n\nMathematical Modeling in Ecology and Evolution\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n\n\n\n\n\n\nJan 14, 2020\n\n\nDr Sarah P. Otto\n\n\n\n\n\n\nNo matching items" + "text": "Introduction to Microbiome Analysis\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis workshop will give an overview of the theory and practice of using metabarcoding approaches to study the diversity of microbial communities. The workshop will give participants an understanding of 1) the current methods for microbiome diversity quantification using metabarcoding/amplicon sequencing approaches and 2) the normalization and diversity analysis approaches that can be used to quantify the diversity of microbial communities.\n\n\n\n\n\n\nMay 19, 2022\n\n\nSteven Kembel, Zihui Wang, Salix Dubois\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to Generalized Additive Models (GAMs)\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nTo address the increase in both quantity and complexity of available data, ecologists require flexible, robust statistical models, as well as software to perform such analyses. This workshop will focus on how a single tool, the R mgcv package, can be used to fit Generalized Additive Models (GAMs) to data from a wide range of sources.\n\n\n\n\n\n\nNov 2, 2021\n\n\nEric Pedersen\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to Shiny Apps\n\n\n\n\n\n\n\nTechnical\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nIntroduction to interactive app development with R Shiny.\n\n\n\n\n\n\nJun 22, 2021\n\n\nKatherine Hébert, Andrew MacDonald, Jake Lawlor, Vincent Bellevance\n\n\n\n\n\n\n \n\n\n\n\nGeneralized Linear Models for Community Ecology\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nIn this workshop we will explore, discuss, and apply generalized linear models to combine information on species distributions, traits, phylogenies, environmental and landscape variation. We will also discuss inference under spatial and phylogenetic autocorrelation under fixed and random effects implementations. We will discuss technical elements and cover implementations using R.\n\n\n\n\n\n\nMay 17, 2021\n\n\nPedro Peres-Neto\n\n\n\n\n\n\n \n\n\n\n\nBuilding R packages\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis practical training will cover the basics of modern package development in R with a focus on the following three aspects: (1) how to turn your code into functions, (2) how to write tests and documentation, and (3) how to share your R package on GitHub..\n\n\n\n\n\n\nMay 4, 2021\n\n\nAndrew MacDonald\n\n\n\n\n\n\n \n\n\n\n\nPoint-count Data Analysis\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nAnalysis of point-count data in the presence of variable survey methodologies and detection error offered by Peter Solymos to BIOS2 Fellows in March 2021.\n\n\n\n\n\n\nMar 25, 2021\n\n\nPeter Solymos\n\n\n\n\n\n\n \n\n\n\n\nIntroduction to EDI Concepts in a Scientific Context\n\n\n\n\n\n\n\nTransversal competencies\n\n\nFR\n\n\nEN\n\n\n\n\nA short introduction to EDI concepts in a scientific context.\n\n\n\n\n\n\nJan 22, 2021\n\n\nAgathe Riallan, Marie-José Naud\n\n\n\n\n\n\n \n\n\n\n\nSpatial Statistics in Ecology\n\n\n\n\n\n\n\nFR\n\n\nEN\n\n\nTechnical\n\n\n\n\nTraining session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). | Session de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT).\n\n\n\n\n\n\nJan 12, 2021\n\n\nPhilippe Marchand\n\n\n\n\n\n\n \n\n\n\n\nMaking Websites with HUGO\n\n\n\n\n\n\n\nTechnical\n\n\nTransversal competencies\n\n\nEN\n\n\n\n\nThis workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming.\n\n\n\n\n\n\nDec 7, 2020\n\n\nDominique Gravel, Guillaume Larocque\n\n\n\n\n\n\n \n\n\n\n\nData Visualization\n\n\n\n\n\n\n\nTechnical\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nGeneral principles of visualization and graphic design, and techniques of tailored visualization. This training was developed and delivered by Alex Arkilanian and Katherine Hébert on September 21st and 22nd, 2020.\n\n\n\n\n\n\nSep 21, 2020\n\n\nAlex Arkilanian, Katherine Hébert\n\n\n\n\n\n\n \n\n\n\n\nScience Communication\n\n\n\n\n\n\n\nCareer\n\n\nFellow contributed\n\n\nEN\n\n\n\n\nRecordings, content and handouts from a 6-hour Science Communication workshop held over two days on 15 and 16 June 2020.\n\n\n\n\n\n\nJun 15, 2020\n\n\nGracielle Higino, Katherine Hébert\n\n\n\n\n\n\n \n\n\n\n\nSensibilisation aux réalités autochtones et recherche collaborative\n\n\n\n\n\n\n\nTransversal competencies\n\n\nFR\n\n\n\n\nSérie de deux webinaires sur la sensibilisation aux réalités autochtones et la recherche en collaboration avec les Autochtones, offert du 28 au 30 avril 2020 par Catherine-Alexandra Gagnon, PhD.\n\n\n\n\n\n\nApr 28, 2020\n\n\nDr Catherine-Alexandra Gagnon\n\n\n\n\n\n\n \n\n\n\n\nMathematical Modeling in Ecology and Evolution\n\n\n\n\n\n\n\nTechnical\n\n\nEN\n\n\n\n\nThis workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020.\n\n\n\n\n\n\nJan 14, 2020\n\n\nSarah P. Otto\n\n\n\n\n\n\nNo matching items" }, { "objectID": "about.html", diff --git a/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd b/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd index e37eb91..c829c10 100644 --- a/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd +++ b/posts/2020-01-14-mathematical-modeling-in-ecology-and-evolution/index.qmd @@ -4,7 +4,7 @@ description: | This workshop will introduce participants to the logic behind modeling in biology, focusing on developing equations, finding equilibria, analyzing stability, and running simulations.Techniques will be illustrated with the software tools, Mathematica and Maxima. This workshop was held in two parts: January 14 and January 16, 2020. categories: [Technical, EN] author: - - name: "Dr Sarah P. Otto" + - name: "Sarah P. Otto" affiliation: University of British Columbia base_url: https://bios2.github.io/ bibliography: citations.bib diff --git a/posts/2020-12-07-making-websites-with-hugo/index.qmd b/posts/2020-12-07-making-websites-with-hugo/index.qmd index 667b5c7..9bad64a 100644 --- a/posts/2020-12-07-making-websites-with-hugo/index.qmd +++ b/posts/2020-12-07-making-websites-with-hugo/index.qmd @@ -1,5 +1,5 @@ --- -title: "Making websites with HUGO" +title: "Making Websites with HUGO" description: | This workshop provides a general introduction to HUGO, a popular open source framework for building websites without requiring a knowledge of HTML/CSS or web programming. author: diff --git a/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd b/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd index 9bf434b..5d3efa6 100644 --- a/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd +++ b/posts/2021-01-12-4-day-training-in-spatial-statistics-with-philippe-marchand/index.qmd @@ -1,5 +1,5 @@ --- -title: "4-Day Training in Spatial Statistics with Philippe Marchand" +title: "Spatial Statistics in Ecology" description: | Training session about statistical analysis of spatial data in ecology, hosted by Philippe Marchand (UQAT). | Session de formation sur l’analyse statistique des données spatiales en écologie, animée par Pr. Philippe Marchand (UQAT). @@ -17,7 +17,7 @@ execute: Version en français [à la suite](#statistiques-spatiales-en-écologie). -# Spatial statistics in ecology +# Spatial Statistics in Ecology BIOS² hosted an online training session about statistical analysis of spatial data in ecology, led by Pr. Philippe Marchand (UQAT). This 12-hour training was conducted in 4 sessions: January 12, 14, 19 & 21 (2021) from 1:00 to 4:00 pm EST. diff --git a/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd b/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd index 4458bcb..fafe69c 100644 --- a/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd +++ b/posts/2021-01-22-introduction-aux-concepts-edi-en-contexte-scientifique/index.qmd @@ -1,5 +1,5 @@ --- -title: "Introduction to EDI concepts in a scientific context" +title: "Introduction to EDI Concepts in a Scientific Context" description: | A short introduction to EDI concepts in a scientific context. author: @@ -17,7 +17,7 @@ number-depth: 1 Texte en français [à la suite](#introduction-aux-concepts-edi-en-contexte-scientifique). -# Introduction to EDI concepts in a scientific context +# Introduction to EDI Concepts in a Scientific Context In 2021, the BIOS2 training program will be holding a series of training and reflection activities on equity, diversity and inclusion issues. The goal is to develop an EDI action plan for the program in order to consolidate a more inclusive, respectful and open environment. diff --git a/posts/2021-05-04-building-r-packages/index.qmd b/posts/2021-05-04-building-r-packages/index.qmd index 503c70d..f5e39dc 100644 --- a/posts/2021-05-04-building-r-packages/index.qmd +++ b/posts/2021-05-04-building-r-packages/index.qmd @@ -12,7 +12,7 @@ number-depth: 1 --- ```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) +knitr::opts_chunk$set(echo = FALSE, message = FALSE) ```