【发布时间】:2012-10-17 03:09:19
【问题描述】:
我们得到一个数字序列,作为向量foo。任务是找到foo 单调递增 - 每一项小于或等于下一项 - 或单调递减 - 每一项大于或等于下一个。
确定这可以通过循环找到,但还有更多创意吗?
【问题讨论】:
我们得到一个数字序列,作为向量foo。任务是找到foo 单调递增 - 每一项小于或等于下一项 - 或单调递减 - 每一项大于或等于下一个。
确定这可以通过循环找到,但还有更多创意吗?
【问题讨论】:
all(diff(x)<0)(酌情替换>、<=、>=)
【讨论】:
一个有趣的答案如下:
foo = c(1, 3, 7, 10, 15)
all(foo[-1] - foo[-length(foo)] >= 0) # TRUE
foo[3] = 20
all(foo[-1] - foo[-length(foo)] >= 0) # FALSE
【讨论】:
foo[-1] - foo[-length(foo) 实际上只是 diff(foo) 的简写(所以这变成了这里给出的其他答案)......但它更难阅读。
一种选择是使用diff() 函数来给出向量中相邻元素之间的差异。
单调递增函数将有diff(x) all > 或等于0:
f1 <- 1:10
f2 <- 10:1
> all(diff(f1) >= 0)
[1] TRUE
> all(diff(f2) >= 0)
[1] FALSE
虽然测试与0 的相等性可能会令人不悦;最好使用< 0 并通过! 否定比较:
> all(!diff(f1) < 0)
[1] TRUE
> all(!diff(f2) < 0)
[1] FALSE
原因是您使用的计算机无法准确表示所有数字。您可能计算出一个实际上为零但不完全为零的结果,因为计算中的数字无法准确表示(即floating points)。因此,如果foo 是计算的结果,则测试它是否等于 0 可能会导致应该是 0 稍微大于或小于 0 的结果,这可能会为增加/减少函数给出错误的结果。
【讨论】:
foo。请记住,您使用的计算机并非所有数字都可以准确表示。您可能计算出一个实际上为零但不完全为零的结果,因为计算中的数字无法准确表示。因此,如果foo 是计算的结果,则测试它是否等于 0 可能会导致应该是 0 稍微大于或小于 0 的结果,这可能会为增加/减少函数给出错误的结果。
foo 舍入到小数位数以消除微小的不确定性.
另一个:检查是否
all(x == cummax(x))
或
all(x == cummin(x))
分别表示单调递增或递减。似乎cummax 比diff 快很多,而且使用的内存也更少:
> x <- seq_len(1e7)
> system.time(all(x == cummax(x)))
user system elapsed
0.11 0.00 0.11
> system.time(all(diff(x) >= 0))
user system elapsed
0.47 0.13 0.59
> x <- seq_len(1e8)
> system.time(all(x == cummax(x)))
user system elapsed
1.06 0.09 1.16
> system.time(all(diff(x) >= 0))
Error: cannot allocate vector of size 381.5 Mb
In addition: Warning messages:
1: Reached total allocation of 1535Mb: see help(memory.size)
2: Reached total allocation of 1535Mb: see help(memory.size)
3: Reached total allocation of 1535Mb: see help(memory.size)
4: Reached total allocation of 1535Mb: see help(memory.size)
Timing stopped at: 1.96 0.38 2.33
我打赌为什么cummax 比diff 快是因为它只需要比较数字,这比计算差异要快。
编辑:应您(阿里)的要求,包括您的答案在内的其他测试(请注意,我现在正在另一台机器上运行,因此不应将以下结果与上述结果进行比较)
> x <- seq_len(1e7)
> system.time(x == cummax(x))
user system elapsed
0.316 0.096 0.416
> system.time(all(diff(x) >= 0))
user system elapsed
4.364 0.240 4.632
> system.time(x[-1] - x[-length(x)] >= 0)
user system elapsed
3.828 0.380 4.227
> system.time(all(x[-1] >= x[-length(x)]))
user system elapsed
2.572 0.288 2.865
【讨论】:
对于增加版本,您可以使用is.unsorted():
x <- seq_len(1e7)
!is.unsorted(x)
> !is.unsorted(x)
[1] TRUE
这也很快:
> system.time(!is.unsorted(x))
user system elapsed
0.099 0.000 0.099
> system.time(all(x == cummax(x)))
user system elapsed
0.320 0.039 0.360
不幸的是,is.unsorted() 明确用于递增顺序。我们在将其转换为下降情况时受到了一些打击,但它仍然与我系统上的其他选项相比具有竞争力:
xx <- 1e7:1
!is.unsorted(-xx)
system.time(!is.unsorted(-xx))
> system.time(!is.unsorted(-xx))
user system elapsed
0.205 0.020 0.226
> system.time(all(xx == cummin(xx)))
user system elapsed
0.356 0.088 0.444
还有一个更大的问题……
x <- 1:1e8
xx <- 1e8:1
system.time(!is.unsorted(x))
system.time(all(x == cummax(x)))
system.time(!is.unsorted(-xx))
system.time(all(xx == cummin(xx)))
> system.time(!is.unsorted(x))
user system elapsed
1.019 0.000 1.019
> system.time(all(x == cummax(x)))
user system elapsed
3.255 0.354 3.608
> system.time(!is.unsorted(-xx))
user system elapsed
2.089 0.561 2.650
> system.time(all(xx == cummin(xx)))
user system elapsed
3.318 0.395 3.713
如果您想强制执行严格递增的序列,请参阅?is.unsorted 中的strictly。
【讨论】:
!is.unsorted(rev(x)),虽然速度不是很好。