Just pad your desired number of random samples and then sample back down to the correct n. This should account for the occasional NA that are produced and subsequently removed with the na.rm=TRUE argument.
require(raster)
# Create example data
r1 <- raster(ncols=500, nrows=500, xmn=0)
r1[] <- runif(ncell(r1))
r2 <- raster(ncols=500, nrows=500, xmn=0)
r2[] <- runif(ncell(r2))
r <- stack(r1,r2)
# Sample size
n=50
# Random sample of raster
r.samp <- sampleRandom(r, size=(n+20), na.rm=TRUE, sp=FALSE, asRaster=FALSE)
dim( r.samp )[1]
# Create a random sample of n size to subset r.samp
# (works with dataframe, matrix and sp objects)
r.samp <- r.samp[sample( 1:dim(r.samp)[1], n),]
dim ( r.samp )[1]
If you can read the raster into memory an approach in sp would be to use rgdal to create a SpatialGridDataFrame the coerce it into a SpatialPointsDataFrame so you can easily remove NA's and end up with a point object of your subsample. You can then sample subsequent rasters using this sp point object. The @data dataframe can be extract and coerced into a matrix for your purposes.
require(sp)
require(rgdal)
require(raster)
n=50 # Number of random samples
# Read raster data using rgdal, results in SpatialGridDataFrame
r <- readGDAL(system.file("external/test.ag", package="sp")[1])
class(r)
spplot(r, "band1")
# Coerce into SpatialPointsDataFrame
r <- as(r, "SpatialPointsDataFrame")
# remove NA's
r@data <- na.omit(r.pts@data)
plot(r, pch=20)
# Create random sample. Object is a SpatialPointsDataFrame
r.samp <- r[sample(1:dim(r)[1], n),]
plot(r.samp, pch=20, col="red", add=TRUE)
class(r.samp)
# Use r.samp sp object for additional sampling
# Add extra column and coerce to raster stack
r2 <- readGDAL(system.file("external/test.ag", package="sp")[1])
r2@data <- data.frame(r2@data, band2=runif(dim(r2)[1]) )
r2 <- stack(r2)
# Extract raster values using r.samp object
r.samp@data <- data.frame(r.samp@data, band2=extract(r2[[2]], r.samp))
str(r.samp@data)
Here is a tidyverse
method of doing it, starting with your table from before converting to sf
. The approach is to create a long-form table where each row is a start or end point, but include a lineid
so that you can group_by
on it and summarise
to union the right points together, and then st_cast
to LINESTRING
.
library(tidyverse)
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, proj.4 4.9.3
table <- structure(list(NOMBRE = c("AL011900", "AL011900", "AL011900", "AL011900", "AL021900", "AL021900", "AL021900", "AL041905", "AL041905", "AL041905", "AL041905"), LAT = c(15, 15.2, 15.3, 15.4, 19, 19.5, 20, 36.3, 37.9, 39.6, 41), LONG = c(-42.1, -43.4, -44.7, -45.6, -59.3, -60, -60.6, -48.6, -47.9, -47.1, -46), INT = c(18.0054, 18.0054, 18.0054, 18.0054, 33.4386, 36.0108, 38.583, 46.2996, 43.7274, 41.1552, 41.1552)), row.names = c(NA, -11L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(NOMBRE = structure(list(), class = c("collector_character", "collector")), LAT = structure(list(), class = c("collector_double", "collector")), LONG = structure(list(), class = c("collector_double", "collector")), FECHA = structure(list(format = ""), class = c("collector_datetime", "collector")), INT = structure(list(), class = c("collector_double", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))
table_sf <- table %>%
group_by(NOMBRE) %>%
mutate(
lineid = row_number(), # create a lineid
LONG_end = lead(LONG), # create the end point coords for each start point
LAT_end = lead(LAT)
) %>%
unite(start, LONG, LAT) %>% # collect coords into one column for reshaping
unite(end, LONG_end, LAT_end) %>%
filter(end != "NA_NA") %>% # remove nas (last points in a NOMBRE group don't start lines)
gather(start_end, coords, start, end) %>% # reshape to long
separate(coords, c("LONG", "LAT"), sep = "_") %>% # convert our text coordinates back to individual numeric columns
mutate_at(vars(LONG, LAT), as.numeric) %>%
st_as_sf(coords = c("LONG", "LAT")) %>% # create points
group_by(NOMBRE, INT, lineid) %>%
summarise() %>% # union points into lines using our created lineid
st_cast("LINESTRING")
plot(table_sf[, 1:2])
You can see in the plot that each line between two points has its own INT
as requested.
Best Answer
Make a spatial sample data set with xyz geometry and an ID column:
split it by the ID:
run st_combine on each element:
and join them all together:
giving MULTIPOINT geometries for the ID groupings with XYZ preserved
And if you want that as a one-liner (and I'll use
Reduce
instead ofdo.call
for no good reason):Only uses base packages and
sf
.