8.1 幽灵(no.11~no.20)

8.1 幽灵(no.11~no.20)

8.1.11 剔除命名的条目

负号(-)可以让你剔除你不需要的条目:

> xlet <- 1:6
> names(xlet) <- letters[1:6]
> xlet[-c(3,4)]
a b e f
1 2 5 6

有时你更喜欢用名字而不是数字来实现剔除操作,但这是无效的(自然地):

> xlet[-c(’c’, ’d’)]
Error in -c("c", "d") : Invalid argument to unary operator

下面是一个合理的方法:

> xlet[!(names(xlet) %in% c(’c’, ’d’))]
a b e f
1 2 5 6

当然,括号也不是必须的:

> xlet[!names(xlet) %in% c(’c’, ’d’)]
a b e f
1 2 5 6

但是它工作起来对我来说好像是变戏法一样—加上括号我更加舒服些。Uwe’s Maxim告诉我:当有括号时,我们需要思考的会更少。

8.1.12 剔除缺失值

> xna <- c(1, NA, 3, 2, 4, 2)
> xna[xna == 2]
[1] NA 2 2

你可以看到,如果你仅仅想要值是2的,那么就会令你失望了。你可以这样:

> xna[!is.na(xna) & xna == 2]
[1] 2 2

或者更加简洁一点:

> xna[which(xna == 2)]
[1] 2 2

8.1.13 负的没有就是有

> x2 <- 1:4
> x2[-which(x2 == 3)]
[1] 1 2 4

上述命令返回了x2中所有不等于3的值。

> x2[-which(x2 == 5)]
numeric(0)

上述命的期望是返回x2中的所有元素因为没有元素等于5。事实就是如此残酷。它返回了一个长度是0的向量。

下述的两条语句有微妙的区别:

x[]
x[numeric(0)]

在输入上有细微的区别,但是输出上没有。

对于这个原始问题有至少三种可能的解决方案。

out <- which(x2 == 5)
if(length(out)) x2[-out] else x2

另外一种是利用逻辑下标:

x2[!(x2 %in% 5)]

或者你可以,在一定意义上,向后工作:

x2[setdiff(seq along(x2), which(x2 == 5))]

8.1.14 0可以是没有

> x3 <- 1:3
> x3[c(0, 4)] <- c(-1, 9)
Warning message: number of items to replace is not a multiple of replacement length
> x3
[1] 1 2 3 -1

这是一个你不想忽视警告信息的示例,因为这四个元素并不是你想要的结果。

8.1.15 一些加上没有是没有

> 1 + NULL
numeric(0)

这个计算没有错误或者警告信息。它能正常运行是因为循环规则告诉这个计算结果的长度应该是0。有时你更希望它会报出警告。

8.1.16 没有之和是零

一些人对下述结果感到惊讶:

> sum(numeric(0))
[1] 0

并且或许对这个更加惊讶:

> prod(numeric(0))
[1] 1

在逻辑运算下的numeric(0):

> any(logical(0))
[1] FALSE
> all(logical(0))
[1] TRUE

惊讶与否,这就是正确答案。我们渴望:

sum(c(1, 3, 5, 7))

sum(c(1, 3)) + sum(c(5, 7))

相等。

因此我们应该同样期望和这个相等:

sum(c(1, 3, 5, 7)) + sum(numeric(0))

在min和max操作上也有相似的结果,尽管会有相应的警告:

> min(NULL)
[1] Inf
Warning message:
In min(NULL) : no finite arguments to min; returning Inf
> max(NULL)
[1] -Inf
Warning message:
In max(NULL) : no finite arguments to max; returning -Inf

8.1.17 方法混淆

虽然矩阵和数据框可以表示相同的数据,或许看起来一样,它们是不同的。特别地,泛型函数会且确实会给出不同的结果。

让我们通过制造一些数据来开始吧:

> mat1 <- cbind(1:3, 7:9)
> df1 <- data.frame(1:3, 7:9)

现在,注意:

> mean(mat1)
[1] 5
> mean(df1)
X1.3 X7.9
2    8

> median(mat1)
[1] 5
> median(df1)
[1] 2 8
> sum(mat1)
[1] 30
> sum(df1)
[1] 30

例子中用数据框进行median操作是会有问题的。在2.13.0版本中的R,是没有关于数据框的median操作的。在这个特殊的案例中它得到了正确的答案,但这只是意外情况。在其他情况下你会得到奇怪的答案。

除非并且直到存在这样一种方法,你可以按照我期望你考虑的:

> sapply(df1, median)
X1.3 X7.9
2    8

8.1.18 仅仅拼配第一项(I)

函数match仅仅拼配第一次出现的情况:

> match(1:2, rep(1:4, 2))
[1] 1 2

如果这不是你想要的,改变你的方式:

> which(rep(1:4, 2) %in% 1:2)
[1] 1 2 5 6

8.1.19 仅仅拼配第一项(II)

如果名字不是只有一个,那么字符下标仅仅会返回第一个匹配项:

> x4 <- c(a=1, b=2, a=3)
> x4["a"]
a
1

如果这不是你想要的,那么你可能是想要使用”%in%”:

> x4[names(x4) %in% ’a’]
a a
1 3

8.1.20 部分匹配可以部分地混淆

部分匹配存在与函数调用和一些下标化中。
这两个函数调用是相同的:

> mean(c(1:10, 1000), trim=.25)
[1] 6
> mean(c(1:10, 1000), t=.25)
[1] 6

入参trim是mean.default中唯一一个以”t”开头的入参,因此R知道当你输入”t”的时候与”trim”等同。这是有帮助的,但是一些人就想知道它是否太过于有帮助了。

> l1 <- list(aa=1:3, ab=2:4, b=3:5, bb=4:6, cc=5:7)
> l1$c
[1] 5 6 7
> l1[[’c’]]
NULL
> l1[[’c’, exact=FALSE]]
[1] 5 6 7
> l1$a
NULL
> myfun1 <- function(x, trim=0, treat=1)
  {
    treat * mean(x, trim=trim)
  }
> myfun1(1:4, tr=.5)
Error in myfun1(1:4, tr = .05) :
argument 2 matches multiple formal arguments

"" ”的代名词的”[[“操作符,不允许默认的部分匹配(在最近的版本中)。一个有争议的匹配在列表上会导致NULL,而在函数调用上则会导致错误。函数myfun1展示了为什么一个错误的出现。在下标化的情况请:

?Extract

以下是函数调用时入参匹配的规则,但是首先明确定义:”正式参数”是在函数定义时的参数名称。函数mean.default有4个正式参数(x,trim,na.rm和…)。”标签”是一个在函数调用中指示哪个正式参数被指代的字符串。我们使用”t”作为一个标签来指代mean(然后是mean.default)。如果标签所有的字符和正式参数的开始字符匹配上,这就是部分匹配。

  • 如果一个标签和一个标准参数完全匹配,它们两个就会绑定在一起。

  • 没有匹配的标签和没有匹配的标准参数进行匹配。

  • 如果任何一个标签部分地匹配了多于一个尚未被匹配的标准参数,发生错误。

  • (潜在的匹配)尚未匹配的标准参数和函数调用中没有名字的参数(没有标签)进行绑定,由调用的顺序和标准参数决定。

  • 如果”…”存在于标准参数中,在”…”之后的所有的标准参数只能精确匹配。

  • 如果”…”存在于标准参数中,在调用中任何没有被匹配的参数,无论是否有标签,将被”…”带走。

  • 如果在函数调用中任何一个提供的参数没有被匹配,发生错误。

部分匹配最大可能的咬你一口是在:当需要一个函数作为入参的时候你却传入额外的参数。
比如:

apply(xmat, 2, mean, trim=.2)

如果函数apply有一个参数匹配或者部分匹配”trim”,那么apply将会得到trim的值,而非mean。

There are two strategies in general use to reduce the possibility of such
collisions:

有两种策略去减少这种碰撞的可能性。

  • apply族函数倾向于拥有全部大写的参数,并且因此不太可能的和其他那些倾向于使用小写字母的函数的参数碰撞。

  • 优化函数倾向于将”…”(意味着这是一个参数)放置在参数表的首位。因此其余的参数对于优化者(和需要优化的函数相对)需要以全称的形式给出。

无论方案是多么令人满意—在很多方面你仍旧会得到意想不到的碰撞。如果确实是这样(你查出了发生了什么),那么你可以包含所有的存在问题的参数到你的调用中。

你可能感兴趣的:(R)