gpt4 book ai didi

r - 默认名称连接

转载 作者:行者123 更新时间:2023-12-01 19:00:31 28 4
gpt4 key购买 nike

如果我有一个命名向量

v <- c(a = 1, b = 2)

然后我添加它们

s <- v[2] + v[1]

结果是一个长度为 1 的向量,其元素被命名为算术中的第一个元素,此处为“b”。您可以使用双括号消除此行为。

无论如何,如果我尝试用 c() 创建一个新的命名向量

v <- c(v, sum = s)

sum 元素的结果名称不是“sum”,而是“sum.b”。

这种行为是不可取的,因为我明确表示我希望将此元素命名为 sum。

如果我添加这样的元素:

v["sum"] <- s

我得到了想要的行为。

为什么 R 将对象的名称和使用 c() 提供的名称连接起来,为什么这与在括号中使用新名称添加元素不同?这并不是要问如何消除这种行为(我可以使用双括号或 unname() 来做到这一点),而是问它背后的原则是什么,以及在其他什么情况下我可以期望这种行为发生?

最佳答案

运算符和组合函数的属性保存规则

通过运算符函数(例如 `+` <- function(e1, e2) {} )和组合函数( c <- function(...) {} )影响的转换,设计者尝试保留对象属性(最常见的是 names )。

运算符函数

对于运算符函数,规则如下:

  • 规则 1:如果 length(answer) == length(e1) & length(answer) < length(e2) 则使用 e1 属性。

  • 规则 2:如果 length(answer) == length(e2) & length(answer) < length(e1),则使用 e2 属性。

  • 规则 3:如果 length(answer) == length(e1) & length(answer) == length(e2),则同时使用 e1 和 e2 属性,但 e1 属性优先。

首先,设置命名和未命名向量。使用多元素对象,因为它们比问题中使用的单元素对象更好地演示规则的应用。

print(a <- setNames(1:2, sprintf("a%s", 1:2)))
# a1 a2
# 1 2
print(b <- setNames(1:4, sprintf("b%s", 1:4)))
# b1 b2 b3 b4
# 1 2 3 4
print(u <- 1:2) # unnamed
# [1] 1 2
print(x <- setNames(1:4, rep("x", 4)))
# x x x x
# 1 2 3 4

然后是一些例子:

#' rule 1
names(a + b[1]) # [1] "a1" "a2"
names(b + a[1]) # [1] "b1" "b2" "b3" "b4"
names(u + a[1]) # NULL

#' rule 2
names(a[1] + b) # [1] "b1" "b2" "b3" "b4"
names(b[1] + a) # [1] "a1" "a2"
names(u[1] + a) # [1] "a1" "a2"

#' rule 3
names(a + b[1:2]) # [1] "a1" "a2"
names(b[1:2] + a) # [1] "b1" "12"
names(u + a) # [1] "a1" "a2" ## e1 is unnamed so use e2's names

运算符函数不保留参数名称,实际上似乎完全忽略它们(仅顺序很重要),即使是函数定义中的参数名称( e1e2 )。

names(`+`(v1 = u, v2 = 0))      # NULL
names(`+`(e2 = a, e1 = b[1:2])) # [1] "a1" "a2" ## despite e1 being b[1:2]

组合功能

对于组合函数,首先要注意的是,参数名称不会像运算符函数那样被忽略,并且参数及其元素都可以命名。规则如下:

  • 规则 1:如果参数未命名且其元素未命名,则不使用名称。

  • 规则 2:如果参数未命名但其元素已命名,则使用元素名称。

  • 规则 3:如果参数已命名且其元素未命名,则对于长度 == 1 的参数使用参数名称,对于长度 > 1 的参数使用带有连续数字后缀的参数名称。

    <
  • 规则 4:如果参数已命名且其元素已命名,则使用由点连接的名称。

首先是一个显示参数命名的函数:

c... <- function(...) {match.call(expand.dots=FALSE)$...}

一些例子:

# rules 1 and 2
names(c...(u, a)) # NULL, all arguments unnamed
names(c(u, a)) # c("", "", "a1", "a2")

# rules 3 and 4
names(c...(v1 = u[1], v2 = u, v3 = a)) # c("v1", "v2", "v3"), all arguments named
names(c(v1 = u[1], v2 = u, v3 = a)) # c("v1", "v21", "v22", "v3.a1", "v3.a2")

# all rules
names(c...(u, v1 = u, a, v2 = a)) # c("", "v1", "", "v2") ## some arguments named
names(c(u, v1 = u, a, v2 = a)) # c("", "", "v11", "v12", "a1", "a2", "v2.a1", "v2.a2")

应该注意的是,规则的设计目的是尽可能保留属性,但其目的并不是将名称创建为唯一标识符。

 # ambiguities (rules 2 and 4)
names(c(x, v1 = x)) # c("x", "x", "x", "x", "v1.x", "v1.x", "v1.x", "v1.x")

当运算符和组合函数一起使用时,每个函数的规则将按计算顺序应用。所以在 c(a) + c(b) ,相当于`+`(c(a), c(b)) ,首先应用组合函数规则。鉴于,在 (a + b) ,相当于c(`+`(a, b)) ,首先应用运算符函数规则。

# c() first, so argument names used
names(c(v1=a) + c(v2=b)) # c("v2.b1", "v2.b2", "v2.b3", "v2.b4")
names(`+`(c(v1=a),c(v2=b))) # c("v2.b1", "v2.b2", "v2.b3", "v2.b4")

# `+`() first, so argument names ignored
names(c((v1=a) + (v2=b))) # c("b1", "b2", "b3", "b4")
names(c(`+`(v1=a, v2=b))) # c("b1", "b2", "b3", "b4")

问题与解答

问题是,(1)“为什么 R 连接对象的名称和使用 c() 提供的名称”,以及 (2)“为什么这与在括号中使用新名称添加元素不同? ”

  1. 运算符和组合函数的原则是通过应用上面给出的规则,以最有意义(且可预测)的方式保留对象属性(包括参数和元素名称)。所有参数和对象的所有属性不可能完整保留,因此应用 (a) 优先级、(b) 顺序数字后缀和 (c) 连接来保留尽可能多的最合适的信息。

  2. 命名元素的直接赋值会同时分配值和属性,在这种情况下,无需保留两个对象或参数和对象的属性,因此上述注意事项均不适用。

关于r - 默认名称连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46280870/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com