Repository navigation
Conversation
A seed outside a boundary that is not convex lost its cell: index gave it the cell that holds the point, which is NA outside the boundary, so cell_values_at(seeds =) filled or mislabelled locations near the edge. build_tessellation() and create_voronoi_polygons() now carry each cell's generator through the clip, and for seeds (the package's seed layers, a selection's seeds, or points given with a cover) index names the cell the seed generates. A seed keeps NA only when the clip removed its whole cell, and the warning now says so. Plain points keep the observation rule. The cells themselves are unchanged. The work-round section in ?cell_values_at is removed. Two tests that pinned the old index are turned round, and test-fix-cells-seed-index.R covers the notched layers, every kind of seed layer and a seed whose cell the clip removed.
- select_resolution()'s size note calls 4.5 rows per cell "the default" rather than "the caller's choice". - The pooled print of a column with tau2 = 0 shows the full block and says each value is its neighbours' mean. - A profile with one level prints "1 level" and drops the WSS-steps clause when fewer than two levels have a WSS; the WSS-steps count on a row subset now counts that subset. The help and the resolution vignette no longer say the size stands because the caller set it. One frozen record, small_five_rows, changes in two printed lines; dev/baseline-core-frozen.R gains a --retake mode to take a record from new code.
…lbow The default on_no_elbow is now "na": with no elbow, too short a ladder or too few distinct points, the call returns NA_integer_ with a spatialkit_no_elbow warning that carries k, sag and structured = FALSE. On the model-aware criteria the NA also carries the sweep's diagnostics. A count the elbow chose carries structured and sag. on_no_elbow = "warn" gives the earlier count and warning exactly. get_voronoi_seeds(n = NA) stops with a message naming the default. The help, README, ?spatialkit and the vignettes tie the NA to the elbow, not to clusters; getting-started names on_no_elbow = "warn". Four frozen calls name "warn" and no record changes.
- Cp no longer takes a nugget at the variogram fit's lower bound; it takes the finest level's residual mean square instead. - Cp's noise variance is held to the short-lag semivariance, and attr(, "cp_noise") and the print say which source was used. - The two variogram warnings carry classes, spatialkit_variogram_unusable and spatialkit_cp_noise. - A cp selection carries a count_rule record, so a pooled summary on its cells raises spatialkit_estimate_mismatch. - A profile without an estimate fitted to a subsample refits the chosen level to every point before handing on its seeds. A profile with an estimate keeps the centres it scored. NEWS and ?spatialkit name the two ways the old-default call no longer gives the old count. 76 frozen records are retaken; test-fix-cp-predictor- path.R covers the repair, including a held-out regret check on six fields.
A cross-validated error is the error at the distance the folds put between held-out points and their training data. The help, vignettes, README, tour scripts and make_folds()'s warnings said instead that random folds flatter, that blocked folds are the ones to report, or that a score leaks, with no target. They now say which way the error reads for predictions farther from or closer to the data, the cv_*() pages state what folds = NULL estimates, and three vignettes check their folds against the map with fold_separation(). The reporting vignette's reading had the direction backwards for its own map and is now computed. No default changes. test-fix-cv-direction-wording.R checks the wording rule across the help, vignettes and scripts.
determine_optimal_levels() switched criterion = "geometric", the default, to "combined" whenever both response_var and predictor_vars were given, also when "geometric" was named, so the count read the response unasked. "combined" averaged the rank of the WSS curve's log-log sag with the rank of Moran's z of the cell means, which put first ten, the lowest count Moran's z can be computed at, or the count after it: on 600 uniform points with a smooth field, under on_no_elbow = "warn", it returned 10 6 5 where "geometric" returns 6 5 7. Its sag came from a curve carrying the WSS of the k-means re-run, so where the re-run landed in a worse optimum at the elbow another count went first, and on eighteen loose clusters the elbow, 15, dropped out of the counts returned. The criterion the caller names, or the default, now stands. With both variables under "geometric", a line logged at INFO says they are not read. "combined" ranks the counts around the elbow by the sag of the sweep's WSS curve, the one the elbow is read from, so the elbow comes first. moran_i, moran_z and wss_eval stay in the diagnostics and rank nothing. Where Moran's I can be computed at no count of a window that reaches ten cells, "combined" ranks as usual and returns the diagnostics with moran_i and moran_z NA and a logged warning, where it fell back to the geometric ranking without them; "morans_i" still falls back there. Two Breaking changes entries in NEWS describe this. A call with both variables and no criterion returns the geometric vector with no "diagnostics" attribute. "combined" returns 11 12 10 on eleven clusters, where it returned 10 11 12, and the same vector with select_on = "split" or a constant response. It raises no spatialkit_diagnostic_ranking warning; that warning comes with "morans_i" alone, its condition no longer carries `upgraded`, and its message names resolution_profile() and select_resolution() in place of select_resolution(criterion = "cp"), an error on the default profile. A factor response is refused only under a criterion that reads it. The help, the class list on the resolution_profile() help page, the vignette, script 02, the README troubleshooting entry and four older NEWS entries are brought in line. No frozen record changes. Tests turned round: the ranking-warning test in test-fix-resolution-moran-diagnostic.R (no `upgraded`, the plain advice, no warning from "combined", "geometric" with both variables); two tests in test-review3-S1-resolution.R, now "combined ranks the window on the log-log sag alone, the elbow first" and "combined on points with no elbow keeps the geometric order"; the "warn" leg in test-fix-levels-no-elbow.R, which expects the ranking class under "morans_i" only; test-resolution-profile.R and test-return-accounting.R, which expect no ranking warning from "combined"; and test-audit-pass5.R, which names criterion = "combined" for the factor-response error. Calls in test-select-on.R and test-review-resolution.R name the criterion. test-fix-levels-combined.R is new.
.estimate_icc() returned 0 both for an ICC it could not estimate (a column's values all in one cell, fewer than two cells holding two or more of them, fewer than four values) and for an estimate at or below 0, so summarize_by_cell(deff = "kish"), and a "variogram" request that fell back to it, gave an unidentified column the uncorrected standard errors under the label of an ICC of 0. Under deff = "variogram", a response with no spatial structure gave every predictor a design effect of 1 in silence, whatever structure the predictor had of its own. .estimate_icc() now returns NA with a reason in the first case and 0 in the second. It reads whether a column varies from all its non-missing values, rows with no cell id included, and names columns whose values fall in no cell or differ only there. For a column with an NA ICC the ..se_*, ..neff_* and ..ci_* values are NA in every cell of two or more values (..df_* stays n - 1), and so is cell_weight when that column sets it; a cell of one value keeps a weight of 1. A column that does not vary keeps standard errors of 0 with no warning. A warning of class spatialkit_icc_unavailable (fields columns and reason) names the withheld columns. attr(, "icc") gains a reason field only when some ICC is NA, the variogram fallback warning names those columns, and under estimate = "pooled" the method of attr(, "intervals") names them after 1 as after "kish", with .intervals_table() still giving the default's text for the other columns. A predictor summarised under a no-structure verdict gets a warning of class spatialkit_deff_no_structure (fields columns and reason); its numbers do not change. NEWS records both under Breaking changes. Three records of tests/testthat/fixtures/core-frozen.rds are retaken: values_one_region (its standard errors, effective n, intervals and cell_weight become NA, with one spatialkit_icc_unavailable warning), values_one_row_regions and values_constant (attr(, "icc") gains reason). No existing test is turned round. "the ICC guard matches its documentation" in test-audit-pass5.R and "a variogram fallback with no fit reports why, as an R warning" in test-review2-assignment.R gain expectations for the NA ICC.
area_of_applicability() measured location for a forest fitted with include_coords = TRUE only through its ..x and ..y predictor columns. Under weights = "auto" those columns take the forest's own importance, so a forest that barely split on its coordinates gave location almost no weight. With half of 50 prediction points one half to one and a half extents beyond the training data, 41 read as inside, 16 of them beyond the extent. Such a forest now gets the location index a gwr_fit and a bayesian_fit get (DI_location, element location), with the same folds and the same rule for repeated locations, and a point is inside only when it is inside on both indices. ..x and ..y stay in the predictor index with the same weights, so DI and threshold are unchanged and DI <= threshold is the old answer. The location coordinates are read after the coordinate block, so a CRS on one side only is reconciled and warned about once. In the example above none of the 25 points beyond the extent is inside. For the forest, params$coords reads "location index and predictors", print() adds "and as the predictors ..x and ..y" under the location line, and plot() counts points outside on location in its subtitle. A threshold the caller passes sets the predictor index alone, and coords = "no" leaves the coordinates out of both indices. The Breaking changes entry in NEWS states the rest: a row outside on location is FALSE also when a predictor is missing, where it was NA; folds that split repeat visits can give a location threshold of 0 with the spatialkit_aoa_zero_threshold warning; and a train_sf in a geographic CRS is refused. The data.frame refusal now suggests coords = "no". No frozen record changes. The test "a forest with the coordinates as predictors keeps its own path" in test-fix-aoa-rf-location.R is turned round to "... keeps them and gains the location index", and the reprojection test in test-area-of-applicability.R also compares DI_location. New tests are in test-fix-aoa-coord-forest.R.
With 2 to 9 cells, summarize_by_cell() takes each cell's target as the mean of every row outside it, so a cell whose own weight is below its share of the column's rows gets a pooled value on the far side of the overall mean from its plain mean. With two cells and `tau2` at 0 every own weight is 0, and each cell's pooled value is the other cell's mean. The spatialkit_pool_few_cells warning said only that a cell "with a small own weight" crosses the overall mean and that two cells can change order. The warning now gives the share of the column's rows as the bound, and adds one sentence naming the columns with two cells and `tau2` at 0: "For 'p' and 'q', with 2 cells and `tau2` at 0, each cell's pooled value is the other cell's mean: the two cells' values change places." The sentence is left out when no column is in that state. The "Conditions" entry of ?summarize_by_cell says the same, and says such a column has `cells` 2 and `own_weight` 0. The pooled values, the condition's class and its fields (`columns`, `cells`, `own_weight`) are unchanged. NEWS has a Bug fixes entry, and nothing goes under Breaking changes. No frozen fixture record was retaken. Two tests were turned round: "with 2 to 9 cells the target is the mean of all the other cells, with a warning" in test-core-pool-edge.R pinned the old sentence for 2, 3 and 9 cells, and "no number stands in those texts but the simulation's figures, its settings and the code's constants" in test-core-docs.R gains 2 and 0 for the "Conditions" entry. New tests check the exchange sentence, that it names no other column, the share when values are missing, and the help and NEWS text.
Texts that print only in a particular case misstated that case. Each now says what happened: - FNN installs with spatialkit, and the texts for when it cannot be loaded said to install it: the work limits of resolution_profile(), summarize_by_cell() and cell_values_at(), the density kind's log line, area_of_applicability(use_fnn = TRUE), the k-NN weights and spatialkit_moran_skipped. They say it could not be loaded and is to be reinstalled. The work-limit errors wrote both numbers with %.2g, so a work 0.04 percent over the limit read "1e+10 ... above the limit of 1e+10"; .count_text() writes them in full with the digits that tell them apart, and the fit guard no longer offers "the FNN package installed". - On a constant response the spatialkit_constant_response warning left out `loo`, `loo_se` and `own_weight`, which are NA too, and summary() stopped with an error that named neither the constant response nor `loo`. The warning names the three, and the error says the response is constant and names `loo`. - select_resolution() said one mean was "within 2% of the optimum" also where it was lower; it says "is not above the optimum by more than 2%", the rule. After Cp's note the variogram's no-structure note was pasted in lower case with its close said twice; it is a sentence of its own. summary() said that one cell does as well where the cells beat one cell and only the F test or the variogram showed no structure; it says which, in attr(, "not_identified"), and picks that agree read "every pick is 60 cells" in place of "picks span 60 to 60 cells (1.0x)". - The support-ceiling hint said to lower min_cell_n, which moves every level; it names `levels`. The prints write "the default" for the default size, "(1 of 1 level)", "(133 cells)", "1 k-means++ restart" and the numbers of one line in one notation (.one_notation()). The profile's print marks a bound nugget where no level gives a noise variance, and says that `cp` is NA. - summarize_by_cell()'s no-structure warning called predictors "the response"; it says "the column" or "the columns". cell_values_at() on a logical, factor or character column advised a summary that summarize_by_cell() cannot make; it says how to convert each class. assign_features_to_polygons() blamed the polygons or the CRS for features with empty geometry; it counts them. - make_folds(auto_range = TRUE) with a `block_size` said the range set the minimum block size; it says the `block_size` does and gives the grid of blocks. On one row it writes "1 fold" and offers no fewer folds. A random or provided seeding's density warning names the method in place of the density kind. model_metrics(se.fit = TRUE) names cv_bayes() only for draws or a Bayesian fit. The REML fallback of estimate_sac_range() said the fit did not converge below 30 locations or without nlme; it says it was not fitted, and why. kriging_adequacy()'s print says what its gain is under a pure nugget. voronoi_seeds_kmeans() and voronoi_seeds_random() refuse the NA of determine_optimal_levels() with the note that names `on_no_elbow`. NEWS has four Bug fixes entries and two under Breaking changes. resolution_profile() raises one spatialkit_size_not_reached for all the sizes held for the same reason, where it raised one a size; its `obs_per_cell` and `wanted` are vectors in ladder order, and one size held gives the condition it gave. The rejected_reason of estimate_sac_range() when fewer than three lag bins hold pairs is "no variogram model could be fitted: fewer than three lag bins hold point pairs", where it ended "(singular fits)". The frozen fixture retakes the 24 records whose value, print, conditions or log carry these texts: select_density_cp, select_density_arguments_cp, select_density_clustered_cp, select_integer_cp, select_lattice_cp, select_lattice_density_cp, select_lonlat_density_cp, select_min_cell_n_cp, select_n_levels_cp, select_sampled_cp, seeds_density_selection, seeds_density_profile, kmeans_density_selection, kmeans_density_profile, count_kmeans_selection_kmeans_named, select_noise_cp, small_five_rows_selected, small_five_rows_count, count_hex_noise, count_kmeans_noise, count_seeds_noise, seeds_noise_selection, seeds_random_power_named and summary_constant; the last two are retaken for the first time. Tests that pinned the old texts are turned round in test-core-count-ladder.R, test-core-count-loo.R, test-core-count-size.R, test-core-pool-edge.R, test-core-pool-properties.R, test-core-pool-summary.R, test-core-seeding-starts.R, test-core-values-at.R, test-fix-resolution-bound-warning.R, test-fix-resolution-structure-test.R and test-fix-resolution-usability.R. test-fix-resolution-no-structure.R accepts the capitalised variogram note, and "kriging_adequacy() says why there is no variogram model, and whose" takes the new reason. New tests are in test-fix-texts-misstated.R, and test-fix-cp-predictor-path.R checks the bound-nugget print.
Four run-time texts said which way an error errs with no word on the map it errs for. print() on an rf_fit called the out-of-bag error "optimistic under spatial autocorrelation"; the caution that fit_rf_model(include_coords = TRUE) logs said the out-of-bag error and random cross-validation "overstate its accuracy"; the caution that select_features_forward(method = "random_kfold") logs said random inner folds "leak spatial autocorrelation" and that a blocked outer loop reports "honest-looking numbers"; and the warning of .remap_folds() on its fallback to random folds said blocked folds "avoid optimistic performance estimates". Each text now says what the error is the error of and names the predictions it reads low for. The out-of-bag error and random folds are the error of predicting among the samples, which reads low for predictions made farther from the data, and the advice is cv_rf() or make_folds() on folds at the distances the map will predict at (?fold_separation). The random_kfold caution says the inner folds choose the variables that predict best among the samples and a blocked outer loop scores the chosen set at the blocks' distance, for which it was not chosen, and it advises inner folds that hold points out as the outer ones do: 'block_kfold', the default. A forest with no row out of bag closes its print with how to score it with cv_rf() in place of the paragraph on an out-of-bag error it does not have. Only the text of a print, two log lines and one warning changes: no result, default, class or error. NEWS has one Bug fixes entry. It leaves out the .remap_folds() warning, which no exported function reaches, since each caller builds block_kfold folds when folds is NULL. Three pins of the old wording are turned round to refuse it and match the new sentences: "print.rf_fit states the out-of-bag caveat" (now "print.rf_fit says what the out-of-bag error is the error of") in test-model-rf.R, the first test of test-fix-aoa-rf-coords-text.R, and "random inner folds are permitted but warned about" in test-feature-selection.R. test-fix-cv-direction-wording.R bars four more phrases and judges the new texts, with the prints of a forest fitted with coordinates and of one with no row out of bag, by the rules the pages follow, each header line of a print as a sentence of its own, and test-review3-S8-bayes-rf.R pins the closing lines of the no-OOB print. No frozen fixture record is retaken.
.crs_distance_error() also scores a layer of fewer than 40 polygons or lines on its outlines' vertices, and above 160 vertices it thinned them at even spacing along the rows of st_coordinates(), which follow the order of the features. Five outlines of 200 vertices over the conterminous United States got an Albers CRS in three of eight feature orders and a Lambert azimuthal one in the other five. .crs_area_error() measures at most 200 of a layer's polygons and took them at even spacing along the rows, so the area error moved with the order: 300 cells in a UTM zone, one of them 700 km east of its central meridian, were refused by summarize_by_cell(area = TRUE) in five of eight orders. The outline is now thinned along its distinct vertices sorted by x and then y, as a point layer's points are sampled: a vertex listed twice (a ring's closing vertex, a border two features share) counts once, and a thinned outline is no longer densified between the vertices kept. Above 200 polygons, the new internal .polygon_sort_keys() orders the polygons by bounding box and then by the means of their vertices' x, y, x^2, y^2 and x*y, which separates polygons that share a box, such as Delaunay triangles of gridded points. The 200 are taken at even spacing along that order, and the polygons with the smallest xmin and ymin and the largest xmax and ymax are always added, so up to 203 are measured. For a given layer the chosen CRS, attr(, "area_error") and the outcome of the area check in summarize_by_cell(area = TRUE) and in ensure_projected(purpose = "area") on projected input can differ from before, and are the same in every row order. The help for the `area` argument of summarize_by_cell() says how the cells are sampled, and NEWS has an entry under Bug fixes. No default or exported contract changes, so there is no Breaking changes entry. No frozen fixture record is retaken and no existing test is turned round. tests/testthat/test-fix-crs-polygon-order.R checks the CRS, the area error and the refusal over several row orders, rings started from another vertex, shared borders, cells that share a bounding box, and a far cell at the edge of the layer.
build_tessellation(crs = 4326) builds the cells of the scored centres in the profile's projected CRS and transforms them. On gridded locations four centres can stand the same distance from one point, and two cells meet there at two corners less than a nanometre apart. The transform to degrees puts them at one point, s2 refused the cell, and assign_features_to_polygons() stopped with "duplicate vertex" on rows in lon/lat. On 16 lattices with rows in EPSG:4326, 27 of 32 paths under the two kinds stopped, and 3 of the other 5 put rows on an edge in another cell than the profile's. When the polygons are in lon/lat and their count record says a profile scored them and holds its centres in a projected CRS, assign_features_to_polygons() moves the join's copy of the features and the polygons to the record's CRS and joins there. The rows returned keep the coordinates they arrived with. Projected cells are joined in their own CRS as before, and lon/lat cells without the record, or with scored_cells = FALSE, still go to s2. On such cells every row lands in the cell the profile scored it in, a point on an edge goes to its nearest centre's cell, and the check in summarize_by_cell() reads "match" on all 32 paths. Features that are not points get overlaps and areas measured in the projected CRS, rows without a CRS join instead of stopping, and cell_values_at() without seeds places locations there too. The help for assign_features_to_polygons(), summarize_by_cell(), create_voronoi_polygons() and build_tessellation() says which cells s2 can still refuse, and NEWS has a Bug fixes entry. In the test "only points on cells with the scored centres in a CRS the join can measure are placed by the profile's rule", the meridian squares with a record in EPSG:32617 now expect the nearer centre's cell for all five points in place of the sphere's answer, and the six points and squares in lon/lat with that record now expect the profile's rule on the points' coordinates in EPSG:32617. No frozen record is retaken.
The seeding functions attach the convex hull of the points they cluster as attr(, "cover"), and .cover_follow() moves it into the cells' CRS with its edges read as straight lines in degrees. For lon/lat points .cover_of() built the hull with s2, whose great-circle edges bow toward the pole. Over the box of the conterminous United States one of 800 points lay 130 km outside the moved cover against a 127 km margin and fell in no cell at 44 and 178 seeds. Round a pole the hull held none of the seeds and was set aside with spatialkit_no_cover (230 of 600 points in no cell at 10 seeds), round the globe it was the whole sphere, and for points on both sides of 180 degrees it ran the long way round. .cover_of() now takes the planar hull of the bare coordinates and sets the layer's CRS on it after. For lon/lat points the new .lon_narrowest() reads the longitudes from -180 to 180 or from 0 to 360, whichever spans fewer degrees, so points on both sides of 180 get a hull whose longitudes run past 180 (-170 as 190). .cover_follow() moves such a cover as it is into a CRS that joins the two sides of 180, as tested by the new .joins_across_180(). Into a CRS that splits the map there, as Web Mercator does, the new .cut_at_180() cuts it at 180 and moves the far part back by 360 degrees, before the edges are densified, so the edges along 180 follow a curved 180th meridian in Mollweide or Equal Earth. On these layers every observation has a cell, the summary's check reads "match", and between 170 E and 170 W the cells on 10 seeds go from 11 times to 1.3 times the points' hull. Cells on seeds placed from lon/lat points can differ at their outer edge, and differ throughout where the cover was set aside or ran the long way round. Layers in a projected CRS, seeds drawn in a boundary and the hull a profile keeps are unchanged. ?get_voronoi_seeds and ?voronoi_seeds_kmeans describe the cover, and NEWS has a Bug fixes entry; nothing goes under Breaking changes. Ten records in core-frozen.rds are retaken, in value only, with and without FNN and Matrix: seeds_lonlat, seeds_lonlat_density, seeds_lonlat_selection, kmeans_lonlat, kmeans_lonlat_density, cells_lonlat, cells_lonlat_selection, values_lonlat, values_lonlat_variogram and values_lonlat_area. Their cover has the same vertices in another order, and the cells move by at most 2.2e-5 m. The test "cells returned in EPSG:4326 are joined in the profile's CRS: rows in degrees on the sixteen lattices ..." in test-core-gridded-ties.R is turned round: s2 now refuses a cell on 10 of the 16 density-kind lattices, where it was 11. New tests are in test-fix-cells-cover.R.
With `what = "loo"` (the same rows in the same number of cells, another leave-one-out error), the spatialkit_cells_differ warning from summarize_by_cell() said that rows exactly on a boundary between two cells (gridded locations) can be assigned to the other cell. assign_features_to_polygons() gives such a row the cell the profile scored it in on the scored cells that carry their count record, kept in the CRS the profile measured the rows in. The sentence named a cause that no longer applies there and left out the ones that do. The closing sentence now names those cases: rows the polygons alone placed (rows without a CRS, rows assigned to cells without their count record, such as cells read back from a file, and rows given their cells by another join than assign_features_to_polygons()), cells built in, or transformed to, another CRS than the one in the count record, cells that are not the Voronoi cells of the scored centres (seeds moved, cells edited), and coordinates that reached that CRS by another transformation. The `what = "cells"` sentence is unchanged. The condition's class, its fields and every result are unchanged. ?summarize_by_cell names the same cases, says that cells transformed to another projected CRS are joined there, and that on a layer wider than a UTM zone the round trip of cells returned in a geographic `crs` can move a corner past the join's margin. NEWS has a Bug fixes entry, and nothing goes under Breaking changes. No frozen fixture record was retaken. Two tests were turned round: "two rows exchanged between neighbouring cells are told from rows dropped" in test-core-count-rule.R pinned the old sentence and now pins the new one, and checks that a cell moved whole into its neighbour reads `what = "cells"`; the else branch of "on gridded locations the check says match exactly when no row was placed in another cell" in test-core-pipeline.R pinned the old cause and now pins the polygons-alone clause. New tests in test-core-gridded-ties.R cover cells drawn in a projected CRS the caller names, rows the polygons alone place, cells transformed to EPSG:5070 and 3857, and the help and NEWS text.
new_spatial_fit() checked only that subclass was one string and built a
fit from any data_sf, formula, response_var, predictor_vars and info. A
column number or a factor as response_var made summary() and
model_metrics() score the fitted values against the column at that
position, since a factor indexes by its code. A misspelt name, the
geometry column's name or a list as data_sf failed later in another
function with a message about something else, a data_sf without
geometry made residual_morans_i() blame a missing residuals() method,
and a data.frame as info stopped with "replacement has 0 rows".
The constructor now stops, without a call and with a message that names
the argument and what it got, unless subclass is one non-empty class
name, data_sf an sf object, formula a formula, response_var one string
naming an attribute column of data_sf, predictor_vars a character
vector of attribute columns (character(0) for none) and info a list.
The geometry column, the one sf names whatever it is called, is refused
as the response or a predictor with a message of its own. NULL as info
is still taken as list(). The response's type is not checked, since a
Bayesian fit can have a factor or ordinal response; summary() and
model_metrics() refuse a non-numeric one as before.
NEWS has a Breaking changes entry, and ?new_spatial_fit says what the
constructor checks and what each argument must be. A fit_fn that passed
st_drop_geometry(train_sf) has to pass train_sf, and a brms::bf()
formula is passed as its $formula. A fit that names a column the
training rows lack fails every fold of cv_spatial() with the
constructor's message in fold_status. In select_features_forward(), a
fit_fn whose fit for no predictors is refused (predictor_vars = NULL,
say) gets the training-fold mean as its baseline, and baseline$type
says "fold mean".
In "new_spatial_fit builds the documented structure" in
test-spatial-fit-s3.R, the expect_error() for subclass = c("a", "b")
now matches "`subclass` must be one class name", and the check that a
cache passed in info is kept, which held only because testthat's
edition 3 finds two empty environments equal, now expects the fresh
cache the constructor puts in its place. "area_of_applicability takes
training data from a fitted model" gives its stand-in fit the response
column z it named. test-fix-new-spatial-fit-args.R pins each refusal
and what still builds. No frozen fixture record is retaken.
With seeds, cell_values_at() fills a location whose cell has no row in values from its nearest scored row. When no seed carried the ID of a cell of values (an ID column from elsewhere, the index of another tessellation, or IDs that are all NA), every location was filled and nothing was raised: on a layer of 107 cells, seeds numbered 1001 to 1107 filled all 120 locations asked for, and 18 values differed from those of the locations' own cells. A values with no cell ID gave every location NA. Seeds without a CRS beside points with one stopped with an error that named no CRS, though get_voronoi_seeds() returns seeds without one for rows in lon/lat without a CRS. cell_values_at() now compares the seeds' IDs with those of values before any CRS work or search, and stops when none matches. The error names the seeds' ID column and says to set it from the tessellation's index; IDs that are all NA get a text of their own. When values carries the cell polygons and some seed ID is NA, the check runs after seeds outside every polygon take the cells they generate, so points placed by hand outside the boundary still run. A values with no row or only NA IDs is an error that names values. One matching seed is enough. Seeds without a CRS beside points with one are read as build_tessellation() reads a boundary without one, with a plain warning. Beside a projected CRS, coordinates that look like lon/lat are taken as EPSG:4326 and transformed, and others are given the CRS of points. Beside a geographic CRS, coordinates inside the lon/lat ranges are given it, and others are an error that names the CRS the summary measured in. newdata without a CRS is still refused. The help for cell_values_at() and two Bug fixes entries in NEWS describe both. In "what `seeds` and `values` must be", a values of no rows with seeds now expects the values error in place of every value NA. In "`newdata` without a CRS is refused beside rows with one, and runs beside rows without", seeds without a CRS now expect one warning and the values of the call with the CRS set. In "a location the same distance from two scored locations takes the lower x, then the lower y", the lone seed with an NA ID gains a second seed at (1e4, 1e4) with the ID of cell 1; every expectation is as it was. No frozen record is retaken.
Under select_on = "split", resolution_profile() scores the estimate on the rows of the selection half that have a response, and the check that estimate has rows to read is made on the layer. A layer whose rows with a response all lay in the estimation half passed it, under a named estimate and under "auto", which became "pooled". The profile returned loo and the estimate's other columns NA at every level, as were rss, cp, moran_i and moran_z, and said nothing. Its print said "fewer than two rows", the count record's print read "in NA cells", select_resolution(criterion = "loo") said loo needs a cell that holds two rows with a response, and summary() said "cp needs a response". The columns stay NA. After the levels are scored, resolution_profile() raises one warning of class spatialkit_no_scored_rows that names the NA columns and counts the rows of the selection half and the rows with a finite value, all in the estimation half. The condition carries reason, n, selection, n_response and column. A call a guard stops raises none. Both prints now read "loo NA: no row of the selection half has a response", select_resolution(criterion = "loo"), the criterion a profile of plain means is read by, stops with that reason, and summary() of the profile names the selection half in its error. The other criteria keep their own refusals. No number, default, column or result class changes, and NEWS has one Bug fixes entry. The help for resolution_profile() (estimate, Value, Conditions) and select_resolution() says when the columns are NA and why. The new test-fix-split-no-response.R pins the warning and its fields, on halves of different sizes too, the prints, the refusals of select_resolution() and summary(), and the calls that raise no warning. No test is turned round and no frozen fixture record is retaken.
fit_bayesian_spatial_model() merged `control` over list(adapt_delta = 0.9, max_treedepth = 12). At 0.9 ordinary data left a few divergent transitions, and one is enough to set `convergence_ok` to FALSE and raise spatialkit_convergence: four layers of 250 points over a smooth field with a 60 km range, fitted at the default four chains of 2,000 iterations from three seeds each, had 1 to 24 in every fit. The warning's advice printed adapt_delta with %.2f, so 0.975 read 0.97, 0.995 read 0.99 and 0.999 read 1.00, and a fit raised to 0.995 was told it ran at 0.99. The defaults are now one list, .bayes_control_default, with adapt_delta 0.99 and max_treedepth 12, and `control` is still merged over it. The four layers had no divergent transition at 0.99. cv_bayes(), compare_models_cv() and every other call that leaves `control` unset take the new default. The advice prints adapt_delta with %.15g, which follows neither options(digits) nor options(OutDec). The `control` entry of ?fit_bayesian_spatial_model gives the measurement, the cost, the way back and 0.995 or 0.999 for divergences that remain at 0.99, as on a weak spatial field; `check_convergence` says its R-hat figures come from fits at 0.9 or 0.95; and the example says Stan may warn about effective sample size. Sampling takes about two to three times as long, and a fit at a given seed draws other values, so its estimates, intervals and predictions change. `control = list(adapt_delta = 0.9)` restores the previous setting. NEWS has a Breaking changes entry, and the README says its recorded compare_models_cv() timing was taken at 0.9. No frozen fixture record was retaken. Four pins were turned round: "a supplied control list keeps the package's adapt_delta default" in test-bayes-smoke.R expects 0.99 after a partial `control`; in test-fix-bayes-convergence.R, "divergences and low E-BFMI fail; tree-depth saturation is recorded only" and "several failures arrive as one warning" expect "(now 0.99)" at the default, and ".bayes_convergence_advice() gives the remedy for the checks that failed" expects "(now 0.9)" for an explicit 0.9. New tests check the merged control, the advice under options(digits) and OutDec, and the help and NEWS text, and test-fix-bayes-default-control.R (opt-in with SPATIALKIT_TEST_BRMS) fits the four layers at the default and expects no divergent transition.
estimate_sac_range() held its floor of 30 against rows. Rows that share a location are one place to the variogram and to its test for spatial structure, which runs on the location means. Five locations visited 20 times passed the floor, got a variogram of ten pairs of locations and a structure test on five means, which called most such layers unstructured even where the range was three times the extent, and summarize_by_cell(deff = "variogram") then gave a design effect of 1 in every cell. After the n_max subsample and before the detrending, the function now counts the distinct locations of the rows the variogram is computed on with .sac_locations(), where two rows are at one location when both coordinates are equal to the last bit after the projection. Below 30 it logs a WARN line, fits nothing and returns the unclassed NA whose rejected_reason, from the new .sac_reason_few_locations(), gives the count: "<k> distinct location(s) among the <n> point(s) with a finite value to model, fewer than the 30 a variogram range is estimated from". When the layer has 30 or more locations and the subsample kept fewer, the counts are the subsample's and the reason says "of the n_max subsample". The check runs again after the rows with no finite value to model are dropped. With detrend = "reml" no REML fit is tried and no REML warning is raised, and the warning that the variogram is fitted to the raw response comes only once the floor has passed. A layer of 30 or more rows at 2 to 29 locations, which 2.0.0 fitted, gets the NA (Breaking changes in NEWS): the range is NA, summarize_by_cell(deff = "variogram") returns Kish standard errors with spatialkit_deff_fallback, make_folds(auto_range = TRUE) builds geometric blocks, kriging_adequacy() stops with the reason, and the Bayesian fit's check before fitting reports the range as not estimated. A layer whose rows all lie at one location gets this reason in place of "the points have no extent". The help of estimate_sac_range() states the floor under Details, predictor_vars, n_max, seed, detrend and Value, and NEWS has Bug fixes and New features entries as well. test-fix-variogram-locations.R is new. Two tests are turned round: "estimate_sac_range()'s early NA returns carry a rejected_reason and nothing else" in test-review3-final-B.R expects the location reason for 40 rows at one location, and "the REML detrending on fewer than 30 locations is said not to be fitted" in test-fix-texts-misstated.R expects no REML warning and the location NA for 40 rows at 20 locations. No frozen fixture record is retaken.
On a lattice two to four locations are equally near. .sac_short_lag() paired each location with its nearest other one through FNN's kd-tree or the base-R search, and the two took different ones, so short_lag_pairs, short_lag_semivariance, Cp's noise variance and the `cp` column differed between a session with FNN and one without (80 pairs against 143 on a 12 x 12 lattice). The pooling's searches, .region_neighbours() and .nearest_location_search(), counted exact ties alone, and lattice centroids that tie in one unit differ in their last bits in another or after a shift of the origin. The same layer in metres and in feet gave some cells other neighbours, and since `tau2` is fitted over the layer every pooled value of summarize_by_cell() moved, and so did the leave-one-out error of resolution_profile(). Squared distances within one part in ten million (.TIE_TOL) of the least are now a tie. A tie goes to the lower x, then the lower y, coordinates within .TIE_TOL times the distance counting as equal, then to the lowest number: .knn_exact_rows() and .knn_tied_rows() take `tol` and `num`, and a new .knn_pick_rows() applies the rule. The partition passes neither and keeps exact ties. .region_neighbours() passes the region's own number, so regions whose centroids coincide stay told apart by number when rounding parts them, and the FNN paths widen their shortlist margins by .TIE_TOL. .sac_short_lag() puts the locations in coordinate order, takes each one's nearest other location from .nearest_location_search() with FNN or .knn_exact_rows(tol = .TIE_TOL) without, and computes the separation in R. On gridded layers a session with FNN now gets the short-lag pairs and `cp` values the search without FNN gave where ties were exact; on a square lattice the pairs run along x. summarize_by_cell() gives the same neighbours and pooled values in another unit or origin while the spacing is above about a ten-millionth of the coordinates. Where three or more cells' centroids coincide the values agree to rounding, and where ten or more do, which 8 each takes can still change. ?summarize_by_cell and ?sac_nugget state the rule, and ?resolution_profile now says the density kind's cells can differ in another unit or origin, since the partition counts exact ties alone. No default, class or error changes. NEWS has two Bug fixes entries and nothing under Breaking changes. Nine frozen records are retaken, each to the record the fixture held for its call without FNN: profile_lattice, profile_lattice_density and profile_integer (value, conditions, printed, log: short_lag_pairs 80 to 143, the semivariance and cp_noise 0.1507 to 0.1257 on the lattice and 15.18 to 12.81 for profile_integer, the `cp` column, the print's variogram line and the two variogram warnings), and select_lattice_cp, summary_lattice, select_lattice_density_cp, summary_lattice_density, select_integer_cp and summary_integer (value). Turned round in test-core-pool-properties.R: .pt_neighbours() and .pt_nearest_other() write the rule with the tolerance and the number through a new .pt_pick(), test 13 holds squared distances nearest first to within .TIE_TOL, the spies on .knn_exact_rows() and .knn_tied_rows() pass `...` on, and the kd-tree stand-ins group candidates within .TIE_TOL (was 1e-9). test-fix-neighbour-ties.R is new.
.no_spread() compared a column's sums of squares with the size of its values. So 1e15 plus a spread of 1, whose values are stored to an eighth, and 1e6 plus 1e-9 times a spread of 1 were called constant, and so were values near 1e200 or 1e-170, whose squares overflow or underflow, whatever their spread. summarize_by_cell() then said their values "do not vary inside any cell" and returned the plain means with weights 1, and resolution_profile() left `loo` NA. The standard error of a leave-one-out error squares the squares, so `loo_se` was Inf for residuals above about 1e77 and lost its precision, then read 0, below about 1e-80. .pool_fit() now reads no spread twice: on the raw values, and on the column centred on its median and scaled by powers of two (.spread_scaled()). A column has no spread only where neither reading finds any. On the scaled column a standard deviation, over all the rows or inside the cells, of at most .POOL_ULPS (3) units in the last place of the largest absolute value is rounding (.scaled_rounding()), so a column whose values differ only by their rounding (0.1 beside 0.3 / 3, 2 beside sqrt(2)^2) is constant as before. Where the raw values lose their spread and the scaled column keeps it, the fit runs on the scaled column with the column's own readings and is put back in its units (.pool_unscale()). A column that is not constant, with an absolute value above 1e150 or a largest distance from its median below 1e-150, is refused with the status "values out of range". .loo_mean_square() divides residuals whose largest lies outside 2^-255 to 2^255 by a power of two before it squares them, and inside those bounds gives the formula's numbers bit for bit. resolution_profile() reads its estimate's columns by the same test (.constant_column()); its test of a constant response for `cp` still reads the raw values alone. summarize_by_cell() pools 1e15 plus a spread of 1, with the weights, `sigma2`, `tau2` and leave-one-out errors of the spread alone. The degenerate warning says the values do not vary inside any cell "to the precision of the values". A column beyond the bounds gets NA pooled columns and a spatialkit_pool_unavailable warning whose `reason` is "values out of range"; at 800 rows, 1e150 to 1e152 and 1e-151 to 1e-160 times a spread of 1 were fitted before and are now refused. `loo_se` is finite inside the bounds, in the record and in resolution_profile(). The profile scores `loo` for 1e15 plus a spread of 1; where the test for `cp` calls the response constant and the estimate's test does not, the warning, print() and select_resolution(criterion = "cp" or "moran_z") say what each test found and that `loo` is scored. Beyond the bounds the profile raises one spatialkit_pool_unavailable warning, which names `cp`, `moran_i` and `moran_z` too where the test for `cp` calls the values constant, and print(), summary() and select_resolution() say the values are out of range. NEWS has a Bug fixes entry, and the Breaking changes list of reasons for spatialkit_pool_unavailable adds values beyond what the arithmetic of pooled values holds. No frozen fixture record was retaken. Four tests were turned round: "11. the rule for no spread is relative to the size of the values" in test-core-pool-properties.R, now "11. the rule for no spread does not depend on where the values sit or on their size", expects 1e6 plus 1e-9 times noise to be fitted as the noise; "a constant response has no loo, and the warning names it among the columns that are NA" in test-core-count-loo.R expects that response constant to the test for `cp` and scored by `loo`; "ten constant predictors raise one spatialkit_pool_degenerate, six of them named" in test-core-pool-summary.R holds the new warning text; and "a response that is constant to within rounding scores nothing, as the message says" in test-fix-resolution-usability.R expects select_resolution(p, "cp") to say what the test for `cp` found, and holds the old error on a profile with `estimate = NULL`. test-fix-pool-extreme-scales.R tests the two readings, the rounding bound, the fit of the scaled column, the bounds and their warnings, the standard errors and the profile's texts.
.crs_distance_error() adds the outline of a layer with fewer than 40 features and, when the outline has fewer than 40 distinct vertices, fills each of its edges with points. An edge two features shared was filled once from each end, some copies of an added point differed in their last bits, unique() kept both, and the pair, about 1e-9 m apart, set the worst-case ratio of every candidate CRS. Two lon/lat boxes of 12 by 15 degrees, one above the other, scored 0.7692 in EPSG:32613 and 0.8682 in EPSG:5070, where their outline as one box scores 0.0051 and 0.1087, and ensure_projected() kept UTM zone 13 with "76.92% vs 76.92%". A 2 by 2 grid of 3.7 by 2.9 degree boxes scored 0.2715 and 0.0965 against 0.0066 and 0.0098, and moved to a Lambert azimuthal CRS with "11.22% against the zone's 13.50%" where its outline gives 0.06% and 0.26%. Two boxes side by side scored 0.3179 and 1, and two boxes one above the other across the antimeridian scored 0.7923 in a Lambert azimuthal CRS on 180, where their outline scores 0.0025. The same held where an added point fell on a corner of another feature (a T-junction, or a corner touching an edge) or on a point added along an edge that overlaps it in part: a T of boxes at (-111.7, 28.3) scored 0.5605 and 1 against its union's 0.0049 and 0.0069. .crs_distance_error() now fills each edge from the end with the smaller longitude, or the smaller latitude when the longitudes are equal, so the two copies of a point on a shared edge are computed the same way and are the same double, whichever way each ring runs. The added points are sorted by coordinate and put after the vertices, and an added point is left out when it shares a cell of 1e-9 degrees (about 0.1 mm) with an earlier point, the cells in each coordinate taken from two grids half a cell apart (round() and floor() of the coordinate times 1e9), so copies a few bits apart are never kept either side of a cell's border. The vertices are kept as they are. The comments and the internal doc of `x_ll` say why. The layers above score within a tenth of a percentage point of their outlines, and the log of ensure_projected() quotes the outlines' figures. A layer on which no added point lies within 1e-9 degrees of another point scores as before, but for the last bits. For the others the CRS, attr(, "crs_choice") and the logged figures can differ from before, and the score no longer depends on the direction of a ring or the order of the features. No default, class or error changes. NEWS has a Bug fixes entry and nothing under Breaking changes. No frozen fixture record is retaken, and no test is turned round. test-fix-crs-shared-edges.R tests shared edges, an edge across the antimeridian, ring direction, feature order and ring start, the figures ensure_projected() logs, corners on another feature's edge, points either side of a half step of the 9th decimal, and pins the scores of layers with no added point on another feature's point.
.crs_area_error() took the geodesic areas of all its probes in one call
on their copy in EPSG:4326. Two corners a fraction of a nanometre apart
in the cells' CRS can fall on one point in degrees, where s2 refuses the
ring ("duplicate vertex"), and a vertex listed twice, which GEOS
accepts, does the same; one such probe made the call fail and the
figure NA for the whole layer. The k-means cells of a 30 by 20 lattice
at 30 m, built and kept in EPSG:32615 from rows in degrees, are all
valid in EPSG:32615 and s2 refused 4 of the 133, so
summarize_by_cell(area = TRUE) stopped because "the area distortion of
`cells_sf`'s CRS could not be measured". ensure_projected(purpose =
"area") skipped its check on projected input in silence the same way:
20 cells of 1 degree from 30N to 69N in Web Mercator, which distort
areas by 214 percent, logged nothing when one cell had such a pair of
corners.
When the one call fails, .crs_area_error() now takes the geodesic
areas one probe at a time, and a probe s2 refuses is measured again
without the vertices that repeat the one before them in degrees. A new
helper, .drop_repeated_vertices(), drops them from each ring of a
POLYGON or MULTIPOLYGON, holes included, comparing x and y alone, so
the ring's points and its area stay as they were. A probe s2 refuses
even then, such as one whose edges cross or one with a spike, makes the
figure NA as before: leaving such probes out of the spread could leave
out the ones that carry the distortion.
st_make_valid() is not used: it snaps vertices to 1e-7 degrees and on
cells a few metres across moves the ratio by more than the tolerance.
The lattice's k-means cells now get a density, with attr(, "area_error")
the spread over all 133 cells (below 1 percent). For the Web Mercator
cells ensure_projected() logs the warning, and summarize_by_cell(area =
TRUE) refuses them for their distortion, no longer because it could not
be measured. A layer whose probes s2 all accepts gets the same figure
as before, to the last bit. A cell s2 refuses for another reason still
leaves the spread unmeasured, and the request is refused as before.
?summarize_by_cell says how a cell s2 refuses is measured and when the
request is still refused. No default, class or error changes. NEWS has
a Bug fixes entry and nothing under Breaking changes.
No frozen fixture record is retaken, and no existing test is turned
round. test-fix-crs-area-refused-probe.R tests the lattice's k-means
cells with rows in degrees and in EPSG:32615, the one-call figure kept
where s2 accepts every probe, cells with a corner beside another or a
repeated vertex in Web Mercator, UTM and a Lambert conformal conic
layer of 300 cells, multipolygons, holes and z coordinates, the log of
ensure_projected() and the error of summarize_by_cell(), and the NA
for a bowtie or a spike.
assign_features_to_polygons() joins rows to lon/lat cells on the sphere
with s2 unless the cells' record names the projected CRS a profile
scored them in. Cells returned in lon/lat can hold two corners that
differ only by rounding and fall on one point in degrees, which s2
refuses. Three kinds of cell still went to s2: cells that had lost their
record, cells whose record says `scored_cells = FALSE`, and cells
without a CRS, which take the rows' EPSG:4326. On them the plain join
stopped with s2's "Loop 0 is not valid: Edge 20 is degenerate (duplicate
vertex)", an error with no class that named neither the polygon nor a
way on. s2 refuses 4 of the 133 k-means cells of a 30 by 20 lattice at
30 m returned in EPSG:4326; with their record the cells joined 600 rows,
and without the record or the CRS the join stopped. The cells of centres
refitted to every point on a 50 by 40 lattice at 250 m stopped it the
same way. A hole that crossed its outer ring and two holes that shared
an edge stopped it with s2's bare message too. The largest-overlap join
wrapped a refusal that outlived its repair in advice to pass
`largest = FALSE`, which meets the same refusal.
The plain join now runs inside withCallingHandlers(), and the
largest-overlap join's handler calls .stop_cells_degenerate() before its
own message. That helper acts when the error names a ring ("Loop N" or
"loop orientations"), the polygons are in lon/lat, sf_use_s2() is on and
sf::st_is_valid() reads at least one polygon as invalid; otherwise it
returns NULL and the error is raised as before.
.raise_cells_degenerate() builds the error of class
spatialkit_cells_degenerate. It gives the number of polygons s2 refuses
and their rows (six at most, then "and N more"), quotes the first line
of s2's message, names the cause of two corners read as one point where
s2's reason is "duplicate vertex", and says to transform `polygons_sf`
to a projected CRS, such as the one the cells were built in or the one
ensure_projected() picks, and assign again; for polygons without a CRS
it says to set the CRS with sf::st_set_crs() first. The condition
carries `rows`, `n`, `reasons` and `parent` (s2's error) and no call.
cell_values_at() without `seeds` catches the class around its join and
raises it again through .raise_cells_degenerate() in its own words: it
names `values` and the placement of the locations, gives the rows of
`values` (rows without an ID are not handed to the join), counts "the N
polygons of `values` that carry an ID" when some lack one, and says to
call cell_values_at() again.
A join on polygons s2 refuses now stops with spatialkit_cells_degenerate
where it stopped with sf's bare message or the advice to pass
`largest = FALSE`. Polygons s2 accepts join as before, the
largest-overlap join still repairs the polygons it can, with its
warning, and runs, and an error of another kind keeps its own message.
No default changes. The Details of ?assign_features_to_polygons, step 3
of ?cell_values_at and `crs` in ?create_voronoi_polygons name the error.
NEWS has a Bug fixes entry and nothing under Breaking changes, since
every call that now raises the class stopped before.
No frozen fixture record is retaken and no test is turned round.
test-fix-join-cells-degenerate.R tests the refused squares and the rows
the message gives, the join in degrees with s2 off, a bowtie, squares
without a CRS, an error of another kind and the predicate's own
condition, the largest-overlap join with a mocked repair, a crossing
hole and two identical holes on both joins and after the transform, a
hole that runs the way its outer ring runs, the lattice's cells without
their record or CRS, cell_values_at() on the lattice summary with and
without its record, an ID or a CRS, the refitted centres' cells, and
the help and NEWS text.
Under the model-aware criteria determine_optimal_levels() re-runs k-means at each count of the window around the elbow, the elbow plus or minus max(4, `top_n`). The re-runs drew from one random stream in order, so a `top_n` above 4 started the window lower, more re-runs came before each count, and every count in the window got other cells, and with them another `wss_eval`, `moran_i` and `moran_z`. On 480 points in twelve clusters with `max_levels = 30` and `set_seed = 123`, "morans_i" put 15 first at `top_n` 1 to 4, 16 at 5 and 17 at 6 and 7, though 15 and 16 lie in all of those windows, and k = 17 had a |z| of 0.0013 at `top_n = 6` and of 0.30 at `top_n = 7`. Of the 21 pairs of calls at `top_n` 1 to 7, 30 columns differed at a shared count under "morans_i" and 45 under "combined", whose ranking stayed while its diagnostics moved. After the sweep the function now draws one integer, `rerun_seed`, from 1 to .Machine$integer.max - k_max, and runs the re-run at k (.partition_centres()) under .with_seed(rerun_seed + k), putting the stream back after each re-run. The integer depends on `set_seed`, or with `set_seed = NULL` on the caller's stream. With the other arguments fixed, a count gets the same cells, `wss_eval` and Moran's I whichever `top_n` sets the window. A wider window still scores more counts, and under "morans_i" one of them can rank first: on the same layer the first count is 15 at `top_n` 1 to 4, 17 at 5 and 18 at 6 and 7, each the count of smallest |z| in its window. For a given seed `moran_i`, `moran_z`, `wss_eval` and the "morans_i" ranking can differ from before, and a "morans_i" call can fall back to the geometric ranking where it ranked, or rank where it fell back; the sweep, the elbow and the "combined" ranking are as before. With `set_seed = NULL` the re-runs take one draw from the caller's stream in place of the draws of every re-run, so the stream after the call no longer depends on `top_n`. ?determine_optimal_levels says under `top_n` that it sets the counts scored and that a count scores the same whichever `top_n` puts it in the window, and its Details say each re-run draws from a stream of its own. No default, class or error changes. NEWS has a Bug fixes entry and nothing under Breaking changes. No frozen fixture record is retaken: levels_morans and levels_combined run at `max_levels = 8`, where every count of the window has fewer than ten cells and the call returns the geometric ranking before any re-run value is stored. No test is turned round. The new test-fix-levels-rerun-seed.R checks that a count scores the same in every window that holds it under both model-aware criteria, on twelve clusters at two seeds and on eighteen clusters under `select_on` "all" and "split"; that under "morans_i" a wider window moves the first count only to a count it adds, with a smaller |z|; that the re-run at a count starts from the same stream in every window; that the caller's stream is left as it was and not read; that the re-runs depend on `set_seed`; that with `set_seed = NULL` the scores and the stream after the call do not depend on `top_n`; and that the help and NEWS say so.
summarize_by_cell(deff = "kish") skipped a column as one that does not vary when its standard deviation was below .Machine$double.eps (about 2.2e-16), on all its values and again on the rows with a cell id, whatever the size of its values. A column that varies, in units that make its values of order 1e-16 or smaller, got an ICC of NA with the reason "the column does not vary", no design effect and the uncorrected standard errors, with no warning. On 800 points in 178 cells the ICC was 0.478 at a scale of 1 and of 1e-14 and NA at 1e-17, 1e-20 and 1e-100, and the median standard error over the scale fell from 0.666 to 0.303. Where only the rows with a cell id were that small, the ICC was NA with "its values differ only on rows that fall in no cell" and the standard errors were NA. A column near 1e200 had an ICC of NA with "the variance decomposition is undefined". The standard deviation inside a cell, behind ..sd_*, ..se_*, ..neff_*, ..df_* and ..ci_*, squared the raw deviations. Above about 1e154 the squares overflowed, and in each cell where they did ..sd_* was Inf and the standard errors and intervals NA, under any deff and with no warning: 7 of 60 cells at 1e154 and all 60 at 1e155 and 1e200. At a spread of 1e-170 ..sd_* and the standard errors were 0. .estimate_icc() inside summarize_by_cell() now reads a column whose standard deviation is below .Machine$double.eps or not finite again with .constant_column(), the pool's test, and skips it only where neither its raw values nor its values centred and scaled show spread beyond their rounding. On the rows with a cell id, such a column with spread is z-scored from .spread_scaled(), which divides by powers of two; the ICC does not change under a shift and a scale. Where the standard deviation is finite and at or above the floor, the raw arithmetic is as it was. A new internal .cell_sd() returns sd(x, na.rm = TRUE) where that is finite and at or above .POOL_Y_MIN (1e-150), and elsewhere the standard deviation of .spread_scaled() of the values times its scale. The ..sd_ closure and .col_stats() call it. After the summarise, a cell whose standard deviation is still Inf raises a warning of the new class "spatialkit_sd_overflow", whose fields `columns` and `cells` give the columns and the number of such cells of each. The internal documentation of .constant_column() names the Kish ICC as a reader. The 800-point layer now gives an ICC of 0.478 and a median standard error over the scale of 0.666 at every scale from 1 to 1e-100, and the ICC of the column near 1e200 is estimated. ..sd_*, ..se_* and the intervals follow the unit of the column from 1e150 to 1e-310, under deff = 1 and "kish", with no NA, no 0 and no warning. A column whose values are all equal still has an ICC of NA and standard errors of 0. A column whose standard deviation is below the floor and whose values differ only by their rounding (0.1 beside 0.3 / 3) still reads "the column does not vary", with standard errors of 0 in a cell whose values are equal and of the size of that rounding in a cell whose values differ. A cell whose spread is of order 1e308 still has ..sd_* of Inf and standard errors of NA, now with the warning. No default or error changes, and the one new class is that of the warning. ?summarize_by_cell gains a sentence on columns that differ only by their rounding and a paragraph on ..sd_* at any size and the new warning class. NEWS has two Bug fixes entries and nothing under Breaking changes. No frozen fixture record is retaken: the one frozen call that reaches the new ICC reading, values_constant, has a column of one value that .constant_column() keeps constant, and the raw standard deviation stays sd(x, na.rm = TRUE), so no ..sd_* record moves. No test is turned round. test-fix-cells-icc-small-units.R is new: the ICC and standard errors over the scale do not depend on the unit, rows with a cell id in small units beside rows with no cell id get the ICC, a column whose standard deviation overflows gets its ICC, a column of one value or of values equal to their rounding still does not vary, the standard deviation and standard error inside a cell and the interval of a cell do not depend on the unit, a cell beyond the largest double is named in the warning, and a column just above the floor keeps the ICC of its raw values.
On gridded locations the density partition depended on the unit and the origin of the coordinates. On a lattice many distances tie exactly, and the last bits of the coordinates, which move with the unit and the origin, settled the ties in four places: the neighbour searches of the density weights and the nearest-centre search of Lloyd's iteration counted exact ties alone; the first k-means++ centre was drawn from weights equal but for their last bits, which sample.int() read as different; the locations the random draws index were put in order by first coordinates equal but for their last bits; and of two starts whose sums agreed to rounding, the rounding chose. On a 40 by 30 lattice at 250 m the default resolution_profile() gave `loo` 0.2978 in EPSG:26915, 0.3068 in UTM 15N in US feet and 0.3006 with the false origin moved by 0.1 m, and `rss` 258.33, 270.72 and 258.80. A profile that drew a subsample took its rows in exact coordinate order, so it drew other locations after a change of origin: on a 50 by 40 lattice with no response, wss as a fraction of the total was 0.6958 in metres and in US feet and 0.6997 with the origin moved. The density partition now uses the pooling's tie rule: squared distances within .TIE_TOL (one part in ten million) of each other are a tie. .knn_locations() passes `tol = .TIE_TOL` to .knn_tied_rows() and .knn_exact_rows(), so a tie between neighbours goes to the lower first coordinate, then the lower second, and its FNN margin widens by .TIE_TOL. .nearest_exact() finds the least squared distance and then the lowest-numbered centre within .TIE_TOL of it, in two passes, and .nearest_centre()'s FNN re-check widens to .TIE_TOL. .wkmeanspp() draws the first centre on the weights with runs of near ties given the run's lowest value. A new .near_columns() counts first coordinates within .TIE_TOL of the extent as one column, and a new .locations_by_column() puts the locations of .density_kmeans() in order by column and then by the second coordinate. .density_kmeans() keeps a later start only when its sum is lower by more than .TIE_TOL. resolution_profile() orders its rows by .near_columns(), then the second and the first coordinate, the response and the predictors, under either kind. .values_at_nearest() takes the same tie between centres and widens its kd-tree shortlist by .TIE_TOL. .scored_edge_cells() searches every point row placed in a cell, and for a row the rule gives to a centre that ties with the strictly nearer centre of the cell holding it, the margin adds the row's distance from the bisector of the two, measured in the record's CRS and scaled to the join's CRS by the ratio of the centres' separations; every other row keeps the margin it had. The lattice above gives `loo` 0.3016 and `rss` 262.94 and the same regions in all three frames, and a uniform layer gives the profile it gave. The regions get_voronoi_seeds() and voronoi_seeds_kmeans() draw under partition = "density" no longer move with the unit or origin either. The cells are the same in another unit or origin as long as no coordinate moves by more than about a forty-millionth of the distance between neighbouring locations; coordinates rounded more coarsely, such as a lattice at 250 m stored in feet to four decimals, can still give other cells. On layers with near ties in distances, weights, first coordinates or starts' sums the regions, and every figure drawn from them, can differ from before for the same seed, under partition = "kmeans" too where two first coordinates are that close. A row the profile scores in the cell of the lower-numbered of two tied centres is assigned there by assign_features_to_polygons() and placed there by cell_values_at(), so summarize_by_cell() still reads `cells = "match"`. ?resolution_profile states the tie rules and the bound in place of the sentence that the cells still differed in another unit or origin; ?assign_features_to_polygons names the tolerance and the wider margin; ?summarize_by_cell names the tolerance; ?cell_values_at names it and says another unit or origin of the same CRS settles its ties the same way; and the diagnostics vignette names the tolerance. No default, class or error changes. NEWS has a new Bug fixes entry, the earlier Bug fixes entry on tied neighbours loses its sentence that the partition still counted exact ties, and the New features entry on the count record names the tolerance; nothing goes under Breaking changes. Fourteen frozen records are retaken. The lattice records profile_lattice_density, select_lattice_density_cp, select_lattice_density_moran_z_diagnostic, summary_lattice_density, seeds_lattice_density and kmeans_lattice_density move with the tie rules. profile_density_clustered, select_density_clustered_cp, select_density_clustered_elbow and select_density_clustered_moran_z_diagnostic, and under the k-means kind profile_geometry, select_geometry_elbow, profile_geometry_sac and select_geometry_sac_reliability, move with the new order: the clustered layer has one pair of first coordinates 7.5e-8 of the extent apart, which now count as one column. Turned round: "the kd-tree's search and the exact search pick by one rule, and the partition keeps exact ties" in test-fix-neighbour-ties.R, now "... counts near ties as ties"; "tied neighbour distances are settled by the kd-tree as the exact search settles them" in test-core-partition-properties.R passes .TIE_TOL and expects the first tied locations in coordinate order; "the nearest centre is the exact one where centres are nearly the same distance away" in test-core-values-at.R, now "centres whose squared distances agree to one part in ten million tie, and the lower number takes the point", with a case whose first kd-tree shortlist ends inside the tie; in test-core-gridded-ties.R the platform pins of moved rows (the polygons alone move rows on 15 of the 16 lattices under the density kind, not 11), of rows elsewhere, and of refused cells (s2 refuses a k-means cell on 15 of the 16 lattices, not 16, and a density cell on 11, not 10), the row a projected CRS puts elsewhere, the round trip through degrees and the cells of seeds moved by 1e-9; and the platform pin of rows on an edge in test-core-pipeline.R, now 0 2 0 0. The helper drop_in_own_crs() of test-fix-crs-area-refused-probe.R keeps a ring closed where the vertex it drops closes it, and "the cells of centres refitted to every point, returned in lon/lat, stop with the error where s2 refuses one" in test-fix-join-cells-degenerate.R uses the k-means kind, since s2 now refuses none of the density cells of its lattice. test-core-gridded-ties.R gains "a point two centres tie for goes to the lower-numbered one beyond the margin of an edge, and only such a point". test-fix-partition-ties.R is new: the lattice in three frames, the subsample, the bound in the help, the uniform layer, each tie rule and the assignment of a tied row.
A cell whose centroid shared its point with 8 other cells or more took the first 8 of them without a search, but .region_neighbours() found the point by exact equality. In another unit, or with the origin moved, rounding parted such centroids by a few units in the last place, and the cells were then searched for among themselves by those distances. Twelve cells of 1 to 12 rows on one point beside a 10 by 10 lattice of one-row cells at 250 m gave 3 cells other neighbours in feet and in US feet, and all 12 with the origin moved by 0.1 m. Since `tau2` is fitted over the layer, every pooled value of summarize_by_cell() moved, by up to 0.171 in feet and 0.208 with the origin moved, and so did the leave-one-out error of resolution_profile() on the same cells. Rows that carry a placeholder or a coarser unit's coordinates make such crowds. .region_neighbours() now finds points with the reach of a tie, .TIE_TOL times the largest absolute coordinate, through a new .shared_points(). Centroids that chains of pairs within the reach in x and in y link are one point while they lie within the reach of one another, and equal centroids are one point in any case. A chain that spans further is linked again at half the reach, the chains still too wide at a quarter, and so on; centroids left apart to the last fall back to exact equality. The linkage is in .reach_chains(), which puts each chain's centroids in squares of the reach's side counted from the chain's own least x and y, and .chain_span() measures a chain along one coordinate. A crowded point's centroids are ordered by region number, and each takes the first 8 of the others. No new constant is added. summarize_by_cell() gives crowded cells the same neighbours and pooled values in another unit and with the origin moved by little against the coordinates. On a point of nine or more centroids, centroids that lie within the reach of one another without coinciding (about 0.46 m at UTM northings) now take each other by ID, not by distance. The reach follows the largest coordinate, so with the origin moved far, to the corner of the data, such centroids can lie beyond it and their cells then take the nearest. A layer whose centroids are equal or further apart than the reach in x or in y gets the neighbours and values it got before. ?summarize_by_cell states the rule and the far-origin limit, and says values agree to rounding where three to eight centroids coincide, not three or more. No default, class or error changes. NEWS has a new Bug fixes entry, and the earlier Bug fixes entry on tied neighbours narrows "three or more" to "three to eight" and drops its sentence that with ten or more cells on one point which 8 each takes can still change. Nothing is added under Breaking changes. No frozen fixture record is retaken. One test is turned round in test-fix-neighbour-ties.R: "regions whose centroids coincide to rounding get the rule's neighbours on both paths" treats its triple of regions 25, 26 and 50, a few units in the last place apart, as one point, so at one neighbour region 25 takes 26 where the rule by distance took 50; its reference fnt_neighbours() gains the reach and the halving, and an expectation pins 25, 26 and 50 to 26, 25 and 25. The new test-fix-neighbour-crowds.R checks crowds of ten or more in metres, feet, US feet and with the origin moved by 0.1, with and without FNN, a crowd beside centroids that chain on beyond the reach, a crowd parted by rounding, summarize_by_cell() at UTM magnitudes, centroids within the reach against centroids beyond it, the far-origin case and its help and NEWS text, and .shared_points() against the rule written out.
cell_values_at(seeds = ) checked that some seed has the ID of a cell of `values`, and counted every seed whatever its geometry. A seed with an empty point, or a coordinate that is not finite or lies beyond 1e150, is the nearest seed of no location, yet it passed the check, and the coordinates were read only as given, so seeds that leave the globe in the working CRS (metres stamped EPSG:4326, a latitude beyond 90) passed too. Seeds that kept their IDs and lost their points left every location without a cell, and each location took the value of the cell of its nearest scored row with no error: the seeds of a tessellation of 107 cells, every point emptied, filled all 120 locations asked for, and so did the one seed with a cell's ID emptied among seeds numbered from 1001. A seed at a northing of 1e200 in EPSG:32618 came back finite in EPSG:32617 and was searched where it landed. .values_at_free_cells() took a cell as named by any seed with its ID, so a seed without a location kept that cell from a point placed by hand outside the boundary, and the 144 locations of that cell were filled. cell_values_at() now reads the seeds' coordinates as given with .values_at_xy() before any CRS work. The check counts only seeds with a location that carry a cell's ID; the check that waits for step 3 needs a seed with a location and an NA ID beside polygons in `values`, and reads the seeds with a location in the working CRS. Once the seeds are placed, a seed without a location as given has none there either, and when the seeds with cells' IDs have a location as given and none in the working CRS, the call stops before the free cells and before any search. .values_at_no_seed_cell() takes `nowhere`, `crs` and `seeds_crs` and returns the two new texts, and the first stop passes whether `values` carries polygons, so seeds with no location and IDs that are all NA keep the text for polygons. .values_at_free_cells() takes a cell as named only by a seed with a location in the working CRS. Such seeds now stop with an error, raised without a call and with no warning for seeds without a CRS: "every seed in `seeds` with the ID of a cell of `values` has no location", or, when they had one as given, a text that names the working CRS and the CRS of `seeds` (or says it has none) and points to sf::st_set_crs(). One seed with a location and the ID of a cell is still enough for the call to run. A seed with a coordinate beyond 1e150 is no longer searched where a move between CRSs puts it. Beside a seed without a location that carries a cell's ID, points placed by hand outside the boundary take their own cells. No default or class changes. ?cell_values_at says which seeds count. NEWS has a Bug fixes entry, and the entry for seeds whose IDs match no cell now says one seed with a location and a cell's ID is enough; nothing under Breaking changes. No frozen fixture record is retaken; no cell_values_at() call is recorded. One test is turned round in test-core-values-at.R: "`seeds` without a CRS beside rows with one are read as build_tessellation() reads a boundary without one" pinned the silent fill for seeds of which none has a location, and now expects the error with and without their CRS and no warning, and calls .values_at_bare_seeds() for the reader's own rule. Two tests are added there, "seeds with the IDs of cells and no location are refused, and one with a location suffices" and "seeds with the IDs of cells and no location in the working CRS are refused, and seeds that have one there run", and "points placed by hand whose IDs are all NA outside the cell polygons of `values` take the cells they generate, and the call is refused only when none does" gains a seed with a cell's ID and an empty point or x = Inf. No test file is new.
fit_gwr_model() regresses a response at a large offset about its centre, and residuals.gwr_fit() returns the residuals of the centred response, which carry no rounding of the offset. The second OLS test of .morans_ols_design() still allowed them the rounding of a regression at the full offset: 10 eps times the offset, about 2 at 1e15. So a GWR at a working bandwidth passed as an OLS fit, and residual_morans_i() with `null = "auto"` took the residual null with `exact` TRUE. On 300 points with z = 2 w + sin(x/2000) + cos(y/1500) + N(0, 0.5) and fit_gwr_model(d, "z", "p", bandwidth = 30), offsets 0 to 1e14 gave the randomisation null, E[I] -0.003344481605, z -2.80112244, p 0.00509252, while 1e15 gave the residual null, E[I] -0.003200223252, z -2.80823692, p 0.00498136; bandwidth 60 did the same (z 2.29550409 against 2.29111526). A new internal helper in R/evaluation.R, .morans_fit_centre(), returns the centre fit_gwr_model() took the response about, for a gwr_fit that records a finite non-zero centre and keeps a residual column of the data's length, which is when residuals.gwr_fit() returns the centred residuals; for every other fit it returns 0. Test 2 of .morans_ols_design() now puts the offset left after that centre on the intercept of the rounding design. With a centre of 0 it runs the old expression, so every other fit gives the same result to the last bit. Users now get at every offset from 0 to 1e15, at both bandwidths, the randomisation null with `exact` FALSE and offset 0's I, E[I], z and p, and compare_models() gives the same Moran columns. A GWR at a global window keeps the residual null with `exact` TRUE. The Details of ?residual_morans_i say the bound counts the offset the fit regressed the response at. NEWS adds a sentence to the Bug fixes entry on residual_morans_i() reading its response, design and residuals at their origin and unit. No frozen fixture record is retaken and no test is turned round. test-fix-moran-gwr-centre.R is new, with 4 tests: bandwidths 30 and 60 at offsets up to 1e15 and -1e15, a response four times wider stored at 4e15, a global window at 0, 1e8 and 1e15, and the cases in which .morans_fit_centre() returns 0.
estimate_sac_range(), make_folds(), resolution_profile(),
determine_optimal_levels() and fold_separation() dropped a row whose
geometry was empty or whose coordinates were missing, and kept a row
at Inf or beyond 1e150, or read it only after the projection or the
move into another CRS. On 300 points in EPSG:32617 with row 1 at
(Inf, 5e6) or (5e5, 1e200), estimate_sac_range() returned NA with "the
points have no extent", where the same row empty gives 35060.33; at
latitude 1e200 or 95 in EPSG:4326 it stopped with FNN's "Data include
NAs". make_folds(method = "block_kfold") stopped with "'to' must be a
finite number" on the Inf row and gave the 1e200 row a fold of its own
(299 and 1, against 59 57 67 58 58 for the row empty), random_kfold
put the row in a test fold, and cv_block_size_sweep() stopped in
make_folds(). resolution_profile() gave a WSS of NA at every level,
and with `sac` in EPSG:32617 a row at 1e200 in EPSG:32616 or 3857 was
moved to a finite point (WSS 9.98e11, against 3.12e11 for the row
empty); determine_optimal_levels() stopped with "missing value where
TRUE/FALSE needed". A prediction point at 1e200 in EPSG:32616 was moved
into EPSG:32617 and measured by fold_separation() ("prediction target:
60 point(s)" where 59 have a location) and by make_folds(method =
"nndm"), which gave 39363 training memberships against 39763.
make_folds()' probe of the rows read the layer as given: in EPSG:3857
a row at x = 1e200 made it wait without end on PROJ, and in a layer
without a CRS it widened the check's tolerance to 1e191, so folds
built on other data were accepted.
Two helpers in R/cross-validation.R, .located_rows() (not empty, finite
and within 1e150) and the phrase .UNLOCATED_WHAT, carry the test. The
bound is read on the coordinates as given, before the reduction to
points and before any move, and again after it.
estimate_sac_range() and make_folds() drop such rows before the
projection and log the rows that lose their location once projected
(a local .projected_located() in block_kfold, buffered_loo, nndm and
knndm). resolution_profile(), determine_optimal_levels(),
fold_separation(), .nndm_target() and .fold_sep_prediction_points()
empty them with .empty_unlocated() before the pointize and the move
and keep .located_rows() after it. resolution_profile() drops a row
that loses its location in the move into the CRS of `sac` with a
warning, where it stopped with "some points have no coordinates in the
CRS of `sac`", and boxes and balances the halves of the split again
from the rows each keeps. .fold_row_probe() empties rows without a
location, so the probe leaves them out as it leaves out empty rows.
Each case above now equals the same layer with the row empty
(35060.33; folds 59 57 67 58 58; row 1 in no test fold; WSS 3.11796e11
at the first level; 59 prediction points; 39763 memberships), and the
probe refuses folds from other data. The drop warnings and log lines
name these rows as points without a location, where they said "with
empty or non-finite coordinates". make_folds()' n_prediction_points no
longer counts an empty prediction point. Layers whose rows all have a
location give the same results as before. The help of the five
functions says so.
NEWS has a Bug fixes entry and nothing under Breaking changes. No
frozen fixture record is retaken. One test is turned round:
test-degenerate-geometry.R matches the new make_folds() drop text.
test-fix-unlocated-rows.R gains 14 tests, among them the probe in a
layer without a CRS and in EPSG:3857 and the split's halves after the
move into the CRS of `sac`.
ensure_stable_poly_id(make_valid = TRUE), the default, gave every row of a layer in longitude and latitude to s2's rebuild when sf::sf_use_s2() was on, valid or not. On nc.shp rows 1 to 8 in EPSG:4326, create_grid_polygons(nc8, cellsize = 0.1, crs = 4326) (127 cells) and target_cells = 40 (27 cells), every row valid under s2 and GEOS, no row came back unchanged: the corners moved by up to 6.96e-8, 6.22e-8 and 6.89e-8 degrees, and POLYGON rows came back MULTIPOLYGON. With s2 off no corner moved. create_grid_polygons_cached(nc8, cellsize = 0.1, crs = 4326) handed back cells 6.22e-8 degrees from those of create_grid_polygons(), with their types not kept. A new internal helper in R/stable-ids-cache.R, .make_valid_rows(), takes an sf or sfc. On a layer in degrees with s2 on it gives .safe_make_valid() only to the rows that s2's sf::st_is_valid(), or GEOS's check on the bare coordinates, does not call TRUE, and returns the other rows as they arrived. GEOS's check is read too because s2 calls valid a hole outside its shell, a part inside another part and a ring of collinear points: a 0.5 degree square with a hole outside it, taken to EPSG:32615, came back GEOS-invalid with an area of 2302.2 km2 and stopped st_intersection() with "unable to assign free hole to a shell", where s2 off gives a valid 2494.9 km2; now both settings give 2494.9 km2. Projected layers, layers with no CRS and layers in degrees with s2 off are repaired by GEOS on every row, as before. ensure_stable_poly_id() repairs the rows it returns with the helper; the repair of the copy the sort key is measured on is unchanged, so no ID moves. create_voronoi_polygons() matches its returned cells to the clipped cells through the same helper; the cells there are projected, so its result is the same. Users now get every valid row of the three layers above back identical to its input, of its type, with s2 on, and the cached grid's 127 cells match the builder's. The IDs equal those before on nc.shp's counties in EPSG:4267 and 4326, the eight rows in EPSG:4267, three grids and a hex tessellation in EPSG:4326, under both settings. ?ensure_stable_poly_id (`make_valid`) and ?create_grid_polygons_cached (Details) state the rule. NEWS has a new Bug fixes entry, and the sentence on the repair in the entry on the cache key and the s2 setting now says the same. No frozen fixture record is retaken and no test is turned round. test-fix-stable-ids-valid-rows.R is new, with 8 tests: valid layers under both settings, the pinned IDs, refused rows beside valid ones, rows s2 calls valid and GEOS does not, projected and s2 off layers, the Voronoi seeds in degrees, the cached grid and the help pages.
cv_block_size_sweep() stated its fits wrongly in four texts. With block_sizes = seq(50, 230, by = 20) and k = 5, max_fits = 20 stopped with "10 block sizes x 5 folds + 5 for the random reference = 55 model fits ... or lower `n_sizes` or `k`", and n_sizes = 1 gave the same refusal, since n_sizes is read only for the default ladder. On the default ladder with n_sizes = 1, k = 2 and max_fits = 3 the count of 4 fits included the random reference, and the advice named only n_sizes and k, neither of which can be lowered. With 200 points on an E-W transect 0 to 6000 m with 1e-6 m of jitter in y (EPSG:32632), every rung of the default ladder needs a grid of more than 1,000,000 blocks, and the sweep refused with "no block size leaves at least k = 5 blocks ... pass smaller `block_sizes`", where the rungs held too many blocks and smaller sizes are refused. On two clusters at opposite corners of a 5 km square (EPSG:32615) with block_sizes = c(300, 1600) and k = 5 the k column read 5, 5, 2 (12 fits), but the print header said 15 fits and the plot caption "5 folds per size, 15 fits in total". The max_fits refusal now picks its advice by ladder: pass fewer `block_sizes` or a smaller `k` with block_sizes supplied, lower `n_sizes` or `k` on the default ladder, and on either one pass include_random = FALSE when the count includes the reference. When every size of the default ladder is too fine the sweep refuses with a message that says so and names the largest size whose grid holds k blocks (1170 on the transect, which runs). The generic refusal keeps "pass smaller `block_sizes` or a smaller `k`" for a supplied ladder. A new internal helper, .sweep_fits_made(), sums the k column; print() and plot() use it, and the caption says "up to k folds per size" unless every row built k. The clustered header now reads 12 fits. attr(, "n_fits") stays the count planned, which the max_fits check reads. ?cv_block_size_sweep states the advice of both ladders in the fit budget section, the refusal of a ladder that is too fine in the ladder section, and what n_fits counts in the value. NEWS has a new Bug fixes entry. No frozen fixture record is retaken and no test is turned round. test-fix-block-sweep-text.R is new, with 7 tests: the refusals on both ladders with and without the reference, the transect refusal and the size it names, the fit counts of a clustered and a uniform sweep and of a subset, a fit_fn that fails on one fold, and the help page.
PROJ 9.5.1 moves a point out of Web Mercator into WGS 84 degrees in time that grows with x: 1.6 s at x = 1e17, more than 20 s at 1e19, and no return at 1e20. The package moves a caller's rows to EPSG:4326 for the record of locations that make_folds() keeps and the folds are checked against, and for the record of a fit's rows that compare_models() checks its AICc and LOOIC with. On an EPSG:3857 layer with one row at x = 1e20, make_folds() on every method, every cv_*() function, fold_separation(), compare_models_cv() and compare_models() with two or more AICc or LOOIC values did not return. The same move stalled ensure_projected(purpose = "area") and summarize_by_cell(area = TRUE) on a polygon with such a vertex, get_voronoi_seeds() given a resolution profile and points in degrees, get_voronoi_seeds(method = "kmeans") with a boundary in degrees and such a sample point, and harmonize_crs(target_crs = 4326) on such a layer. At x = 1e12, where PROJ returns, such a row came back at a finite, wrapped longitude. R/cross-validation.R now holds .LONLAT_MOVE_MAX (1e10, further from the origin than any projected CRS places a point of the Earth), .beyond_lonlat_move(), which reads every vertex of every part of a feature, and .lonlat_of_placed(g, crs). When `g` is projected and `crs` is in degrees, on any datum, the latter empties the rows beyond the bound with .empty_unlocated() and then moves the set; any other move is sf::st_transform() as before. .fold_row_probe(), .fit_rowset() in R/evaluation.R, both moves of .seeds_in_crs_of() in R/seeding.R, .align_crs() and .transform_or_stamp() in R/utils.R, and the move in harmonize_crs() go through it, and .crs_area_error() gives NA for a probe of a projected CRS with a coordinate beyond the bound. Users now get these calls back at once. The folds, the fits and the rows each function keeps are unchanged, and the far row is read as a row without a location. get_voronoi_seeds() with the profile gives 16 seeds, one empty, in 0.01 s; with method = "kmeans" it gives 5 seeds in 0.1 s and drops the far point with its warning about empty points; harmonize_crs() gives 60 rows, one empty; the area checks find the distortion unmeasured. A row at 1e12 moved into degrees now comes back empty. Layers in degrees or without a CRS, layers whose rows all lie within 1e10 of the origin, and moves into a projected CRS give the same results as before, to the bit. ?harmonize_crs says such a row comes back empty. NEWS has one Bug fixes entry. No frozen fixture record is retaken and no test is turned round. test-fix-fold-probe-far.R is new, with 17 tests over the fold probe, the row fingerprint, the folds, the seeds, the area check, harmonize_crs(), the shared moves and multi-part geometries; each test first mocks sf::st_transform() to refuse such a move, so a regression fails and does not hang.
.morans_i_for_k(), behind the counts of determine_optimal_levels() under criterion = "morans_i" or "combined" and the `moran_z` of those calls and of resolution_profile(), regressed the cell means on the cell design. Where the raw response lost its spread and was taken about its centre (1e12 or 1e15 plus a spread of a few units), the residuals were tested only against the centred cell means, so the residuals of an exact fit, the rounding of the offset, were scored: on 800 points, 30 of 30 random fits a + b w + c w2 at 1e15, and determine_optimal_levels() returned 10 11 at 1e15 where it returned 7 6 8 at 0. Where the cell means were regressed again about the centre, the residuals were refused when within three units in the last place of the raw response, the rounding of one row, though a mean of n rows has the rounding and the spread of a row over sqrt(n): 1e15 + 1e5 w + f on w gave NA at 20 to 80 cells, and the call fell back to the geometric ranking. .residuals_rounding() in R/pool.R takes two new arguments for residuals of means: `n`, the rows behind each mean, and `m`, the rounding of forming each mean. The bound is then the residual degrees of freedom (the means less the rank of the design) times the mean over the cells of (three units in the last place)^2 / n plus m^2, in the units of the response. Callers that pass neither get the old bound to the last bit. .morans_i_for_k() counts the rows with a response and all rows per cell on both the grouped and the loop path, fits the rows by OLS on the centred predictors and returns NA where their residuals are within the rounding of a row, as resolution_profile() reads its own; the fit is taken again about .residual_centre() where the centre is 0 and the rows' residual sum of squares is under 1e-12 of the response's. The cell-mean residuals are then read against the bound for means, with `m` the rounding of summing each cell's rows. Users now get the same counts and `moran_z` at offsets 0 and 1e15. Exact fits give NA at offsets 0, 1e6, 1e12 and 1e15, on cells of 1,200 to 2,200 rows, and on a predictor along which the response at 1e15 changes by a unit in the last place; determine_optimal_levels() gives 7 6 8 for the exact fit at both offsets. On 20,000 rows, the exact fits k 10 a 1e4 b 500 and k 15 a 100 b 5 were scored on the loop path at offset 0 and are now NA, and 2 + 0.05 ws with max_levels = 100 gives 9 8 10, the geometric fallback, with no finite `moran_z` where it gave 12 with z 0.372. 1e15 + 1e5 w + f gives the same I and z at 0 and 1e15; residuals that the rounding of a row holds (1e15 + 1e5 w + 0.3 f) give NA, and residuals above the bounds are scored as before. On a layer with real spread, resolution_profile() gives the `moran_z` and `cp` it gave. NEWS has one Bug fixes entry. No frozen fixture record is retaken and no test is turned round. test-fix-cell-moran-offset.R is new, with 8 tests: exact fits at four offsets and on 20,000 rows, the spread at 0 and 1e15, near-exact fits within the rounding of the sums, a smooth predictor at 1e15, determine_optimal_levels() at both offsets, and .residuals_rounding() with unequal cells, a design of rank 4 and `m`.
create_grid_polygons_cached() projected a boundary in degrees to the CRS create_grid_polygons() picks without `crs`, and with `crs` given the builder then transformed that copy to `crs`, where the uncached builder transforms the boundary once. On rows 1 to 8 of nc.shp in EPSG:4326 with s2 off, `cellsize = 0.1, crs = 4326` matched 0 of 127 cells of ensure_stable_poly_id(create_grid_polygons()) on geometry, corners off by up to 4.26e-13 degrees, and `cellsize = 10000, crs = 32617` matched 0 of 133, off by up to 9.83e-8 m; `target_cells = 40` did the same with either `crs`. The counts and IDs agreed. A boundary with no CRS and `crs` given differed too. ensure_stable_poly_id() with `make_valid = TRUE` gave the rows of a lon/lat layer that s2 or GEOS calls invalid s2's rebuild with s2 on, and s2's rebuild does not split crossing edges. A bowtie, a figure eight or a MULTIPOLYGON whose parts overlap, beside a 0.3 degree square in EPSG:4326, came back invalid under s2 and GEOS: sf::st_area() of the row stopped, and its EPSG:32615 copy cut by its bbox stopped with "TopologyException: side location conflict". With s2 off the row came back valid (s2 areas 1.19686e9, 4.2069e9 and 1.19685e9 m2). A new internal helper in R/stable-ids-cache.R, .grid_crs_arg(), reads the `crs` create_grid_polygons() is given, by name, partial name or position, and .grid_returned_in_degrees() uses it. create_grid_polygons_cached() still takes its key on the .project_for_grid() copy, so the keys are unchanged to the bit, and builds on the caller's boundary when `crs` is given, on the projected copy otherwise. .make_valid_rows() gives a row that s2's rebuild leaves invalid under s2 or GEOS GEOS's repair of the coordinates it arrived with, which is what the call gives with s2 off. A row still invalid after that, such as a polygon whose edges cross only as great circles, is returned as GEOS repaired it with one warning naming its rows. The help of ensure_stable_poly_id() (`make_valid`) says so. Users now get the uncached grid from the cached builder in every case above, under both s2 settings, and from ensure_stable_poly_id() with s2 on the row s2 off gives, valid under both checks; the square comes back as it arrived. A repaired row is keyed on GEOS's repair, so its ID is the one s2 off gives. With s2 on it was keyed from a second repair that drops the overlap of overlapping parts: in a layer of a 1 degree square overlapping a 0.6 degree square plus 111 small squares, that row was ID 52 with s2 on and 55 with s2 off, and is now 55 under both, and the rows that had IDs 53 to 55 with s2 on move down by one. NEWS has two Bug fixes entries. No frozen fixture record is retaken. Three tests are turned round: test-fix-stable-ids-valid-rows.R test 3 now expects GEOS's repair of the bowtie, not s2's rebuild; test-stable-ids-crossing-edges.R expects the Texas cell transformed to EPSG:4326 to come back valid with no warning; test-fix-cache-key-s2.R test 2 compares against the uncached grid of the caller's boundary. test-fix-cached-grid-crs.R and test-fix-stable-ids-crossing-edges.R are new: the four grid calls under both s2 settings, `crs` by position, partial name and as a layer, the keys against the old formula, the three layers with crossing edges, the overlapping parts layer and the great circle polygon with its warning.
A row with a coordinate that is not finite or lies beyond 1e150 has no
location, but several readers took it as one or moved it first.
harmonize_crs(), ensure_projected(target_crs = ) on a projected layer,
.transform_or_stamp() and .align_crs() moved such a row with
sf::st_transform(), which drops the vertex: two half-degree squares near
(-93.5, 45.4) in EPSG:4326, the second with a vertex at (1e200, 45.8),
(-93.4, 1e200) or (Inf, 45.8), came back with row 2 as a triangle of
1,088,897,076 m^2 (the square is 2,168,128,746). create_grid_polygons()
laid 55 cells over that triangle where it refuses the row empty, and
assign_features_to_polygons() joined the point (-93.85, 45.35) to it.
From EPSG:32616 a vertex at (3.2e5, 1e200) came back at (733095.47,
5751433.9).
With one of 300 sample points at (5e5, 1e200) in EPSG:32617,
voronoi_seeds_kmeans(k = 15) and get_voronoi_seeds(method = "kmeans", n
= 15) stopped with "no start gave a partition of the 300 point(s) into
15 cells"; in EPSG:32616 beside a boundary in EPSG:32617 the point was
moved to a finite place and clustered (seed x summing to 8300090 against
8255199 for the row empty), with no warning. A seed at Inf or 1e200
stopped create_voronoi_polygons() and build_tessellation(method =
"voronoi") in GEOS ("Could not locate vertex", "encountered NaN/Inf
numbers", "distance must be a finite value", "Points of LinearRing do
not form a closed linestring"); clip_target_for() stopped at Inf and
gave a target of infinite area at 1e200. One point of a `cover` at Inf
or 1e200 set the whole cover aside and the cells covered 5,334 km^2
against 10,516 km^2 for the point empty; a polygon cover in EPSG:32616
with a vertex at a northing of 1e200 became a boundary of 68,562 km^2
against 8,983 km^2. summarize_by_cell(deff = "variogram") correlated
such a point with its cell (standard error 0.5428794 against 0.6636533),
and kriging_adequacy() stopped at Inf and kriged from 1e200 (3272.494,
or 3274.911 with folds of 399 and 1, against 3264.932).
assign_features_to_polygons() joined a point at 1e200 in EPSG:32616 to
the cell of EPSG:32617 the move put it in.
The bound is now read on the coordinates as given, before any move, with
.unlocated_features() and .empty_unlocated(), and again after it
(.values_at_xy(), .located_rows()). Every move of a caller's layer goes
through .transform_keep_unlocated() in R/crs-geometry.R:
harmonize_crs(), ensure_projected(), .transform_or_stamp() and
.align_crs() in R/utils.R, .cover_follow() for the builders' `cover`,
the move of the polygons into a scored record's CRS in
assign_features_to_polygons(), and .values_at_free_cells() of
cell_values_at(). get_voronoi_seeds(), voronoi_seeds_kmeans() and
.scored_seeds_record() in R/seeding.R; create_voronoi_polygons(),
build_tessellation(), clip_target_for() and .build_point_cell_index() in
R/tessellation.R; summarize_by_cell() and .cor_stats_from_coords() in
R/assignment.R; and kriging_adequacy() empty such rows as given.
.transform_keep_unlocated() now moves with .lonlat_of_placed() in place
of sf::st_transform(), so a row of a projected layer with a coordinate
beyond 1e10 is still emptied before a move into a CRS in degrees, as
harmonize_crs(), .align_crs() and .transform_or_stamp() did before this
change; without it a row at x = 1e20 in EPSG:3857 went back to PROJ,
which does not return. .lonlat_of_placed() reads the source CRS alone,
so a layer in degrees with a longitude of 1e200 no longer draws sf's
warning "bounding box has potentially an invalid value range for longlat
data" from ensure_projected() or cell_values_at(). The comments of
.lonlat_of_placed() and .transform_keep_unlocated(), and ?harmonize_crs
(Value), name both bounds.
Users now see such a row read as the same row empty: the moved square
comes back as POLYGON EMPTY, the grid is refused, the join gives NA; the
seeds sum to 8219723 (EPSG:32617) and 8255199 (EPSG:32616) with the
warning "dropping 1 point(s) without a location (an empty point, or a
coordinate that is not finite or lies beyond 1e150)."; 29 Voronoi cells
over 1e10 m^2 with one NA in `index`; a clip target of 8,197,779,700
m^2; covers of 10,516 and 8,983 km^2; a standard error of 0.6636533; and
3264.932 from kriging_adequacy(). Warnings and log lines that said "with
empty or non-finite coordinates" or "empty geometry" now count these
rows as rows without a location. The help of
assign_features_to_polygons(), build_tessellation(),
create_voronoi_polygons(), ensure_projected(), get_voronoi_seeds(),
harmonize_crs() and voronoi_seeds_kmeans() says so. NEWS widens the
entry on rows moved to another CRS and has a new Bug fixes entry; the
entry on rows beyond 1e10 now names the warning as one about points
without a location. Nothing is under Breaking changes.
No frozen fixture record is retaken. Expectations on message text are
turned round, with the same assertions, in test-fix-cells-seed-index.R,
test-fix-texts-misstated.R (four), test-review2-assignment.R,
test-review3-S2-tessellation.R, test-seeding.R and test-audit-pass5.R.
test-fix-unlocated-rows.R gains tests for the moving readers, the
seeders, the Voronoi cells and clip target, point and polygon covers,
the variogram design effect on points and polygons, kriging_adequacy()
and the scored join and free cells. test-fix-fold-probe-far.R gains a
test that the shared move empties both a row beyond 1e150 and a
projected row beyond 1e10 moved into degrees, a polygon cover included,
and a test that it moves a layer in degrees with a longitude of 1e200
without that warning.
estimate_sac_range(detrend = "reml") handed nlme::gls() the predictors and the response as given, and gls() fails on a column such as 1e8 plus a spread of 1. The estimate then warned that the REML detrending "did not converge", detrended by OLS and returned the OLS range and nugget. On 600 points with z = 2 w + field + noise and a predictor at 1e8 or 1e15 plus w, it gave detrend_method "ols", a range of 1428.861 and a nugget of 0, where the predictor at 0 gives "reml", 1561.566 and 0.02143349. On 300 points with the response at 1e8 or 1e12 it gave "ols" and a range of about 1400 with a nugget of 0, against the REML range 1361.364756 and nugget 0.01423461 at 0; at 1e7 the REML range moved in the fifth digit. Two subsamples were drawn by position from rows in the exact order of the first coordinate. After another unit or origin the first coordinates of one column of a lattice differ in their last bits, so the draws took other rows. On a 40 by 30 lattice at 250 m with reml_max_n = 300 the REML nugget was 0.20623529 in EPSG:26915 and in UTM 15N in US feet and 0.24105594 with the false origin moved by 0.1 m. With n_max = 300 the range was 646.9834 m in the first two frames and 794.7406 m in the third. In the REML branch of estimate_sac_range() the predictors and the response now go through .centre_columns() before .reml_trend(), with the gate of the OLS fit: a column whose centre is more than 1000 times its spread is taken less its centre. The structure test reads the same centred design. For the exact-fit test the response's centre is added back to the intercept, and the predictors' centres reach .rounding_design() through attr(X, "assign"), as in the OLS branch. Below the gate every fit gets the same frame to the last bit. .reml_trend() and the canonical row order of estimate_sac_range(), before ensure_projected() and the n_max draw, now sort by .near_columns() of the coordinates, then the second coordinate, the first and the other columns, as resolution_profile() does. First coordinates within 1e-7 of the diagonal of the bounding box count as one column. Where no two first coordinates come that close, the order is that of the coordinates, as before. Users now get the REML fit at any offset of a predictor or the response: offsets 0, 1e5, 1e8 and 1e15 of the predictor give "reml", 1561.566 and 0.02143349, and the response at 1e7, 1e8 and 1e12 gives 1361.364756 and 0.01423461, with no fallback warning. The lattice gives a REML nugget of 0.20623529 and an n_max range of 646.9834 m in all three frames; a jittered lattice keeps the results it had. The help of estimate_sac_range() says how the rows are ordered, and its claim that the result does not depend on the unit or the origin now holds for the subsample. NEWS has four Bug fixes entries, and the closing sentence of the entry on the OLS detrending at an offset now points to them. The frozen record profile_density_clustered is retaken: two points of that layer have first coordinates 1e-4 m apart on a layer 1,340 m across, which now count as one column, so the variogram's pair sums move in their last bits. No test is turned round. test-fix-reml-offset.R is new, with 9 tests: a predictor and a response at large offsets, the centred frame gls() gets, the exact-fit test with a factor and with the response at 1e8, and the REML and n_max subsamples of lattices across units and origins.
predict_surface() took a grid point's covariates from
sf::st_nearest_feature(), which settles a point the same distance from
several covariate points by the last bits of the distances. A grid laid
between the points of a lattice ties with four of them. On a 20 by 15
lattice at 250 m with the grid at the midpoints, 147 of 266 grid points
took another covariate row in UTM 15N in US feet than in EPSG:26915,
and 189 with the false origin moved by 0.1 m; `.pred` moved by up to
0.0305.
The `attr(, "kmeans")` record of get_voronoi_seeds() for the scored
centres of a profile or selection put each point with the seed
st_nearest_feature() returned. On a 40 by 30 lattice with the 267
centres of resolution_profile(seed = 1), `cluster` differed from the
metre record in 5 rows in US feet and 2 with the origin moved, 1 to 4
rows per frame were not in the cell the profile scored them in, and the
tot_withinss ratio was 10.792861 against the unit factor 10.763867, and
0.999679 with the origin moved.
coerce_to_points("auto") ordered tied midpoints of a MULTILINESTRING by
exact x, so two congruent parts whose midpoints share one x, reached
from other coordinates, were settled by the last bits of x. Over 200
origins 167 took the lower part and 33 the upper; in degrees 52 of 60
symmetric features took the southern part and 8 the northern.
All three now follow the package's tie rule: squared distances within
one part in ten million of the least are a tie, settled by the
.near_columns() column, then y, then the lower number.
predict_surface() calls the new internal .surface_nearest_rows(): for a
POINT covariate layer not in degrees it orders the covariate points by
column, then y, then row, and searches them with .values_at_nearest();
lines, polygons and points in degrees keep sf::st_nearest_feature().
.scored_seeds_record() in R/seeding.R assigns each cloud point with
.nearest_centre(), seeds numbered by seed_id, and leaves seeds without
a location out of the search. The MULTILINESTRING loop of
coerce_to_points() orders tied midpoints by column, y, Z or M, then x.
Users now get the same covariates at every grid point in all three
frames, with or without FNN, and `.pred` does not move. A grid point
that ties with no other point takes the row it took before. A point of
a grid kept as given with a non-finite coordinate or one beyond 1e150
now gets NA covariates; its `.pred` is NA as before. The seeds record
holds the profile's cells in every frame, the same rows as the metre
record, and tot_withinss scales by 10.763867 and 1.000000.
coerce_to_points() takes the lower part at all 200 origins in both
part orders, and the southern part of all 60 features in degrees.
?predict_surface (`covariates`), ?get_voronoi_seeds (Value) and
?coerce_to_points (Details) state the rule. NEWS has two new Bug fixes
entries, for predict_surface() and the kmeans record, and the entry on
coerce_to_points() and the longest part is amended. No frozen record is
retaken and no test is turned round. test-fix-nearest-ties.R is new,
with 12 tests: lattice midpoints in three frames and without FNN, the
row order of the covariates, untied, polygon and degrees controls, the
seeds record on a lattice and of a profile, a seed without a location,
tied midpoints at 100 origins, by the box diagonal and in degrees, and
the help pages.
ensure_projected() scored each candidate CRS on the points PROJ could place and left the rest out, so a UTM zone that cannot place part of a lon/lat layer could win. LINESTRING (0 0, 180 0) in EPSG:4326 kept UTM zone 46 (2.788 against 11.69 for the Lambert azimuthal CRS centred on (90, 0)), which places neither vertex, and came back empty with no warning. Five points on the equator at longitudes 0, 45, 90, 135 and 180 kept zone 46 (0.153 against 0.174) with 2 of the 5 rows empty. coerce_to_points() in mode "auto" or "line_midpoint" then handed the empty line to sf::st_line_sample(), which segfaulted and ended the R session; a lon/lat line with an Inf vertex did the same, and MULTILINESTRING ((0 0, 180 0)) under "auto" gave POINT EMPTY with no word. .pick_local_projected_crs() in R/crs-geometry.R now uses a candidate only if it places every located vertex of the layer, on the comparison path and on the purpose = "area" path. New helpers .located_vertices() and .places_vertices() test this with one sf::st_transform() of the distinct vertices per candidate; a vertex at a latitude beyond 90, which no CRS places, takes no part in the test. A candidate that fails gets distance_error NA, is not chosen and is named in the log line. When no candidate places the layer, the global fallback is used (EPSG:3857, Equal Earth for "area") with crs_choice NULL and its own log line, and the first-candidate fallback is now the first candidate that places the layer. .crs_distance_error() gives NA when a sampled point with a location cannot be placed. coerce_to_points() never passes to sf::st_line_sample() a line its temporary projection returns empty, short of vertices or not finite, in the LINESTRING and MULTILINESTRING branches. It stops with class spatialkit_features_degenerate, site "projection" and field crs, naming the rows and offering mode = "centroid" or tmp_project = FALSE (.raise_unplaced_lines(), new); .pointize_refused() in R/model-prep.R raises it again in the caller's words. A lon/lat line with a coordinate not finite or beyond 1e150 gets POINT EMPTY. ensure_projected() warns with class spatialkit_rows_unplaced (fields rows and n) when a move out of lon/lat leaves a located row empty or short of vertices (.rows_unplaced(), .warn_rows_unplaced(), .rows_text()). .values_at_place() in R/cell-values-at.R and .pooled_xy() in R/assignment.R, which report such rows in their own words, take the class over (.answer_for_classed()). Users now get the Lambert azimuthal CRS for the line and the five points with every row placed, and (90, 0) as the line's midpoint under "auto" and "line_midpoint". 39 stations over the conterminous United States with a row at (-96, 95) get the Lambert azimuthal CRS centred on (-96.7, 40.7) with 0.88%, as before, and the warning names the one row that comes back empty. Layers that every candidate places get the CRS, crs_choice, geometry and points they got. The help of ensure_projected() and coerce_to_points() states the placement rule. NEWS has a Bug fixes entry and nothing under Breaking changes. No frozen fixture record is retaken. Two tests in test-fix-unlocated-rows.R are turned round: resolution_profile() and determine_optimal_levels() on a row at (-80, 95) moved to EPSG:32617 now give the spatialkit_rows_unplaced line before the control's messages, with the values still identical. test-fix-crs-places-rows.R is new, with 15 tests: the line and the equator points, the NA score, the area path, the global fallback, layers placed as before, the distinct vertices, a row beyond latitude 90, the pooled readers, the warning, the midpoint, prep_model_data() and make_folds(), the refusal, its re-raise and the help.
kriging_adequacy() handed gstat::krige() its nmax with the points in the unit, origin and row order given. On a lattice several locations are often the same distance from a cell's centre or a held-out point, and gstat took its nmax among them by the last bits of the coordinates and by the order of the rows. On a 32 x 24 lattice at 250 m with 8 x 6 cells and nmax = 12, the same layer in US feet moved kr_pred in 26 of 48 cells, by up to 0.017, and the false origin moved by 0.1 m moved it in 27, by up to 0.031, kr_shift by up to 1.03 and the cross-validation statistic by 5e-4. On 18 x 8 at 250 m with 3 x 1 cells and nmax = 4, kr_n_used differed by up to 3, kr_pred by 0.28 and kr_gain by 1.1, and 20 entries were NA in one frame only. On a 30 x 30 lattice at 100 m with 3 x 3 cells and nmax = 20, the rows reversed moved kr_pred in 5 of 9 cells, by up to 0.0035, and the statistic by 9e-4. A location whose rows named cells 5 and 6 belonged to the cell of its first row, so both cells moved with the order, with no warning. Points XYZ throughout were kriged in three dimensions with a variogram fitted in x and y: on 400 points with heights of 0 to 1000 m, kr_pred differed in 16 of 16 cells, kr_var by 13 percent on average and kr_gain by up to 0.14. The kept rows now go in .canonical_order(), a new helper in R/kriging-adequacy.R: by the .near_columns() columns, then cell ID as text, then response, sorted by radix so text sorts the same in any locale. Each row keeps its position as given, so a location is held out under the fold of its first row as given and a vector of fold labels is read by position (.location_splits() and .fold_labels_for() take that position). A location whose rows name more than one cell is now no cell's own, with a warning giving the count; its rows still count in n, mean, se and plain_var of the cell each names. A second new helper, .tie_pick(), takes the k nearest by the package's tie rule (.knn_pick_rows(), .TIE_TOL) and says whether the k-th ties with the next. .cell_neighbourhoods() picks each cell's nmax and the locations added outside an enlarged cell with it, and counts whether a cell is enlarged with the rule's tolerance. A cell or held-out location whose nmax-th nearest ties with the next is kriged on its own from the rule's pick; untied ones stay in gstat's own nmax search, which picks the same set. The points are read with sf::st_zm(drop = TRUE) in place of .xy_if_mixed(). Users see every column and the statistic agree to 2e-12 across units, origins and row orders on both lattices above, the two-ID location in neither cell's own set (cell 5 kriged from 83 locations, cell 6 from 84) with the warning, and points XYZ or XYM throughout give the result of their XY copy. Layers with no tied distances give the same figures to rounding; a lattice takes longer. ?kriging_adequacy states the tie rule, its bound, the row order and the location named by two cells. NEWS has two Bug fixes entries and nothing under Breaking changes. No frozen fixture record is retaken. In test-fix-mixed-zm-summaries.R two tests are turned round: points XYZ throughout are now kriged as their XY copy, and the help test follows. test-fix-kriging-large-offset.R takes its reference mean over the rows in the canonical order. test-fix-kriging-ties.R is new, with 11 tests: units and origins on lattices, the enlargement tolerance, a jittered control, the tied route against gstat's search, row order, the location named by two cells, fold labels by position and by first row, .canonical_order(), points XYZ and XYM, and the help.
estimate_sac_range(detrend = "reml") handed nlme::gls() the coordinates, the response and the predictors as given. Where the REML range is not identified the likelihood is flat, the range runs to 1e8 m and more with a nugget proportion near 1e-6, and whether gls() returned a fit or failed on the same rows was set by the last bits of its input. On a 20 by 15 lattice at 250 m with reml_max_n = 100, EPSG:26915 gave detrend_method "reml" and a nugget of 0.2165, and UTM 15N in US feet and the false origin moved by 0.1 m gave "ols", a nugget of 0.1542 and the warning that the REML detrending did not converge. On a 24 by 18 lattice with reml_max_n = 120 it was the other way round. The response times 1000, or changed by two units in the last place, gave "reml" where the response as given gave "ols", and a predictor so changed did the same. estimate_sac_range() also passed .reml_trend() an extent with a floor of 1 in the layer's unit, so the same lattice at 25 m, 475 m across, gave "ols" and a nugget of 0.1542 in metres and "reml" and 0.2165 in km. .reml_trend() (R/cross-validation.R) now puts the coordinates of the rows it uses in the frame of .kmeans_frame(): centred on the middle of their bounding box, divided by its diagonal and rounded to 2^-30. The distances, the pair floor, the profile grid, the starts, every gls() call and the null model read that frame, and the range and pair floor are multiplied back by the diagonal, which .kmeans_frame() (R/partition.R) now returns as `scale`, with `mid`. The new helper .reml_value_frame() puts the response and each numeric predictor that is a term of its own in the frame of its range on those rows. The coefficients, sigma2 and both log-likelihoods are taken back to the layer's units. Formulas without an intercept and a response that is not a numeric column are left as they are. The extent floor is dropped, and an extent that is not finite or not positive reads as the diagonal. Users now get one detrend_method, one warning and one nugget for a layer in any unit or origin, and for a response or predictor scaled or changed in its last bits: 0.2165221642 in metres and km on the 25 m lattice. The range is NA on these lattices, before and after. On a 40 by 30 lattice whose REML range is identified the range is the same length in metres and in US feet, and on the same lattice jittered with reml_max_n = 150 it moves from 632.983630502 to 632.983627542. The help of estimate_sac_range() says how the REML fit reads its input. NEWS has one Bug fixes entry. No frozen fixture record is retaken. One test in test-fix-reml-offset.R is turned round: it compared the response a mocked gls() receives with the raw values and now compares it with their frame. test-fix-reml-frame.R is new, with 10 tests: lattices across units and origins, the data a mocked gls() receives, the range in the caller's unit, the jittered control, a layer under 1 km across in metres and km, the response and a predictor scaled and changed in their last bits, the coefficients and log-likelihoods against gls() on the data as given, a missing or zero extent, and the fields .kmeans_frame() returns.
ensure_projected() read a row of a lon/lat layer with a vertex at a latitude beyond 90 in the extent, the longitudes of the antimeridian test and the centre, though no CRS places such a row. 39 stations over the conterminous United States (longitudes -120 to -75, latitudes 30 to 47) get an Albers CRS with standard parallels 32.917007 and 42.998514 and lon_0 -96.698554, for both purposes. With a 40th row at (-96, 95) they got a Lambert azimuthal CRS with lat_0 40.674623 and lon_0 -96.700618, and the Albers candidate's parallels moved to 41.2 and 84.2. A row at (-100, -95) gave the Lambert azimuthal CRS with lat_0 38.373631, and a swapped row at (40, -96) gave it with lat_0 38.221954 and put the box 139.0 degrees from the zone's central meridian. The new internal helper .beyond_pole_features() in R/crs-geometry.R flags a feature with a vertex whose latitude is finite and beyond 90 in absolute value; it reads points, lines, polygons, multi types and collections, and skips the walk when the bounding box lies within [-90, 90]. .pick_local_projected_crs() empties those rows on its WGS84 copy with .empty_unlocated(), the whole row, as it does a row with a coordinate beyond 1e150, so the box, the wrap test, the centre, the parallels, the placement test and the scores read only the other rows. The test reads degrees on the EPSG:4326 copy, so a layer in grads is read in degrees too. The log line for a layer with no located row now names a latitude beyond 90. The 39 stations with any of the three rows now get the CRS and crs_choice they get alone. The layer returned is not changed by the choice: the row is still moved, comes back empty or without the vertices the CRS cannot place, and the spatialkit_rows_unplaced warning names it. A layer each row of which has such a vertex gets Web Mercator (Equal Earth for purpose = "area"). Layers with no latitude beyond 90 get the CRS they got. The help of ensure_projected() says the choice does not read such a row. NEWS has one Bug fixes entry. No frozen fixture record is retaken. One test in test-fix-crs-places-rows.R is turned round: it required the Lambert azimuthal CRS that the row at (-96, 95) or (40, -96) produced, and now requires the CRS of the 39 stations alone. The new test-fix-crs-lat-beyond-90.R has 5 tests: the helper on each geometry type and at latitudes 90 and 90.000001, the three rows with both purposes, a polygon row with one vertex beyond 90, a layer whose every row is beyond 90, and layers in NAD83 and in grads.
?resolution_profile and the NEWS entry for the density partition's tie rule said the cells stay the same in another unit or with another origin as long as no coordinate moves by more than about a forty-millionth (2.5e-8) of the distance between neighbouring locations, and that PROJ's rounding of about 1e-9 m is below that for locations more than a few centimetres apart. The tie rule counts squared distances within one part in ten million (.TIE_TOL, 1e-7) as equal, which keeps an exact tie between two centres only while the move is at most 1e-7 / (8 sqrt 2) = 8.8e-9 of the distance to them, and that distance is at least half the spacing: 4.4e-9 of the spacing. With a location midway between two centres 250 m apart, the location moved by +delta in x and both centres by -delta, a delta of 4e-9 or 5e-9 of the spacing kept centre 1, and 1e-8 or 2.5e-8 gave centre 2: a move inside the stated figure broke the tie. PROJ's 1e-9 m over 4.4e-9 is 0.23 m, not a few centimetres. The Details of ?resolution_profile, in R/resolution-profile.R, now say "about a two-hundred-millionth of the distance between neighbouring locations" and "more than about a quarter of a metre apart", the wording ?kriging_adequacy uses; man/resolution_profile.Rd is regenerated. The tie rule and .TIE_TOL are unchanged, so no result changes; users see the help state a bound the rule keeps. The development-version NEWS entry for the density partition's tie rule gives the same figure; there is no new NEWS entry. No frozen fixture record is retaken. In test-fix-partition-ties.R the help test is turned round: it pinned the forty-millionth and now pins the two-hundred-millionth and the quarter of a metre, and checks that the old figure and "few centimetres" are gone.
Five summaries read the spread of a column from values that carry the
rounding of a large offset. .compute_reg_metrics() took R-squared only
where the total sum of squares passed a test scaled by the sum of the
squared values: on 200 rows, R-squared was 0.80419 at offset 0, 0.80407
at 1e14, and NA with adjusted R-squared at 1e15, with RMSE computed.
.estimate_icc() read a column whose values differ only by their
rounding (a0 or a0 (1 + eps)) as one that does not vary only while its
standard deviation was below eps: the same values times 16, 1024 or
2^20 got a Kish ICC of 0.3946 and a design effect, while the pooled
summary of the same call said the column does not vary.
prep_model_data() took the shift of the dropped rows from the raw
means: a shift of 0.75 gave 0.865940 SD at 0 and 1e5 and 0.929802 at
1e15, with "not missing at random" only at 1e15, and a response of one
value up to rounding read "a difference of 1.61 SD" from its last bit
at 1.23, 4.5e6 and 1e15. .standardise_by() in the Bayes model scaled a
column a + {-1, 0, 1} ulp by 7.53e-10 at 4.5e6 and 0.106 at 1e15, and a
transect at x = 4.5e6 with jitter in the last bit got an x scale of
7.7e-10. A GWR fitted about a centre was scored on its fitted values
and predictions in the response's units: on 300 points with bandwidth
60, in-sample RMSE was 0.49543466 at 0 and 0.49555314 at 1e15 with
R-squared NA, and cv_gwr() gave RMSE 0.6553265 at 0 and 0.6531574 at
1e15.
.compute_reg_metrics() keeps its raw test and, where it fails, computes
R-squared when the response is not constant by .constant_column(); it
gains a `centre` argument, a scalar or one per row. .estimate_icc()
reads .constant_column() at the all-values gate and at the gate of the
rows with a cell id, and z-scores a column with spread from
.spread_scaled(). prep_model_data() takes the means and standard
deviation less .regression_centre() of the response and adds the
centre back only to the means its message quotes; a response of one
value up to rounding gets NA. .standardise_by() keeps the caller's mean
and sd only where the raw values show spread, and asks
.constant_column() elsewhere. New helpers .gwr_predict_centred_at() and
.gwr_predict_rows() sit behind predict.gwr_fit(), whose return value is
unchanged, and .scored_fitted() and .scored_predictions() in
R/model-classes.R feed model_metrics(), summary(), evaluate_insample(),
compare_models(), the cross-validation folds and
select_features_forward()'s score_holdout. The centred path is taken
when the predict arguments are empty or are list(se.fit = FALSE).
.cv_centred_columns() fills the centred columns of folds fitted without
a centre when a run mixes both, and .cv_overall_metrics() reads them.
Users now get R-squared 0.80351 at 1e15 where it was NA, ICC NA with
"the column does not vary" at every scale for a column that differs
only by its rounding, a shift of 0.865940 SD at every offset, a Bayes
scale of 1 for a rounding-only column at every size, and for the GWR
in-sample RMSE 0.49543466, MAE 0.40823795, R-squared 0.95501081 and
cv_gwr() RMSE 0.6553265, R-squared 0.9218483 at every offset. The
predictions of a cross-validation whose folds fit about a centre gain
the columns y_centre, yhat_centred and y_train_mean_centred; yhat stays
in the response's units. Responses and columns whose raw values show
their spread give the figures they gave. The help of model_metrics(),
fit_gwr_model(), cv_gwr(), cv_spatial(), compare_models(),
evaluate_insample(), prep_model_data() and summarize_by_cell() states
the change. NEWS has two new Bug fixes entries, on R-squared at a large
offset and on the shift of the dropped rows, and extends the entries on
the Kish ICC, the Bayes standardisation and the GWR fitted about a
centre.
No frozen fixture record is retaken and no test is turned round.
test-fix-spread-summaries.R is new, with 20 tests, and a test title in
test-fix-gp-prefit-offset.R now names the gate of .standardise_by().
On a box with no height the Albers candidate's standard parallels fall
back to 5 degrees either side of the centre on the sphere. A line along
one parallel that spans 180 degrees of longitude runs over the pole, so
its centre is the pole: on LINESTRING (0 45, 180 45), (0 20, 180 20),
(0 60, 180 60), (-10 70, 170 70) and (0 -30, 180 -30) the parallels
were 85 and 95 (-95 and -85 in the south), and ensure_projected()
stopped with "invalid crs: +proj=aea +lat_1=85.000000 +lat_2=95.000000"
with either purpose. Centres near a pole but not on it did the same:
(0 80, 160 80), centred on (80, 88.2), gave lat_2 93.2. With purpose =
"area" a point layer stopped too: a point at (10, 89) ("lat_1=84
+lat_2=94"), at (10, 85.5) or at (10, -87), and two points along 87N.
Every function that moves such a layer through ensure_projected()
stopped with it.
A new internal helper in R/crs-geometry.R, .albers_parallels_ok(),
holds the cone test as before and requires both parallels to lie
between -90 and 90; PROJ builds lat_2 = 90 and refuses 90.0000001, so
the bound is inclusive. The purpose = "area" path and the comparison
path of .pick_local_projected_crs() call it in place of the inline cone
test, and an Albers candidate that fails it is left out of the
comparison, as a degenerate cone is. The parallels are not clamped.
Users now get, on the five lines above and with either purpose, the
Lambert azimuthal equal-area CRS centred on the pole (lat_0 90, or -90
for the south line); its worst distance error on the line at 20N is
21.91% against the zone's 181.36%. The lines off the pole and the point
layers with purpose = "area" get the Lambert azimuthal CRS centred on
the data; with purpose = "distance" the points keep their UTM zone. A
point at (10, 85), whose parallels are 80 and 90, keeps its Albers
candidate. Layers whose parallels lie in range get the CRS, the
crs_choice and the geometry they got, identical() on 13 layers with
both purposes. ?ensure_projected says the Albers conic is scored where
its parallels do not degenerate or pass a pole. NEWS has one Bug fixes
entry.
No frozen fixture record is retaken and no test is turned round.
test-fix-crs-albers-pole.R is new, with 4 tests: the helper's bounds
and cone test, the lines near a pole with both purposes, layers in
range left as they were, and point layers near a pole.
make_folds() let the last bits of the coordinates decide three ties. A lattice point on the edge two blocks share went to the first block sf::st_intersects() found it in, which was the lower block only while the edge passed through the point exactly. On a 37 x 25 lattice at 250 m, 3 x 2 blocks put 469 of 925 rows in another fold with the false origin moved by 0.1 m, 4 x 3 blocks 448 rows in UTM 15N in US feet and 824 with the origin moved, and block_size 1500 m 745 rows with the origin moved. The block counts behind the leakage advice disagreed as well: on 36 x 24 cells the polygon count gave 864, 576 and 680 occupied cells in metres, US feet and the moved origin, and the fast count 864, 612 and 681. With the origin moved, the selection half of select_on = "split" on a 40 x 30 lattice moved by 786 rows, and the rss of resolution_profile(select_on = "split") was 131.8186 against 122.8157 in metres. Lattice points on a `boundary` drawn through them were read as outside: on 469 points clipped to a triangle the call warned about 8 (US feet) to 50 (km) of them and extended the block region from 27,000,000 m^2 to 40,500,000 m^2. A point outside every supplied block as near two went to whichever which.min() met first (3 to 10 of 72 such points moved in feet, kilometres and moved origins). method = "buffered_loo" kept a neighbour at the buffer distance in one frame and excluded it in another: on a 20 x 15 lattice with buffer 500 m, 295 of 300 training sets differed in US feet and 253 with the origin moved. Two new internal helpers in R/count-rule.R, beside .edge_tol(), hold the ties. .edge_join() gives each point the lowest index of the polygons it lies within .edge_tol() of, one part in 1e10 of the largest coordinate of both layers; on projected layers it buffers the smaller layer by that margin and calls st_intersects(), and in degrees it uses st_is_within_distance() with s2 on and st_intersects() with s2 off. .lowest_nearest() gives each row of a distance matrix the lowest column within the tie tolerance of its smallest distance. In R/cross-validation.R the block join of make_folds(block_kfold), for the grid and for supplied blocks, the `boundary` test and .block_occupied() use .edge_join(); .block_occupied_fast() reads a quotient within the margin above a whole number as that number before ceiling(); a point in no supplied block, and the grid's centroid fallback, use .lowest_nearest(); and buffered_loo compares distances with the buffer times sqrt(1 + .TIE_TOL). Users now get the metre folds in every unit and origin: 0 rows in another fold on every lattice above, 864 occupied cells in every frame, identical split halves and rss 122.8157, no boundary warning and 27,000,000 m^2 of blocks, and mean buffered_loo training sizes of 288.15 and 275.08 in every frame. An edge point goes to the cell to its left or below, or to the lower row of supplied blocks. The count of points outside the design and its warning are unchanged, and a point 1 km outside the triangle is still warned about. Layers whose points sit off the block edges and the buffer distance get the folds they got. ?make_folds now matches its roxygen on params$blocks$source_row. NEWS has one Bug fixes entry. No frozen fixture record is retaken and no test is turned round. test-fix-fold-ties.R is new, with 14 tests: block edges in three frames for the grid and supplied blocks, the boundary, the fast and the polygon block counts, the split halves, buffered_loo at the buffer, outside points as near two blocks, the two directions of .edge_join() and .lowest_nearest(), with jittered controls.
.compute_reg_metrics() took the sums of squared errors and deviations on the values as they stand. For 200 rows with R-squared 0.768 scaled by 2^-540, every squared error fell below the smallest double: RMSE was 0 and R-squared 1, and at 2^-560 R-squared was NA. Scaled by 2^510 to 2^540 the sums passed the largest double: RMSE was Inf and R-squared NA. One prediction of 1e200 among the 200 gave RMSE Inf where it is 7.07107e198, and the response c(x, x/2, x/4, -x/8) with x the largest double gave RMSE Inf and R-squared NA. The scores reach model_metrics(), summary(), evaluate_insample(), compare_models(), the folds and pooled scores of the cv_*() functions and compare_models_cv(), and select_features_forward(). .compute_reg_metrics() now reads a sum again only where it is not finite, or is below n * .POOL_Y_MIN^2 while its own terms are not all 0: RSS on y and yhat, TSS on y and the baseline. The other sum keeps its value, so a far prediction or baseline does not move the scale of the sum it is not part of. New internal helpers in R/utils.R: .pow2_floor() gives the power of two at or below a value, capped at 2^1023; .mean_pow2() takes the mean of y divided by that power, since mean() of values near the largest double can be Inf or -Inf where a long double is no wider than a double; .ss_pow2() returns a sum of squared differences as m * (s * f)^2, the differences divided by the power of two at or below their largest absolute value, and taken on the halves (f = 2) where a difference overflows. RMSE is multiplied back, and R-squared takes the ratio of the sums as m_rss / m_tss times the square of the ratio of their scales, 0 for an exact fit. The test on TSS reads y in the units of that scale. .constant_column() takes y as before. Users now get, for every scale 2^k from k = -900 to 1000, RMSE over the scale 1.0079481633, R-squared 0.76766134 and adjusted R-squared 0.76648791. One prediction of 1e200 gives RMSE 7.07107e198 and R-squared -Inf, and the largest-double response gives R-squared 0.6023391813, that of the same values at unit size. RMSE is Inf only where it passes the largest double. MAE, MAPE and SMAPE do not change, and where both sums lie between n * 1e-300 and the largest double every score is as it was, to the bit. NEWS has a new Bug fixes entry on RMSE and R-squared for a response whose squares underflow or overflow. test-fix-metrics-range.R is new, with 11 tests. No frozen fixture record is retaken and no test is turned round.
.pick_local_projected_crs() measured how far a lon/lat box reaches from the central meridian of its candidate UTM zone as the larger of abs(lon_min - cm) and abs(lon_max - cm), not wrapped. The zone comes from the centre on the sphere, which for a layer across a pole, or one whose longitudes are given outside -180 to 180, can lie far outside the box, and ensure_projected()'s comparison warnings then quoted figures above 180. For two lines from (-10, 70) to (170, 70) and from (-10, 75) to (170, 75) the warning said the extent "reaches 257.0 deg from the central meridian of UTM zone 16"; points at longitudes 170, 185 and 200 gave "reaches 377.0 deg ... UTM zone 1". Points at 181 and 183, 2 degrees from that meridian, were said to reach 360.0 degrees and got an Albers CRS, and points at -181 and -183 the same against UTM zone 60. A new internal helper in R/crs-geometry.R, .lon_offset_from(), wraps each end's difference to 0 to 180, keeps the larger, and gives 180 when the meridian opposite cm lies in the box; a box or meridian that is not finite gives a figure that is not finite. .pick_local_projected_crs() reads its offset from it, and the 5-degree test that sends a layer to the comparison of candidates and both warnings read that one figure. Users now see 180.0 for the lines across the pole, with the same CRS, candidates and distance error, and 17.0 for 170, 185 and 200 with the same choice. Points at 181 and 183 keep UTM zone 1 (EPSG:32601) and points at -181 and -183 keep UTM zone 60 (EPSG:32660), as layers at -179 and -177 or at 179 and 177 do. Other layers get the CRS and the crs_choice they got. NEWS has a Bug fixes entry for the offset. No frozen fixture record is retaken and no test is turned round. test-fix-crs-lon-offset.R is new, with 5 tests: the helper against a brute-force maximum, the polar lines, layers whose choice and log stay as they were, the boxes beyond 180 and -180, and the 377.0 example.
predict_surface() took a grid point's covariates from a layer of lines or polygons by sf::st_nearest_feature(), and a grid point on the edge two polygons share, or at the shared end of two lines, is at distance 0 from both, so GEOS gave it either one. On 10 by 8 square cells of 500 m with w the row number, 72 grid points on the shared vertical edges and lm(z ~ w) fitted on a 20 by 15 lattice at 250 m, 34 of the 72 took another cell (another w and .pred) than in EPSG:26915 with the false origin moved by 0.1 m, and 29 with the rows of `covariates` shuffled. Lines did the same: 21 to 27 of 72 shared ends did not take the left segment in a frame, and 26 to 36 with the rows shuffled. A point of a grid kept as given at x = 1e200 got the covariates of a row GEOS gave it: w = 1 2 1 and .pred = 1.048 2.048 1.048 with lines or polygons, and w = 1 71 1 with any layer in degrees, where ?predict_surface (`grid`) states NA. .surface_nearest_rows() sends a layer that is not in degrees and not all POINT to a new helper, .surface_nearest_shapes(). It takes the least distance d from st_nearest_feature(), and the features within d * (1 + 1e-7) plus .edge_tol() of the layer's box are a tie. They are shortlisted by st_intersects() of a square around the point, then by the distance from the point to each feature's bounding box, then kept by st_distance(). The tie goes to the feature whose box centre is in the lowest column by .near_columns(), then the lowest by the same rule on y, then the lower row of the layer. A point with one nearest feature takes the row it took before. Point layers keep the search of cell_values_at(), and a layer in degrees keeps st_nearest_feature(), now asked only for grid points with a location. A grid point without a location gets NA covariates whatever the layer. Users now get the cell or segment to the left for each of the 72 edge points and line ends in EPSG:26915, in UTM 15N in US feet, with the origin moved and with the rows shuffled, with the same w and .pred in each. The point at x = 1e200 gets w = NA and .pred = NA for every layer. The shortlist keeps far grid points cheap: 10,000 points over 24 km against 3,600 cells take 2.4 s. ?predict_surface (`covariates`) states the rule for lines, polygons and mixed layers. The NEWS entry under Bug fixes on predict_surface() ties now covers features, with the figures above, the rule, layers in degrees, and the NA for a grid point without a location. No frozen fixture record is retaken and no test is turned round. test-fix-surface-edge-ties.R is new, with 14 tests: edge points in three frames, row order, line ends, a tie 100 m outside the layer, a near miss, empty grid points and covariate rows, the unit ranking, an oblique tie, unlocated grid points for each layer type, y by the column rule, the relative reach, the dispatch for layers in degrees, the distances measured far from the layer, and the help text.
make_folds(method = "nndm") and method = "knndm" let the last bits of the coordinates choose the folds of a lattice. NNDM took each point's neighbours in the order FNN's kd-tree or order() gave equidistant ones, broke ties between held-out distances by the exact order of the coordinates, and compared its distances with the target and with `phi` exactly. On a 20 x 15 lattice at 250 m predicted onto a 30 x 25 lattice at 400 m from 3 km outside, 195 of the 300 training sets in UTM 15N in US feet differed from those in EPSG:26915, and 234 with the false origin moved by 0.1 m; the training rows were 60670, 61078 and 60845. With phi = 500 m, n_removed_total was 2675, 2188 and 2363. max_ecdf_excess was 0.42, 0.42 and 0.413 with prediction points 250 m apart beside the lattice, and max_ecdf_deficit 0, 0 and 0.003. kNNDM gave Ward's method and its k-means the coordinates as given and took the centre FNN or sf::st_nearest_feature() returned, so with k = 5 and seed 1 on the same lattice 170 (US feet) and 290 (moved origin) of the 300 rows were in another fold, with W 1191.21, 1223.84 and 1288.05 m. A chain of candidates with W = 1, 1 - 0.6e-7 and 1 - 1.2e-7 returned the third, where ?make_folds said the earlier of two within the tolerance. In R/cross-validation.R, .nndm_tie_key() ranks points by the column of .near_columns(), then the second coordinate, then the row. The new .nndm_neighbours() and .nndm_sort_rows() give each point its k nearest by squared distance, distances within .TIE_TOL a tie ordered by that key; an FNN shortlist is rechecked and the same answer comes without FNN. They replace get.knn() and the twin repair. The sweep takes the least value of each run of distances within .TIE_TOL, and its insertion, G_target(r), `phi` and the floor warning's excess_phi count distances within that part as equal. .ecdf_deficit() evaluates at at * (1 + .TIE_TOL), and .nndm_reach() reads the target as separated only when max(g_target) * (1 + .TIE_TOL) < min(loo_fin). In .knndm_folds() and .knndm_kmeans(), hclust(), k-means and .ward_from_groups() read .kmeans_frame(xy)$z, with held-out distances and W in the layer's unit as before; .nearest_centre() gives a point as near two centres to one part in ten million the lower one, with or without FNN; and the earliest candidate whose W is within .TIE_TOL of the least is returned, the random partition first. Users now get the same folds and figures in metres, US feet and a moved origin: 60670 training rows in all three, 2675 rows removed at phi = 500 m and 1812 at phi = 250 * sqrt(2), equal ECDF figures, and the kNNDM folds with W 1349.59 in every frame. These need not be the folds any frame gave before. The mocked W chain returns the second candidate. params$target_separated, and the out-of-reach warning it raises on small samples, take a prediction distance within one part in ten million of a leave-one-out distance as not shorter. Jittered layers keep their folds. ?make_folds states the rules for phi, separation and the choice among candidates. NEWS has one Bug fixes entry. No frozen fixture record is retaken and no test is turned round. test-fix-fold-ties.R gains tests of NNDM and kNNDM folds in three frames, of phi at a lattice length, of the tie key, of the ECDF figures, of equal and chained W among kNNDM candidates, and of the separation rule.
The last bits of the coordinates, which move with the unit and the false origin, settled ties in the tessellation builders and in cell_values_at(). On a 40 x 30 lattice at 250 m with square cells of 1000 m, build_tessellation() put 80 of 1200 points in another cell in UTM 15N in US feet than in EPSG:26915, 235 in kilometres and 226 with the origin moved by 0.1 m; with hexagons, 156 with the origin moved. Of 180 points just outside the cells beside corners two boundary cells share, 4 to 27 were snapped to another cell in other frames, since st_nearest_feature() picked either of two cells the same distance away. Triangles of a 37 x 25 lattice were 1728 in metres and US feet (860 of them other triangles) and 1823 to 1827 in other frames, 95 to 99 of them flat. create_voronoi_polygons() merged near-coincident points by ten decimals of the unit: 60 points with copies of 20 moved by 1e-9 m gave 80 cells in metres, 62 in US feet, 79 with the origin moved and 60 in kilometres. create_grid_polygons(cellsize = ) read a 9000 m side as 9.0000000000001741 cells of 1000 m with the origin moved and laid 60 square cells, the smallest of 5e-8 m^2, against 54, and 79 hexagons against 76. cell_values_at() without `seeds` broke a tie between two scored locations of one column by their exact x: 2 of 14 locations midway between two points of a 20 x 15 lattice's first column took the upper point with the origin moved. In R/tessellation.R, .build_point_cell_index() joins points to cells with .edge_join() and a margin of .edge_tol() of the cells' box, skips rows without a location, and gives a point in several cells the smallest cell_id. A new .snap_lowest_cell() gives a snapped point the smallest cell_id among the cells within its distance times (1 + .TIE_TOL) plus that margin. build_tessellation(method = "triangles") hands geometry::delaunayn() the points in the frame of .kmeans_frame() and draws the triangles on the points' own coordinates; the GEOS fallback does the same in the new .triangulate_in_frame(). create_grid_polygons() counts the cells per side with the new .grid_side_counts(), which reads a side within .edge_tol() of a whole number of cells as that number, for a caller's `cellsize` and for the side `target_cells` derives, and the new .drop_edge_slivers() drops a clipped part that lies within that margin of its cell's edge (not for grids in degrees). In R/utils.R, .dedup_points() keys each located vertex by its place in the frame of .kmeans_frame(), and its unused `digits` argument is gone. In R/cell-values-at.R the scored locations are ordered by .near_columns() of x, then y. Users now get the same index, snapped cells, triangles, Voronoi cells, grid and fill in every unit and origin tried: 0 points in another cell on both layers, 162 and 1728 triangles with none flat, 60 Voronoi cells, 54 square cells and 76 hexagons, and the lower point of the column. params$snapped no longer lists a point within the margin of an edge. Copies 1e-6 m apart on that 5 km layer, which were kept, now merge (80 cells before, 64 after). The help of build_tessellation(), create_grid_polygons(), create_voronoi_polygons() and cell_values_at() states the rules. NEWS has five Bug fixes entries and nothing under Breaking changes. No frozen fixture record is retaken. One test is turned round: in test-fix-s2-boundaries.R, the test that a cell s2 reads with two corners as one point names the clip in degrees reached that error through the extra row of cells; it now expects the 4 parts of the grid, and checks the error and its message with the side counted as sf counts it. test-fix-tessellation-ties.R (13 tests) and test-fix-values-at-column-ties.R (3 tests) are new. The merge applied without conflicts and needed no further change.
assign_features_to_polygons() found a point on the edge two polygons share in both only while the edge passed through it exactly. The last bits of its coordinates put it a hair inside one or the other, and the bounding-box centres that `tie_break = "smallest_area"` compares were compared exactly, so the unit and the origin of the coordinates chose the cell. On a 37 x 25 lattice at 250 m in EPSG:26915 and a 10 x 7 grid of square cells over it, 25 of 925 rows went to another cell with the grid built in UTM 15N in US feet and 11 with the false origin moved by 0.1 m; with the grid moved with the points, 13 rows moved with the origin, and `tie_break = "first"` did the same. Polygons of one area and one bounding-box centre went to the first in the rows of `polygons_sf`, where the help said the choice does not depend on their order: of the two triangles of a split square, points on the diagonal went to T1 as given and to T2 with the rows swapped; a square and a rhombus of its area about its centre, and one polygon under two IDs, went to whichever came first, with no warning, in the join by `predicate` and in the largest-overlap join. With the default `predicate` (sf::st_intersects), the join is now .intersects_margin(): the exact hits, and for POINT and MULTIPOINT features also the polygons .edge_join() finds within one part in 1e10 of the largest coordinate of the polygons (.edge_tol()). Lines and polygons get no margin, and another `predicate` is applied as given. A new .tie_rule_rows() keeps, per feature, the candidates of least area, then key by key those within that margin of the least: bounding-box centre y, x, then the mean of the vertices y, x (.vertex_means(), from .polygon_sort_keys()). The predicate join and .largest_overlap_ties() both use it. A feature still left with more than one candidate gets an NA ID, is counted in attr(, "ties") and listed in its new element `unresolved`, is kept or dropped as `keep_unassigned` says, is not counted as unassigned, and raises a warning of class spatialkit_ties_unresolved (data `n` and `total`). Users now see every row of the lattice in the same cell in every frame, under both tie-breaks, and a jittered control is unchanged. A point 1e-5 m east of a shared edge, as a POINT or a MULTIPOINT, is a tie the rule decides; a line along the edge stays in the cell it lies in. The triangles go to T1 in both orders, by vertex means (66.7, 33.3) and (33.3, 66.7). The square and rhombus and the polygon under two IDs give NA in both orders with the new warning. Points off the edges, and features whose candidates differ in area or centre, are assigned as before. The help of `predicate` and `tie_break` states the margin. NEWS has one Bug fixes entry and nothing under Breaking changes. Two frozen fixture records are retaken, assigned_units_lonlat and values_units_lonlat: a lon/lat point on the units' outer edge came back a hair outside after the move into EPSG:32632 and was dropped; it is now assigned, 400 rows with the GEOIDs of the metre record. Tests turned round in test-core-gridded-ties.R (the cell counts and edge rows on lattices, the sphere and meridian points, and the point 1e-5 east of an edge, now in cell 1, with a mirrored case added) and in test-core-pipeline.R (`on_edge` c(0, 2, 0, 0) to c(0, 6, 0, 6), with a check that those rows lie on a boundary). test-fix-assignment-ties.R is new, with 13 tests: the frames, the margin, degrees with s2 on and off, the triangles, unresolved candidates, the order of the centre keys in both joins, exact hits kept on a bowtie, MULTIPOINT features, and the help and NEWS sentences.
predict_surface() with lines or polygons as `covariates` settles a distance-0 tie by the features' bounding-box centres, read by .near_columns(), whose step was a part in ten million of the diagonal of the centres' own bounding box. Where every centre lies on one point that box is last-bits small, and the last bits of the centres, which move with the unit and the origin, chose the feature. A 1000 m square with a 500 m hole and the island that fills it, alone in the layer, with five grid points on the hole's ring, gave the square (`w` 1) in EPSG:26915 and in UTM 15N US feet and the island (`w` 2) with the false origin moved by 0.1 m, where the centres differ by 9.31e-10 m in y; `.pred` was 0.7378 against 0.7308. Two lines crossing at their midpoints, and a ring of 32 sides with the disc that fills its hole, took the second feature in US feet or with the origin moved, where the centres differ by 2.33e-10 or 5.82e-11 in x. .near_columns() in R/partition.R takes an optional extent `ex`, by default the diagonal of the points' own bounding box as before, so its other callers do not change. .surface_nearest_shapes() in R/predict-surface.R passes the diagonal of the layer's bounding box to both the column and the row read, so centre x values and y values within that part of the layer's diagonal are one column and one row, and the tie goes to the lower row of the layer. Users now see the same feature, `w` and `.pred` in every frame for each of the three layers above, in both row orders. Layers whose centres part by more than the step take the feature they took. The help of `covariates` in ?predict_surface states the extent. The NEWS entry on surface ties for lines and polygons states it and adds the polygon with a hole and its island; nothing under Breaking changes. No frozen fixture record is retaken and no test is turned round. test-fix-surface-edge-ties.R gains tests of the polygon with a hole and its island, of the crossing lines and the ring with its disc, and of .near_columns() with and without an extent, and its help-text test reads the new wording.
Six paths ran in silence, gave base R's, sf's or GEOS's bare message, blamed the wrong cause or measured in the wrong unit: - resolution_profile() with `predictor_vars` on which no row is complete fit OLS on zero rows. On 400 points that all carry a response and a predictor that is NA on every row, rss, cp and moran_z were NA at 6 of 6 levels, with base R's "number of rows of result is not a multiple of vector length", a log line saying the raw response was scored, and summary() saying "cp needs a response". - cell_values_at() without `seeds` read only the geometry type of `values`, so a `values` of POLYGON EMPTY rows filled 120 of 120 locations with cell_id NA and nothing said. - create_voronoi_polygons() and build_tessellation(method = "voronoi") on points none of which has a location gave 0 cells and sf's "x contains no geometries of specified type", or stopped with GEOS's "BufferOp::getResultGeometry distance must be a finite value". 20 points at latitudes 91 to 95 in EPSG:4326 did the same after the move to the working CRS. - get_voronoi_seeds() ignored `seeds` under "kmeans" and "random", and `sample_points` under "random", in silence. `seed = 1` is matched to `seeds`, so two such calls gave two different layouts. - create_grid_polygons() returned 0 cells without a word when the clip left none: the box (-179, -80) to (179, 80) at cellsize c(358 / 3, 10), and build_tessellation() then gave NA for 50 of 50 points. - build_tessellation() on cells in degrees held its snap tolerance in degrees against distances in metres, so on a 0.1 degree grid a point 1.2 m outside its cell was NA (21 NA, 0 snapped). With s2 off it stopped with "there is no package called 'lwgeom'". resolution_profile() now skips the fit when no row is complete and raises spatialkit_no_scored_rows with or without the split; the bounds record carries n_response_only, and summary() and select_resolution() (cp, moran_z) name the predictors through the new .no_complete_row() and .no_complete_text(). cell_values_at() refuses a `values` none of whose polygons has a location, after .drop_empty_parts(), so rows of MULTIPOLYGON(EMPTY, cell) still run. create_voronoi_polygons() refuses points with no location before the cover and boundary branches, and points the move to the working CRS leaves without one get their own refusal, named by create_voronoi_polygons() or build_tessellation(voronoi), whichever made the move. .build_point_cell_index() no longer returns early on zero cells, so spatialkit_unassigned gives the count there too. get_voronoi_seeds() warns for each argument the method ignores, after the checks that would refuse the call, and returns what the call without it returns. create_grid_polygons() stops with "the clip to `boundary` left zero cells", naming the cause and the remedy in degrees with s2 on; build_tessellation() and create_grid_polygons_cached() pass it on. In .build_point_cell_index() the snap tolerance for cells in degrees is the median cell width as an arc in metres, the nearest cell and the distances are taken under .with_s2(), and the log line names the unit. Users see a refusal or a classed warning in place of the silent or bare results above. On the 0.1 degree grid, 20 points are NA (all 21 m or more out) and 1 is snapped with s2 on, and with s2 off 0 are NA and 2 snapped. Projected and CRS-less cells are indexed as before. The help of resolution_profile, get_voronoi_seeds, create_grid_polygons and build_tessellation is updated, and six Bug fixes entries are added to NEWS; nothing under Breaking changes. No frozen fixture record is retaken and no test is turned round. The new test-fix-guards-sibling.R holds 17 tests of the refusals, the warnings, their controls and a point the planar and spherical nearest cells disagree on.
Four subsamples were drawn, or thinned, by row position, so their results moved with the row order of the input: - summarize_by_cell(deff = "variogram") on a cell of more than `deff_max_n` points. One cell of 1500 uniform points at the default deff_max_n = 500 had `..se_resp_z` 0.2613 with its rows as given and 0.2550 reversed, and `cell_weight` 12.77 against 13.36. - area_of_applicability() with more training rows than `normalizer_max_n`. 1000 rows at normalizer_max_n = 300 gave a normaliser of 1.018 as given and 1.155 reversed, and DI and the threshold with it; with `threshold = 0.0065` supplied, 2 of 500 inside or outside calls differed. - gp_lengthscale_bounds() above `max_n` distinct locations, and the GP prior and basis fit_bayesian_spatial_model() and cv_bayes() build from it. 1500 locations gave bounds of 675.7 and 2810.3 as given and 684.0 and 2822.3 reversed. - The GP pre-fit check of fit_bayesian_spatial_model() and cv_bayes() on more than 1500 rows, which thins the rows at even steps. On 2400 rows, 10 row orders gave Moran's I from 0.031 to 0.061 at a floor of 1140 m, so the status was "below_floor_long_range" in 4 and "below_floor" in 6. Each now orders the rows before the draw, with .canonical_order() of R/kriging-adequacy.R, the coordinates passed again so that the exact coordinates decide after the .near_columns() keys. .cor_stats_from_coords() (R/assignment.R) orders the cell's points by their coordinates. .aoa_normalizer() (R/area-of-applicability.R) orders the predictor matrix by its columns in turn and the location matrix by its coordinates. gp_lengthscale_bounds() (R/model-prep.R) puts the distinct locations in coordinate order before .safe_dist(). .gp_floor_moran() (R/model-bayesian.R) takes its even steps through the rows ordered by coordinates, then the response and the predictors, and still draws no random number. The located-row filters that run before these draws are kept. Users now get one result for the input in any row order: the cell above gives 0.2592 and 12.96, the normaliser 1.124 with no call differing, the bounds 683.4 and 2822.3, and the pre-fit check I 0.049 and "below_floor" in all 10 orders. Under each cap nothing is drawn and every figure is as before; above it the subsample is another one, so the figures differ from before for the rows as given. The help of `deff_max_n`, `normalizer_max_n` and `max_n` says the subsample does not depend on the row order. NEWS has one Bug fixes entry and nothing under Breaking changes. One frozen fixture record is retaken, values_variogram_max_n (summarize_by_cell(deff = "variogram", deff_max_n = 5) on the number-count cells), whose 5-point subsamples are now drawn in coordinate order. No test is turned round. test-fix-subsample-order.R is new, with 14 tests: each subsample in random row orders, on uniform points, gridded cells and layers, tied integer and indicator-coded predictors, a supplied threshold and twice-visited sites, with the results under each cap and the random stream left as it was.
Two functions drew the starts of one level from a stream that the other levels of the call had already drawn from, so a count's cells moved with arguments that should not reach them: - determine_optimal_levels() under criterion = "morans_i" and "combined" drew the integer that seeds the re-runs in the window after the sweep, which takes more draws the more counts it runs. On 480 points in twelve clusters (set_seed = 123, top_n = 3), max_levels 30 and 31 both put the elbow at 12 and the window at 8 to 16, but moran_z at 14, 15 and 16 cells was -0.449, -0.447 and -0.585 against -1.265, -0.408 and 0.528, and "morans_i" returned 15, 14, 16 against 15, 16, 10. - resolution_profile() ran every level's partition on one stream in ladder order, so a level's cells, and wss, rss, cp, moran_z, loo and the other columns read off them, depended on the levels before it. On the same layer at seed = 123 the 20-cell k-means level had wss 106785.80 and moran_z 0.647 on the ladder 10, 20, 30, 40 and 106029.56 and -1.024 on 20, 30, 40; the density partition gave 109735.12 against 113160.10. select_resolution() on the even counts to 36 from 6, 8, 10 and 12 chose 34, 36, 30 and 28 under "cp" and 18, 26, 30 and 28 under "loo". determine_optimal_levels() (R/level-selection.R) now reads the re-run integer before the sweep, with the bound .Machine$integer.max - n_uniq, and puts .Random.seed back after the read, so the sweep starts where it did; each re-run keeps .with_seed(rerun_seed + k) and its restore. resolution_profile() (R/resolution-profile.R) draws one integer after the subsample and before the variogram, and runs each level's .partition_centres() under .with_seed(level_seed + L), restored in tryCatch(finally = ). Users now get, for one seed, the same cells and scores for a count in any window or ladder that holds it. On the layer above moran_z at 14 to 16 is -0.729, -0.536 and -0.421 for max_levels 30 and 31, the counts 16, 15, 10 under "morans_i" and 12, 13, 14 under "combined"; the 20-cell level has wss 107615.29 and moran_z 0.111 on every ladder, and "cp" and "loo" choose 32 on all four ladders. The sweep, the elbow and the geometric ranking are as before. Profiles, selections, seeds and cells for a given seed differ from before. With set_seed = NULL the re-runs no longer draw from the caller's stream, and with seed = NULL the levels take one draw from it in place of their own draws. The Details of ?determine_optimal_levels and `seed` of ?resolution_profile say so; the latter adds that on a layer of more than sample_n rows a ladder of counts and a ladder of sizes are fitted to other rows and can give a level other cells. NEWS has two Bug fixes entries. The entry on re-runs seeded per count now says the integer is drawn before the sweep and gives the first counts 16 at top_n 1 to 4, 17 at 5 and 6 and 19 at 7; the entry on the 40 x 30 lattice at 250 m and the gridded k-means entry give loo 0.3066 and 0.2929. 169 frozen fixture records built on a profile are retaken (profiles, summaries, selections, the select_*_moran_z refusals, seeds, cells, counts, values_selection, small_five_rows* and print_default_digits); no levels_* record moves and the other 192 are unchanged. Tests turned round, as they pinned what the old streams drew: the partition arguments, convergence, reference and defaults tests replay the engine on the level's stream; count-rule, count-loo, gridded-ties, pipeline, values-at, partition-ties, texts-misstated and the white-noise structure test take the new figures; the levels re-run test takes the new wording; and the no-structure test lets through the spatialkit_bound_chosen warning a white-noise optimum at the ladder's first level now raises. test-fix-streams-per-step.R and its helper helper-level-streams.R are new: max_levels 28 to 32 under both criteria, ladders of counts and sizes in both kinds, the count chosen on four ladders, each level's starting state, and the stream after a call with seed = NULL.
Five constructors and entry points took inputs that disagreed with each other and went on in silence or stopped late: - new_spatial_fit() built a fit whose formula and `predictor_vars` disagreed. `price ~ elev` with `predictor_vars = "slope"` printed a model of elev while area_of_applicability() measured distances in slope and residual_morans_i() rebuilt the OLS design from it. - cv_spatial() scored a fold's predictions against `response_var` without checking that the fold's fit models it. A fit_fn that fits price, called with `response_var = "slope"`, gave 3 of 3 folds ok and an RMSE of 16.03, a fit of price scored against slope. - kriging_adequacy() kriged each location once, so hand-built folds whose test sets shared rows kept the last fold's prediction. 200 points with rows 1 to 50 in every test set gave a variance of the z-scores of 0.978021 and 0.988830 with the folds in two orders. - kriging_adequacy(folds =) read a vector of labels against the rows kept, so with one response set to NA a vector of 200 labels, one per row, stopped after the variogram fit with a message saying the labels must have one entry per row. - create_voronoi_polygons() and build_tessellation(method = "voronoi") handed on a seeds layer's record of its count unchanged when the seeds were fewer or more. A selection's 32 seeds cut down to 16 gave 16 cells whose record said 32 with scored_cells TRUE, and summarize_by_cell() warned spatialkit_cells_differ while every row was assigned. new_spatial_fit() (R/model-classes.R) now stops, unless the right side of `formula` holds `.`, when `predictor_vars` names a column the right side's all.vars() does not hold, or when the right side uses an attribute column of `data_sf`, other than the response and the reserved names ..x and ..y, that `predictor_vars` does not name. The message names both arguments and says what to do: name the column in `predictor_vars`, or give a column the fit derives itself a name that is not a column of `data_sf`. .cv_fit_one_fold() (R/cross-validation.R) fails a fold whose fit's `response_var` is not the call's, compared without names, with both names in fold_status; cv_block_size_sweep() and select_features_forward() run their folds through it, and the hold-out score of select_features_forward(select_on = "split") is NA with a warning for such a fit (R/feature-selection.R). In R/kriging-adequacy.R, .location_splits() refuses folds whose test sets share a location before the variogram, naming the location's row and the two folds by their positions in `folds`, and .fold_labels_for() reads a label vector of one per row of `assigned_points_sf` by position, or one per row kept as before; any other length stops at entry with its length, the number of rows and, when rows were dropped, the number kept. .seeds_count_rule() (R/tessellation.R) gives seeds that are not their record's count the record with scored_cells FALSE, as get_voronoi_seeds(method = "provided") marks them. Users see an error in place of a fit whose parts disagree; a fit_fn that derives coordinates x and y on a layer that keeps x and y as columns is refused, and offset() and grouping columns count as used. cv_spatial() fails every fold of a fit of another response, with 0 of 3 folds and the cause in the all-folds-failed warning. Shared test locations are refused; the 200 labels above now give k 4, n_pred 199 and a zscore_var of 1.054370641, identical to the labels of the rows kept. The 16 cut-down seeds give cells whose summary reads "not checked: other cells were built from this count", with no warning. The help of new_spatial_fit, cv_spatial, kriging_adequacy, create_voronoi_polygons and build_tessellation is updated. NEWS has one Breaking changes entry for new_spatial_fit() and four Bug fixes entries. No frozen fixture record is retaken. Four tests are turned round: the left-side test of new_spatial_fit() now passes `predictor_vars = character(0)` with `cbind(price, elev) ~ 1`, the oracle backend of the area of applicability tests builds its formula from its predictors, the count-rule test of a selection's twenty seeds expects scored_cells FALSE and the "not checked" summary, and kriging_adequacy(folds = 1:5) expects the new length message. test-fix-entry-checks.R is new, with 15 tests, and test-fix-new-spatial-fit-args.R gains tests of the right-side rule, the reserved names, the trend-surface message and the help.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.