#duplicates #raster #side-effects #terra
#дубликаты #растр #побочные эффекты #terra
Вопрос:
При изменении некоторых атрибутов дублируемого SpatRaster
, оригинал также изменяется:
library(terra)
r <- rast(ncol=2, nrow=2, vals=c(5.3, 7.1, 3, 1.2))
#class : SpatRaster
#dimensions : 2, 2, 1 (nrow, ncol, nlyr)
#resolution : 180, 90 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : proj=longlat datum=WGS84 no_defs
#source : memory
#name : lyr.1
#min value : 1.2
#max value : 7.1
xmin(r)
#[1] -180
t <- r # duplication
xmin(t) <- -300 # xmin modification of the duplicated SpatRaster
xmin(r) # the original SpatRaster has also been modified
#[1] -300
Это ошибка или выбор? Это происходит только для некоторых атрибутов, а не для всех. Если это выбор, как создать «независимую» копию или как разорвать ссылку?
Ответ №1:
Это произошло потому, что SpatRaster — это просто оболочка вокруг объекта C . Это создает x
(ниже) мелкую копию (т. Е. Указывает на тот же объект в памяти)
library(terra)
r <- rast()
x <- r
Это имеет значение только в некоторых случаях, при использовании методов замены (на ваш пример больше не влияет current terra
). Я также добавил copy
метод, который возвращает глубокую копию, то есть SpatRaster, указывающий на другой (глубоко скопированный) объект C .
Комментарии:
1. Спасибо, это понятно. Вы правы, сохранение таких побочных эффектов может вызвать недоумение.
Ответ №2:
Для информации, функция add
имеет ту же проблему (в terra
1.0.11):
logo <- rast(system.file("ex/logo.tif", package="terra"))
nlyr(logo)
[1] 3
r <- logo
add(r) <- r[[1]]
nlyr(logo)
#[1] 4
Комментарии:
1. Это сделано намеренно — и это совсем другой случай.
2. Спасибо. Какова цель такого поведения в случае функции
add
?3. Пользователи не могут заранее знать, какие функции вызовут такие побочные эффекты, а какие нет. Это должно быть где-то объяснено. В противном случае нельзя писать надежные скрипты. Или следует указать, что никогда не следует выполнять простые назначения растров, а всегда делать печатные копии?
4.
function(x) <- value
всегда меняетсяx
— поэтому поведениеadd
должно быть таким, как ожидалось. Чего еще вы могли ожидать? .
Ответ №3:
Здесь может быть недопонимание, особенно от меня. Тот факт, что add(r) <- r[[1]]
изменения r
абсолютно нормальны, как вы указываете. Но тот факт, что он также изменяется logo
, вовсе не является обычным ( add
предполагается, что функция добавляет слой к r
, а не к какому-либо другому объекту, не связанному с текущей строкой скрипта, согласно документации).
Если я правильно понял, и, как вы объясняли ранее, это потому r <- logo
, что не дублирует logo
(глубокое копирование), а только создает указатель (мелкую копию) на logo
. Этот выбор имеет важные последствия для использования terra
объектов, поскольку последующие модификации r
также изменят logo
объект («побочный эффект», с точки зрения пользователя). Я вижу здесь как минимум 3 пункта:
- Необычное поведение. Возможно, пользователь должен быть предупрежден.
«В семантике R объекты копируются по значению. Это означает, что изменение копии оставляет исходный объект нетронутым. «: глубокие или отложенные копии являются основным правилом R (https://rlang.r-lib.org/reference/duplicate.html ). Поэтому пользователь должен хорошо знать, что простые назначения в terra
( r <- logo
) копируются не по значению, а по ссылке, в противном случае высок риск ошибки в сценариях. Однако это необычное поведение в настоящее время не объясняется в документации terra
.
- Мелкие копии — это скорее инструмент, ориентированный на программиста.
Когда пользователи понимают, что terra
копии являются мелкими копиями, они, вероятно, чаще всего предпочитают делать глубокие копии, потому что использование мелких копий для terra
пользователей, вероятно, ограничено и редко. Я не вижу слишком много случаев, когда такое поведение было бы полезно. Глубокие или отложенные копии гораздо чаще встречаются у пользователей.
- Неоднородное поведение в зависимости от функций
Но это не главный вопрос. Основная проблема в том, что на данный момент некоторые операции влияют как на исходный объект, так и на скопированный объект, а другие — нет. add
изменяет исходный объект (побочный эффект), но res
не изменяет его :
logo <- rast(system.file("ex/logo.tif", package="terra"))
nlyr(logo)
# [1] 3
res(logo)
# [1] 1 1
r <- logo
add(r) <- r[[1]]
nlyr(logo)
# side effect of add function on the number of layers
# [1] 4
res(r) <- c(10,10)
res(logo)
# no side effect of res function on the resolution
# [1] 1 1
Если все эти предположения верны, было бы полезно объяснить, какие функции после назначения влияют или не влияют на исходный объект, иначе невозможно надежно программировать.
Комментарии:
1. Спасибо за отличное разъяснение — хотя, возможно, имеет смысл отредактировать ваш вопрос, чтобы я мог ответить на него правильно. Но я попробую здесь:
res
возвращает новый объект и позволяет избежать проблемы с мелким копированием. Это можно легко сделать.add
не создает глубокую копию, потому что это очень дорого, и причина добавления заключается в том, чтобы обеспечить эффективное добавление слоев. Однако я могу изменить значение по умолчанию, чтобы оно создавало глубокую копию, если не указано иное.2. Я понимаю. Поскольку это преднамеренный выбор для повышения эффективности
terra
, мне кажется необходимым для надежности программирования перечислить на страницеterra:copy
справки точный список функций иterra
операторов, которые работают по ссылке. Один из других (нечастых) пакетов, которые сделали этот выборdata.table
. На странице справкиdata.table::copy
четко указано, что функцииdata.table::set
и:=
оператор являются единственными случаями, когда не создается печатная копия. Трудно писать надежныеterra
сценарии без этой информации.