{"id":13706620,"url":"https://github.com/isciences/exactextractr","last_synced_at":"2025-06-29T23:02:10.123Z","repository":{"id":40431914,"uuid":"137118038","full_name":"isciences/exactextractr","owner":"isciences","description":"R package for fast and accurate raster zonal statistics","archived":false,"fork":false,"pushed_at":"2024-08-16T00:16:24.000Z","size":1060,"stargazers_count":277,"open_issues_count":13,"forks_count":26,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-28T17:24:03.718Z","etag":null,"topics":["gis","r","raster","rcpp"],"latest_commit_sha":null,"homepage":"https://isciences.gitlab.io/exactextractr/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/isciences.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-12T19:26:45.000Z","updated_at":"2024-10-25T08:46:32.000Z","dependencies_parsed_at":"2023-02-14T13:02:39.371Z","dependency_job_id":"10ed3617-7070-41d7-9bb0-f0535e474876","html_url":"https://github.com/isciences/exactextractr","commit_stats":{"total_commits":322,"total_committers":4,"mean_commits":80.5,"dds":0.3012422360248447,"last_synced_commit":"efa5d50d0301df1477a883ac6f6c504c1cf5d8a1"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isciences%2Fexactextractr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isciences%2Fexactextractr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isciences%2Fexactextractr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isciences%2Fexactextractr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/isciences","download_url":"https://codeload.github.com/isciences/exactextractr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224466131,"owners_count":17315932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gis","r","raster","rcpp"],"created_at":"2024-08-02T22:01:02.472Z","updated_at":"2024-11-13T14:31:48.573Z","avatar_url":"https://github.com/isciences.png","language":"C++","funding_links":[],"categories":["Geospatial Library","C++","R"],"sub_categories":["R"],"readme":"# exactextractr\n\n[![Build Status](https://gitlab.com/isciences/exactextractr/badges/master/pipeline.svg)](https://gitlab.com/isciences/exactextractr/-/pipelines)\n[![coverage report](https://gitlab.com/isciences/exactextractr/badges/master/coverage.svg)](https://isciences.gitlab.io/exactextractr/coverage.html)\n[![CRAN](http://www.r-pkg.org/badges/version/exactextractr)](https://cran.r-project.org/package=exactextractr)\n[![cran checks](https://badges.cranchecks.info/worst/exactextractr.svg)](https://cran.r-project.org/web/checks/check_results_exactextractr.html)\n \n`exactextractr` is an R package that quickly and accurately summarizes raster\nvalues over polygonal areas, commonly referred to as _zonal statistics_. Unlike\nmost zonal statistics implementations, it handles grid cells that are partially\ncovered by a polygon. Despite this, it performs faster other packages for many\nreal-world applications.\n\n![Example Graphic](https://gitlab.com/isciences/exactextractr/-/raw/assets/readme/brazil_precip.png).\n\nCalculations are performed using the C++\n[`exactextract`](https://github.com/isciences/exactextract) tool. Additional\nbackground and a description of the method is available\n[here](https://github.com/isciences/exactextract#background).\nFull package reference documentation is available\n[here](https://isciences.gitlab.io/exactextractr/reference).\n\n### Basic Usage\n\nThe package provides an\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\nmethod that operates analogously to the\n[`extract`](https://www.rdocumentation.org/packages/raster/topics/extract)\nmethod in the\n[`raster`](https://CRAN.R-project.org/package=raster) package.\nThe snippet below demonstrates the use of this function to compute monthly mean precipitation for each municipality in Brazil.\n\n```r\nlibrary(raster)\nlibrary(sf)\nlibrary(exactextractr)\n\n# Pull municipal boundaries for Brazil\nbrazil \u003c- st_as_sf(getData('GADM', country='BRA', level=2))\n\n# Pull gridded precipitation data\nprec \u003c- getData('worldclim', var='prec', res=10)\n\n# Calculate vector of mean December precipitation amount for each municipality\nbrazil$mean_dec_prec \u003c- exact_extract(prec[[12]], brazil, 'mean')\n\n# Calculate data frame of min and max precipitation for all months\nbrazil \u003c- cbind(brazil, exact_extract(prec, brazil, c('min', 'max')))\n```\n\n#### Summary Operations\n\n`exactextractr` can summarize raster values using several named operations as well\nas arbitrary R functions. Where applicable, a named operation will provide\nbetter performance and reduced memory usage relative to an equivalent R function.\nNamed operations are specified by providing a character vector with one or more \noperation names to the `fun` parameter of [`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html).\n\nThe following summary operations are supported:\n\n| Name                   | Description    |                     \n| ---------------------- |--------------- |\n| `count`                | Sum of all cell coverage fractions. |\n| `majority` (or `mode`) | The raster value with the largest sum of coverage fractions. |\n| `max`                  | Maximum value of cells that intersect the polygon, ignoring coverage fractions. |\n| `mean`                 | Mean value of cells that intersect the polygon, weighted by the fraction of the cell that is covered. |\n| `median`               | Median value of cells that intersect the polygon, weighted by the fraction of the cell that is covered. |\n| `quantile`             | Arbitrary quantile value of cells that intersect the polygon, weighted by the fraction of the cell that is covered. |\n| `min`                  | Minimum value of cells that intersect the polygon, ignoring coverage fractions. |\n| `minority`             | The raster value with the smallest sum of coverage fractions. |\n| `sum`                  | Sum of values of raster cells that intersect the polygon, with each raster value weighted by its coverage fraction. |\n| `variety`              | The number of distinct raster values in cells wholly or partially covered by the polygon. |\n| `variance`             | The population variance of cell values, weighted by the fraction of each cell that is covered by the polygon. |\n| `stdev`                | The population standard deviation of cell values, weighted by the fraction of each cell that is covered by the polygon. |\n| `coefficient_of_variation` | The population coefficient of variation of cell values, weighted by the fraction of each cell that is covered by the polygon. |\n| `frac`                 | Fraction of covered cells that are occupied by each distinct raster value. |\n\nThree additional summary operations require the use of a second weighting raster,\nprovided in the `weights` argument to \n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html):\n\n| Name                   | Description    |                     \n| ---------------------- |--------------- |\n| `weighted_mean`        | Mean value of defined (non-`NA`) cells that intersect the polygon, weighted by the product of the coverage fraction and the value of a second weighting raster. |\n| `weighted_sum`         | Sum of defined (non-`NA`) values of raster cells that intersect the polygon, multiplied by the coverage fraction and the value of a second weighting raster. |\n| `weighted_variance`    | Population variance of defined (non-`NA`) values of cells that intersect the polygon, weighted by the product of the coverage fraction and the value of a second weighting raster. |\n| `weighted_stdev`       | Population standard deviation of defined (non-`NA`) values of raster cells that intersect the polygon, multiplied by the coverage fraction and the value of a second weighting raster. |\n| `weighted_frac`        | Fraction of covered cells that are occupied by each distinct raster value, with coverage fractions multiplied by the value of a second weighting raster. |\n\nWeighted usage is discussed in more detail [below](#weighted-usage).\n\nUndefined (`NA`) values are ignored in all of the named summary operations when \nthey occur in the value raster. When they occur in the weighting raster, they \ncause the result of the summary operation to be `NA`.\n\n#### Summary Functions\n\nIn addition to the summary operations described above,\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\ncan accept an R function to summarize the cells covered by the polygon. Because\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\ntakes into account the fraction of the cell that is covered by the polygon, the\nsummary function must take two arguments: the value of the raster in each cell\ntouched by the polygon, and the fraction of that cell area that is covered by\nthe polygon. (This differs from\n[`raster::extract`](https://www.rdocumentation.org/packages/raster/topics/extract),\nwhere the summary function takes the vector of raster values as a single argument\nand effectively assumes that the coverage fraction is `1.0`.)\n\nAn example of a built-in function with the appropriate signature is \n[`weighted.mean`](https://www.rdocumentation.org/packages/stats/topics/weighted.mean).\nSome examples of custom summary functions are:\n\n```r\n# Number of cells covered by the polygon (raster values are ignored)\nexact_extract(rast, poly, function(values, coverage_fraction)\n                            sum(coverage_fraction))\n\n# Sum of defined raster values within the polygon, accounting for coverage fraction\nexact_extract(rast, poly, function(values, coverage_fraction)\n                            sum(values * coverage_fraction, na.rm=TRUE))\n\n# Number of distinct raster values within the polygon (coverage fractions are ignored)\nexact_extract(rast, poly, function(values, coverage_fraction)\n                            length(unique(values)))\n\n# Number of distinct raster values in cells more than 10% covered by the polygon\nexact_extract(rast, poly, function(values, coverage_fraction)\n                            length(unique(values[coverage_fraction \u003e 0.1])))\n```\n\n### Weighted Usage\n\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\nallows for calculation of summary statistics based on\nmultiple raster layers, such as a population-weighted temperature.\nThe weighting raster must use the same coordinate system as the primary raster,\nand it must use a grid that is compatible with the primary raster. (The resolutions and\nextents of the rasters need not be the same, but the higher resolution must must be an \ninteger multiple of the lower resolution, and the cell boundaries of both rasters must\ncoincide with cell boundaries in the higher-resolution grid.)\n\nOne application of this feature is the calculation of zonal statistics on\nraster data in geographic coordinates. The previous calculation of mean\nprecipitation amount across Brazilian municipalities assumed that each raster\ncell covered the same area, which is not correct for rasters in geographic\ncoordinates (latitude/longitude).\n\nWe can correct for varying cell areas by creating a weighting raster with the area of\neach cell in the primary raster using the \n[`area`](https://www.rdocumentation.org/packages/raster/topics/area) function\nfrom the `raster` package.\n\n#### Weighted Summary Operations\n\nPerforming a weighted summary with the `weighted_mean` and `weighted_sum` operations\nis as simple as providing a weighting\n[`RasterLayer`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nor\n[`RasterStack`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nto the `weights` argument of\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html).\n\nThe area-weighted mean precipitation calculation can be expressed as:\n\n```r\nbrazil$mean_dec_prec_weighted \u003c- exact_extract(prec[[12]], brazil, 'weighted_mean', weights = area(prec))\n```\n\nWith the relatively small polygons used in this example, the error introduced\nby assuming constant cell area is negligible. However, for large polygons that \nspan a wide range of latitudes, this may not be the case.\n\n#### Weighted Summary Functions\n\nA weighting raster can also be provided when an R summary function is used.\nWhen a weighting raster is provided, the summary function must accept a third\nargument containing the values of the weighting raster.\n\nAn equivalent to the `weighted_mean` usage above could be written as:\n\n```r\nbrazil$mean_dec_prec_weighted \u003c- \n  exact_extract(prec[[12]], brazil, function(values, coverage_frac, weights) {\n    weighted.mean(values, coverage_frac * weights)\n  }, weights = area(prec))\n```\n\nOr, to calculate the area-weighted mean precipitation for all months:\n\n```r\nbrazil \u003c- cbind(brazil,\n  exact_extract(prec, brazil, function(values, coverage_frac, weights) {\n    weighted.mean(values, coverage_frac * weights)\n  },\n  weights = area(prec),\n  stack_apply = TRUE))\n```\n\nIn this example, the `stack_apply` argument is set to `TRUE` so that the summary function\nwill be applied to each layer of `prec` independently. (If `stack_apply = FALSE`,\nthe summary function will be called with all values of `prec` in a 12-column\ndata frame.)\n\n### Additional Usages\n\n#### Multi-Raster Summary Functions\n\nA multi-raster summary function can also be written to implement complex\nbehavior that requires that multiple layers in a\n[`RasterStack`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nbe considered simultaneously.\n\nHere, we compute an area-weighted average temperature by calling\n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\nwith a\n[`RasterStack`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nof minimum and maximum temperatures, and a\n[`RasterLayer`](https://www.rdocumentation.org/packages/raster/topics/Raster-class),\nof cell areas.\n\n```r\ntmin \u003c- getData('worldclim', var = 'tmin', res = 10)\ntmax \u003c- getData('worldclim', var = 'tmax', res = 10)\n\ntemp \u003c- stack(tmin[[12]], tmax[[12]])\n\nbrazil$tavg_dec \u003c- exact_extract(temp, brazil,\n  function(values, coverage_fraction, weights) {\n    tavg \u003c- 0.5*(values$tmin12 + values$tmax12)\n    weighted.mean(tavg, coverage_fraction * weights)\n  }, weights = area(prec))\n```\n\nWhen \n[`exact_extract`](https://isciences.gitlab.io/exactextractr/reference/exact_extract.html)\nis called with a \n[`RasterStack`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nof values or weights and `stack_apply = FALSE` (the default), the values or\nweights from each layer of the \n[`RasterStack`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nwill be provided to the summary function as a data frame.\n\nIn the example above, the summary function is provided with a data frame of\nvalues (containing the values for each layer in the `temp` stack), a vector of\ncoverage fractions, and a vector of weights.\n\n#### Multi-Valued Summary Functions\n\nIn some cases, it is desirable for a summary function to return multiple values\nfor each input feature. A common application is to summarize the fraction of\neach polygon that is covered by a given class of a categorical raster.\nThis can be accomplished by writing a summary function that returns a one-row\ndata frame for each input feature. The data frames for each feature will be \ncombined into a single data frame using using `rbind` or, if it is available, `dplyr::bind_rows`.\n\nIn this example, the mean temperature for each municipality is returned for\neach altitude category.\n\n```r\naltitude \u003c- getData('alt', country = 'BRA')\n\nprec_for_altitude \u003c- exact_extract(prec[[12]], brazil, function(prec, frac, alt) {\n  # ignore cells with unknown altitude\n  prec \u003c- prec[!is.na(alt)]\n  frac \u003c- frac[!is.na(alt)]\n  alt \u003c- alt[!is.na(alt)]\n  \n  low \u003c- !is.na(alt) \u0026 alt \u003c 500\n  high \u003c- !is.na(alt) \u0026 alt \u003e= 500\n\n  data.frame(\n    prec_low_alt = weighted.mean(prec[low], frac[low]),\n    prec_high_alt = weighted.mean(prec[high], frac[high])\n  )\n}, weights = altitude)\n```\n\n### Rasterization\n\n`exactextractr` can rasterize polygons though computation of the coverage\nfraction in each cell. The\n[`coverage_fraction`](https://isciences.gitlab.io/exactextractr/reference/coverage_fraction.html)\nfunction returns a\n[`RasterLayer`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nwith values from 0 to 1 indicating the fraction of each cell that is covered by\nthe polygon. Because this function generates a\n[`RasterLayer`](https://www.rdocumentation.org/packages/raster/topics/Raster-class)\nfor each feature in the input dataset, it can quickly consume a large amount of\nmemory. Depending on the analysis being performed, it may be advisable to\nmanually loop over the features in the input dataset and combine the generated\nrasters during each iteration.\n\n### Performance\n\nFor typical applications, `exactextractr` is much faster than the `raster`\npackage and somewhat faster than the `terra` package. An example benchmark\nis below:\n\n```r\nbrazil \u003c- st_as_sf(getData('GADM', country='BRA', level=1))\nbrazil_spat \u003c- as(brazil, 'SpatVector')\n\nprec_rast \u003c- getData('worldclim', var='prec', res=10)\nprec_terra \u003c- rast(prec_rast) \nprec12_rast \u003c- prec_rast[[12]]\nprec12_terra \u003c- rast(prec_rast[[12]])\n\nmicrobenchmark(\n  extract(prec_rast, brazil, mean, na.rm = TRUE),\n  extract(prec_terra, brazil_spat, mean, na.rm = TRUE),\n  exact_extract(prec_rast, brazil, 'mean', progress = FALSE),\n  exact_extract(prec_terra, brazil, 'mean', progress = FALSE),\n  extract(prec12_rast, brazil, mean, na.rm = TRUE),\n  extract(prec12_terra, brazil_spat, mean, na.rm = TRUE),\n  exact_extract(prec12_rast, brazil, 'mean', progress = FALSE),\n  exact_extract(prec12_terra, brazil, 'mean', progress = FALSE),\n  times = 5)\n\n```\n| Package       | Raster Type | Layers | Expression                                                     | Time (ms)    |                     \n| ------------  | ----------- | ------ |---------------------------------------- |--------------------- |\n| raster        | RasterLayer | 1      |          `extract(prec_rast, brazil, mean, na.rm = TRUE)`| 48708           | \n| terra         | SpatRaster  | 1      | `extract(prec_terra, brazil_spat, mean, na.rm = TRUE)`|   436           | \n| exactextractr | RasterLayer | 1      | `exact_extract(prec_rast, brazil, \"mean\", progress = FALSE)`|  1541           | \n| exactextractr | SpatRaster  | 1      | `exact_extract(prec_terra, brazil, \"mean\", progress = FALSE)`|   129           | \n| raster        | RasterStack | 12     |            `extract(prec12_rast, brazil, mean, na.rm = TRUE)`| 10148           | \n| terra         | SpatRaster  | 12     |      `extract(prec12_terra, brazil_spat, mean, na.rm = TRUE)`|   266           | \n| exactextractr | RasterLayer | 12     |`exact_extract(prec12_rast, brazil, \"mean\", progress = FALSE)`|   222           | \n| exactextractr | SpatRaster  | 12     |`exact_extract(prec12_terra, brazil, \"mean\", progress = FALSE)`|   112           | \n\nActual performance is a complex topic that can vary dramatically depending on\nfactors such as:\n\n- the number of layers in the input raster(s)\n- the data type of input rasters (for best performance, use a `terra::SpatRaster`)\n- the raster file format (GeoTIFF, netCDF, etc)\n- the chunking strategy used by the raster file (striped, tiled, etc.)\n- the relative size of the area to be read and the GDAL block cache\n\nIf `exact_extract` is called with `progress = TRUE`, messages will be emitted\nif the package detects a situation that could lead to poor performance, such\nas a raster chunk size that is too large to allow caching of blocks between\nvector features.\n\nIf performance is poor, it may be possible to improve performance by:\n\n- increasing the `max_cells_in_memory` parameter\n- increasing the size of the GDAL block cache\n- rewriting the input rasters to use a different chunking scheme\n- processing inputs as batches of nearby polygons\n\n\n# Accuracy\n\nResults from `exactextractr` are more accurate than other common\nimplementations because raster pixels that are partially covered by polygons\nare considered.  The significance of partial coverage increases for polygons\nthat are small or irregularly shaped. For the 5500 Brazilian municipalities\nused in the example, the error introduced by incorrectly handling partial\ncoverage is less than 1% for 88% of municipalities and reaches a maximum of 9%.\n\n### Dependencies\n\nInstallation requires version 3.5 or greater of the\n[GEOS](https://libgeos.org/) geometry processing library.  It is recommended\nto use the most recent released version for best performance. On Windows,\nGEOS will be downloaded automatically as part of package install. On MacOS, it\ncan be installed using Homebrew (`brew install geos`). On Linux, it can be\ninstalled from system package repositories (`apt-get install libgeos-dev` on\nDebian/Ubuntu, or `yum install libgeos-devel` on CentOS/RedHat.)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisciences%2Fexactextractr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisciences%2Fexactextractr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisciences%2Fexactextractr/lists"}