1

当修改一个 duplicated 的一些属性时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

是错误还是选择?它只发生在某些属性上,而不是全部。如果是选择,创建“独立”副本的方法是什么,或者如何断开链接?

4

3 回答 3

0

有关信息,函数add有同样的问题(在terra1.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
于 2021-01-17T22:44:48.367 回答
0

这里可能存在误解,尤其是我自己。正如您所指出的,add(r) <- r[[1]]变化的事实是绝对正常的。r但它也发生变化的事实logo根本不是例行公事(根据文档,该add函数应该添加一个层r,而不是与当前脚本行无关的任何其他对象)。

如果我理解正确,并且正如您之前解释的那样,那是因为r <- logo不会复制logo(深拷贝),而只会创建指向logo. 这个选择对对象的使用有重要的影响,terra因为以后的修改r也会修改logo对象(从用户的角度来看,这是一个“副作用”)。我在这里至少看到 3 点:

  1. 不寻常的行为。也许应该警告用户。

“在 R 语义中,对象是按值复制的。这意味着修改副本会使原始对象保持不变。”:深度或惰性副本是 R 的基本规则(https://rlang.r-lib.org/reference/重复.html )。因此,用户必须清楚地知道terra( r <- logo) 中的简单赋值不是按值复制,而是按引用复制,否则脚本出错的风险很高。但是,这种不寻常的行为目前没有在terra.

  1. 浅拷贝更多是面向程序员的工具。

当用户明白terra副本是浅副本时,他们可能最喜欢制作深副本,因为对terra用户使用浅副本可能受到限制且不常见。我没有看到太多这种行为有用的情况。深拷贝或惰性拷贝对用户来说更为常见。

  1. 根据功能的异构行为

但这不是主要问题。主要问题在于,目前,某些操作会同时影响原始对象和复制对象,而其他操作则不会。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

如果所有这些猜想都是正确的,那么解释在赋值之后哪些函数会影响或不影响原始对象会很有用,否则就无法可靠地编程。

于 2021-01-21T20:51:18.243 回答
0

发生这种情况是因为 SpatRaster 只是 C++ 对象的包装器。这使得x(下面)一个浅拷贝(即指向内存中的同一个对象)

library(terra)
r <- rast()
x <- r 

仅在某些情况下,使用替换方法时才重要(您的示例不再受 current 影响terra)。我还添加了一个copy返回深拷贝的方法,即指向不同(深拷贝)C++ 对象的 SpatRaster。

于 2020-12-20T18:57:40.230 回答