{"id":1831,"date":"2016-05-21T17:51:09","date_gmt":"2016-05-22T00:51:09","guid":{"rendered":"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/?p=1831"},"modified":"2016-05-27T14:45:04","modified_gmt":"2016-05-27T21:45:04","slug":"cluster-analysis-r","status":"publish","type":"post","link":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/2016\/05\/21\/cluster-analysis-r\/","title":{"rendered":"K-means Clustering in R"},"content":{"rendered":"<p><strong>Introduction<\/strong><\/p>\n<p>I am working with a dataset from a dynamic global vegetation model (DGVM) run across the Pacific Northwest (PNW) over the time period 1895-2100. This is a process-based model that includes a dynamic fire model. I am particularly interested in drivers of the fire regimes (the frequency and intensity of wildfire) produced by the model. The general question I am studying is \u201cwhat, if any, is the relationship between the climatic and elevation inputs of the model and the fire regimes produced by the model?\u201d A more specific pair of questions for this method is \u201cDo fire regimes cluster locally?\u201d and \u201cHow do fire regimes change over time?\u201d<\/p>\n<p><strong>Method description<\/strong><\/p>\n<p><em>Overview<\/em><\/p>\n<p>I divided the data into two time periods: 1901-2000 and 2001-2100 to capture the historical and projected climates and fire regimes over those periods. To define a fire regime, I chose the two fire-related output variables \u2013 carbon consumed by fire and percent of model pixel burned \u2013 along with fire return interval (FRI) over the century time period. I used k-means cluster analysis in R to define four fire regimes.<\/p>\n<p>K-means clustering divides a dataset into a specified number of data point clusters and calculates centroids and cluster membership such that the Euclidean distance between each cluster\u2019s centroids its members is minimized. The relationships between scales of the input variables should be taken into consideration in this type of analysis as it affects the values of Euclidean distances calculated. The steps in the analysis are outlined below. An appendix of the actual commands used for the analysis are in Appendix A.<\/p>\n<p><em>Outline of steps<\/em><\/p>\n<p>For each of the two input files:<\/p>\n<ol>\n<li>Open the NetCDF file<\/li>\n<li>Reverse the order of the latitude values (change from <em>highest to lowest<\/em> to l<em>owest to highest<\/em>)<\/li>\n<li>Filter out the na (no data) values<\/li>\n<li>Copy data (carbon consumed by fire, fraction pixel burned, FRI) into a combined data set<\/li>\n<\/ol>\n<p>For the combined dataset:<\/p>\n<ol>\n<li>Normalize values for each variable to 0.0 to 1.0 using the minimum and maximum of each variable in the combined dataset.<\/li>\n<li>Generate the four clusters<\/li>\n<li>Output value distributions of the four clusters<\/li>\n<li>Distribute resulting data into two output datasets, one for each of the two time periods\n<ol>\n<li>Divide into two separate datasets<\/li>\n<li>Distribute results into non-na data locations<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>For each of the output datasets:<\/p>\n<ol>\n<li>Create output NetCDF file<\/li>\n<li>Write data to NetCDF file<\/li>\n<li>Close NetCDF file<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><strong>Results<\/strong><\/p>\n<p><em>Clusters<\/em><\/p>\n<p>With my input data, the FRI values range from a minimum of 1 to a maximum of 100 years. The mean annual fraction area burned has a theoretical range from 0 to 1, and the mean annual carbon consumed ranges from 0 to 266.5 gm<sup>-2<\/sup>. Performing the cluster analysis using the original input values resulted in 3 of the 4 clusters driven primarily by the values of carbon consumed (Fig. 1a-c). Normalizing the values of each input variable using the variable\u2019s minimum and maximum, resulted in clusters driven by different variables (Fig. 2). For the remainder of the project I am using normalized variables.<\/p>\n<p><a href=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1832\" src=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster01-300x294.png\" alt=\"SheehanCluster01\" width=\"802\" height=\"786\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster01-300x294.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster01-1024x1003.png 1024w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster01.png 1127w\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" \/><\/a><\/p>\n<p>Fig. 1: Z-score distributions of input variables within clusters for clusters computed without normalizing input data. Clusters 1, 2, and 3 (A-C) exhibit strong overlaps in both fraction area burned, and time between fires, and strong shifts in carbon consumed between clusters. Cluster 4 (D) is the only cluster in which all three factors differ substantially with other clusters.<\/p>\n<p><a href=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster02.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1833\" src=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster02-300x293.png\" alt=\"SheehanCluster02\" width=\"803\" height=\"784\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster02-300x293.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster02-1024x999.png 1024w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster02.png 1118w\" sizes=\"auto, (max-width: 803px) 100vw, 803px\" \/><\/a><\/p>\n<p>Fig. 2: Distributions of normalized input variables within clusters. Each of the clusters was created by performing cluster analysis using normalized input data. All clusters have substantial shifts in the distributions of at least two factors compared to the other clusters.<\/p>\n<p><em>Result maps<\/em><\/p>\n<p>The clustering of fire regimes can easily be seen in maps of the fire regimes (Fig. 3). Areas without fire tend to be at higher elevations: in the Coast Range and Cascades of Oregon and Washington and the Rockies of western Montana and northwestern Idaho. High frequency fires (Low FRI) are common in the plains and plateaus of southern Idaho, south and central Oregon, and the Columbia Plateau in central Washington. The other two fire regimes, both of which have a Medium FRI are somewhat intermingled, but are present in mid elevations in the Rockies, in southwest Oregon, and in the Willamette Valley and Puget Trough regions of Oregon and Washington, respectively.<\/p>\n<p><a href=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster03.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1834\" src=\"http:\/\/blogs.oregonstate.edu\/geo599spatialstatistics\/files\/2016\/05\/SheehanCluster03-230x300.png\" alt=\"SheehanCluster03\" width=\"414\" height=\"540\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster03-230x300.png 230w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster03-786x1024.png 786w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/1572\/files\/2016\/05\/SheehanCluster03.png 813w\" sizes=\"auto, (max-width: 414px) 100vw, 414px\" \/><\/a><\/p>\n<p>Fig. 3: Fire regime maps for (A) the historical period (1901-2000) and (B) the future period (2001-2100). (C: carbon consumed; Med: medium; Frac: fraction of grid cell; No Fire: no fire occurred in the cell over the time period)<\/p>\n<p>Fire regime change from the historical (Fig. 3A) to future (Fig. 3B) period include the appearance of the High Carbon Consumed, Medium Fraction Burned, Medium FRI fire regime around the edges of the plains and plateaus as well as into the Blue Mountains of northeastern Oregon as well as the spread of both Medium FRI fire regimes into the Coast, Cascade, and Rocky Mountain ranges.<\/p>\n<p><strong>Method critique<\/strong><\/p>\n<p>I found this method to be very useful for my study. Fire and vegetation modeling results are commonly expressed using single variables over time or area and fail to take into consideration the relationships between multiple variables. This work indicates that breaking sets of multiple fire-related variables into clusters provides a way to better characterize regional characteristics as well as spatial changes through time.<\/p>\n<p>I did find the data manipulation required for the method a bit tricky. Having to work around the na values within the data required a bit of labor. Converting matrix data to vector data for the methods was another minor inconvenience. All that said, however, I believe such manipulations will become second nature as my experience with R grows.<\/p>\n<p><strong>Appendix A<\/strong>: Annotated R commands used for the analysis of normalized input data.<br \/>\n## Cluster analysis on normalized data.<br \/>\n## The dataset is drawn from two files, one for the 20th<br \/>\n## century and one for the 21st<br \/>\n## Install the necessary libraries<\/p>\n<p>library(&#8220;DescTools&#8221;) # for displaying data<br \/>\nlibrary(&#8220;ncdf4&#8243;) # reading and writing netCDF files<\/p>\n<p>## Set the current working directory for data and results<\/p>\n<p>setwd(&#8216;\/Users\/timsheehan\/Projects\/MACA\/FireClustering\/Analysis&#8217;)<\/p>\n<p>## Open the NetCDF files for reading<\/p>\n<p>histnc = nc_open(&#8216;SummaryOver_1901-2000.nc&#8217;)<br \/>\nfutnc = nc_open(&#8216;SummaryOver_2001-2100.nc&#8217;)<\/p>\n<p>## Get the lat and lon variables<\/p>\n<p>lon = ncvar_get(histnc,&#8217;lon&#8217;)<br \/>\nlat = ncvar_get(histnc,&#8217;lat&#8217;)<\/p>\n<p>## The lat dimension is highest to lowest in the input<br \/>\n## file, so its vector needs to be reversed.<br \/>\n## Reverse lat into ascending order (lower case r rev)<\/p>\n<p>lat = rev(lat)<br \/>\n## Create the data frames for historical, future, and difference data<\/p>\n<p>normHist = expand.grid(lon=lon, lat=lat)<br \/>\nnormFut = expand.grid(lon=lon, lat=lat)<br \/>\nnormDiff = expand.grid(lon=lon, lat=lat)<\/p>\n<p>## Get the fields from the input files<br \/>\n## Note the lat dimension comes in from high to low, so<br \/>\n## it needs to be reversed so that R can display it (upper case R Rev)<\/p>\n<p>## Consumed is the annual mean for carbon consumed<br \/>\n## PBurn is the annual mean of fraction of area burned<br \/>\n## FRI is the mean number of years between fires<\/p>\n<p>normHist$Consumed = c(Rev(ncvar_get(histnc,&#8217;CONSUMED_mean&#8217;),margin = 2))<br \/>\nnormHist$PBurn = c(Rev(ncvar_get(histnc,&#8217;PART_BURN_mean&#8217;),margin = 2))<br \/>\nnormHist$FRI = c(Rev(ncvar_get(histnc,&#8217;PART_BURN_intvl&#8217;),margin = 2))<\/p>\n<p>normFut$Consumed = c(Rev(ncvar_get(futnc,&#8217;CONSUMED_mean&#8217;),margin = 2))<br \/>\nnormFut$PBurn = c(Rev(ncvar_get(futnc,&#8217;PART_BURN_mean&#8217;),margin = 2))<br \/>\nnormFut$FRI = c(Rev(ncvar_get(futnc,&#8217;PART_BURN_intvl&#8217;),margin = 2))<\/p>\n<p>## Normalize the values prior to doing the analysis<br \/>\n## Also get the z scores for distribution plotting later<br \/>\n## Note that NA values from the data must be omitted before<br \/>\n## taking the statistics<\/p>\n<p>## Loop over the three variables used in the clusters<br \/>\n## foreach one filter out cells with no data using na.omit<br \/>\n## Normalize the data based on the min and max value of each<br \/>\n## variable.<\/p>\n<p>for(nm in c(&#8216;Consumed&#8217;,&#8217;PBurn&#8217;,&#8217;FRI&#8217;)) {<br \/>\n## Temporary data for efficient processing<br \/>\ntmpVect = c(na.omit(normHist[[nm]]),na.omit(normFut[[nm]]))<br \/>\ntmpMin = min(tmpVect)<br \/>\ntmpMax = max(tmpVect)<br \/>\ntmpDiff = tmpMax &#8211; tmpMin<br \/>\ntmpMean = mean(tmpVect)<br \/>\ntmpSD = sd(tmpVect)<\/p>\n<p>## Normalize the data<br \/>\nnormHist[[nm]] = (normHist[[nm]] &#8211; tmpMin) \/ tmpDiff<br \/>\nnormFut[[nm]] = (normFut[[nm]] &#8211; tmpMin) \/ tmpDiff<\/p>\n<p>## Z scores<br \/>\nnormHist[[paste(nm,&#8217;_Z&#8217;,sep=&#8221;)]] = (normHist[[nm]] &#8211; tmpMean) \/ tmpSD<br \/>\nnormFut[[paste(nm,&#8217;_Z&#8217;,sep=&#8221;)]] = (normFut[[nm]] &#8211; tmpMean) \/ tmpSD<br \/>\n}<\/p>\n<p>## Create the data frame for clustering<br \/>\n## Again, we omit data with no value using na.omit<\/p>\n<p>normWorkDF = data.frame(&#8216;Consumed&#8217; = c(na.omit(normHist$Consumed),na.omit(normFut$Consumed)))<br \/>\nnormWorkDF$PBurn = c(na.omit(normHist$PBurn),na.omit(normFut$PBurn))<br \/>\nnormWorkDF$FRI = c(na.omit(normHist$FRI),na.omit(normFut$FRI))<\/p>\n<p>## Perform the clustering analysis<br \/>\n## This is the point of all the work being done here<br \/>\n## The Lloyd algorithm runs efficiently on the large dataset<br \/>\n## (~100k points)<\/p>\n<p>normCluster = kmeans(<br \/>\ndata.frame(normWorkDF$Consumed,normWorkDF$PBurn,normWorkDF$FRI),<br \/>\n4,<br \/>\nalgorithm=&#8221;Lloyd&#8221;,<br \/>\niter.max=500<br \/>\n)<\/p>\n<p>## Copy the clusters back to the work data frame<\/p>\n<p>normWorkDF$Clust = normCluster$cluster<\/p>\n<p># Plot the cluster distributions<\/p>\n<p>for(ndx in 1:4) {<br \/>\nfNm = paste(<br \/>\n&#8216;\/Users\/timsheehan\/Projects\/MACA\/FireClustering\/Analysis\/Graphs\/NormClust_&#8217;,<br \/>\nndx,<br \/>\n&#8216;.png&#8217;,<br \/>\nsep=&#8221;<br \/>\n)<br \/>\npng(fNm)<br \/>\ntmpDF = subset(normWorkDF,normWorkDF$Clust == ndx)<br \/>\nplot(<br \/>\ndensity(tmpDF$Consumed),<br \/>\nxlim=c(0,1),<br \/>\nylim=c(0.0,6.0),<br \/>\ncol=&#8217;darkblue&#8217;,<br \/>\nxlab=&#8217;Normalized Value&#8217;,<br \/>\nmain=paste(&#8216;Cluster&#8217;,ndx,&#8217;Distribution&#8217;)<br \/>\n)<br \/>\nlines(density(tmpDF$PBurn),xlim=c(0,1),col=&#8217;green&#8217;)<br \/>\nlines(density(tmpDF$FRI),xlim=c(0,1),col=&#8217;red&#8217;)<br \/>\nlegend(<br \/>\n&#8216;topright&#8217;,<br \/>\nlegend=c(&#8216;C Consumed&#8217;,&#8217;Fract. Area Burned&#8217;,&#8217;Time Betw. Fires&#8217;),<br \/>\nlwd=1,<br \/>\ncol=c(&#8216;darkblue&#8217;,&#8217;green&#8217;,&#8217;red&#8217;)<br \/>\n)<br \/>\ndev.off()<br \/>\n}<\/p>\n<p>## Add the cluster numbers into the original data frames<br \/>\n## Note that NA needs to be taken into account using<br \/>\n## [!is.na(hist$Consumed)] to get the indexes of those data<br \/>\n## items that are not NA<\/p>\n<p>## Historical values are in first half of data frame, future in second<br \/>\n## Calculate indexes for clarity<\/p>\n<p>histClustStartNdx = 1<br \/>\nhistClustEndNdx = length(normCluster$cluster)\/2<br \/>\nfutClustStartNdx = length(normCluster$cluster)\/2 + 1<br \/>\nfutClustEndNdx = length(normCluster$cluster)<\/p>\n<p>normHist$Clust = NA<br \/>\nnormHist$Clust[!is.na(normHist$Consumed)] = normWorkDF$Clust[histClustStartNdx:histClustEndNdx]<\/p>\n<p>normFut$Clust = NA<br \/>\nnormFut$Clust[!is.na(normFut$Consumed)] = normWorkDF$Clust[futClustStartNdx:futClustEndNdx]<\/p>\n<p>## Create matrices for results and display<br \/>\n## png() tells R what file to store the results to<\/p>\n<p>png(&#8216;\/Users\/timsheehan\/Projects\/MACA\/FireClustering\/Analysis\/Graphs\/NormHistClustMap.png&#8217;)<br \/>\nnormHistClustArr = matrix(normHist$Clust,nrow=331,ncol=169)<br \/>\nimage(lon,lat,normHistClustArr)<br \/>\ndev.off()<\/p>\n<p>png(&#8216;\/Users\/timsheehan\/Projects\/MACA\/FireClustering\/Analysis\/Graphs\/NormFutClustMap.png&#8217;)<br \/>\nnormFutClustArr = matrix(normFut$Clust,nrow=331,ncol=169)<br \/>\nimage(lon,lat,normFutClustArr)<br \/>\ndev.off()<\/p>\n<p>## Calculate Euclidean distance between cluster centers<\/p>\n<p>normClustCtrEucDist = data.frame(cbind(rep(0,4),rep(0,4),rep(0,4),rep(0,4)))<\/p>\n<p>for(ndx_1 in 1:4) {<br \/>\nfor(ndx_2 in 1:4) {<br \/>\nnormClustCtrEucDist[ndx_1,ndx_2] =<br \/>\nsqrt(<br \/>\n(normCluster$centers[ndx_1,1] &#8211; normCluster$centers[ndx_2,1]) ^ 2 +<br \/>\n(normCluster$centers[ndx_1,2] &#8211; normCluster$centers[ndx_2,2]) ^ 2 +<br \/>\n(normCluster$centers[ndx_1,3] &#8211; normCluster$centers[ndx_2,3]) ^ 2<br \/>\n)<br \/>\n}<br \/>\n}<\/p>\n<p>## Create Fire Regime Euclidean distance map between historical and future<\/p>\n<p>normDiff$HistClust = normHist$Clust<br \/>\nnormDiff$FutClust = normFut$Clust<br \/>\nnormDiff$EucDist = NA<\/p>\n<p>normDiff$EucDist = mapply(<br \/>\nfunction(x,y) ifelse(is.na(y), NA, normClustCtrEucDist[x,y]),<br \/>\nnormDiff$HistClust,<br \/>\nnormDiff$FutClust<br \/>\n)<\/p>\n<p>normDiffEucDistArr = matrix(normDiff$EucDist,nrow=331,ncol=169)<br \/>\nimage(lon,lat,normDiffEucDistArr)<\/p>\n<p>## Create NetCDF file and store results there. This yields a<br \/>\n## NetCDF file that can be used independently of R<\/p>\n<p>x = ncdim_def(&#8216;lon&#8217;,&#8217;degrees&#8217;,lon)<br \/>\n## Reverse the order of latitude values<br \/>\ny = ncdim_def(&#8216;lat&#8217;,&#8217;degrees&#8217;,rev(lat))<\/p>\n<p>histFCNCVar = ncvar_def(&#8216;HistFireCluster&#8217;,&#8217;classification&#8217;,list(x,y),-9999,prec=&#8217;short&#8217;)<br \/>\nfutFCNCVar = ncvar_def(&#8216;FutFireCluster&#8217;,&#8217;classification&#8217;,list(x,y),-9999,prec=&#8217;short&#8217;)<br \/>\neucDistNCVar = ncvar_def(&#8216;EucDistance&#8217;,&#8217;NormalizedDistance&#8217;,list(x,y),9.9692099683868690e+36,prec=&#8217;float&#8217;)<\/p>\n<p># Reverse the lat order of the values being output<br \/>\nOutHistClust = c(Rev(matrix(normDiff$HistClust,ncol=length(lat),nrow=length(lon)),margin=2))<br \/>\nOutFutClust = c(Rev(matrix(normDiff$FutClust,ncol=length(lat),nrow=length(lon)),margin=2))<br \/>\nOutEucDist = c(Rev(matrix(normDiff$EucDist,ncol=length(lat),nrow=length(lon)),margin=2))<\/p>\n<p>## Output the variables and close the file<\/p>\n<p>ncOut = nc_create(&#8216;NormClusters.nc&#8217;,list(histFCNCVar,futFCNCVar,eucDistNCVar))<\/p>\n<p>ncvar_put(ncOut,histFCNCVar,OutHistClust)<br \/>\nncvar_put(ncOut,futFCNCVar,OutFutClust)<br \/>\nncvar_put(ncOut,eucDistNCVar,OutEucDist)<\/p>\n<p>nc_close(ncOut)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction I am working with a dataset from a dynamic global vegetation model (DGVM) run across the Pacific Northwest (PNW) over the time period 1895-2100. This is a process-based model that includes a dynamic fire model. I am particularly interested in drivers of the fire regimes (the frequency and intensity of wildfire) produced by the&hellip; <a href=\"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/2016\/05\/21\/cluster-analysis-r\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":7728,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[661527],"tags":[],"class_list":["post-1831","post","type-post","status-publish","format-standard","hentry","category-tutorials-2016"],"_links":{"self":[{"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/posts\/1831","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/users\/7728"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/comments?post=1831"}],"version-history":[{"count":5,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/posts\/1831\/revisions"}],"predecessor-version":[{"id":1842,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/posts\/1831\/revisions\/1842"}],"wp:attachment":[{"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/media?parent=1831"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/categories?post=1831"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.blogs.oregonstate.edu\/geo599spatialstatistics\/wp-json\/wp\/v2\/tags?post=1831"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}