Wir erhalten eine Zahlenfolge als Vektor foo
. Die Aufgabe ist zu finden, dass foo
ist monoton steigend - jedes Element ist kleiner oder gleich dem nächsten - oder monoton verringert - jedes Element ist größer oder gleich dem nächsten.
Sicher kann man dies über eine Schleife finden, aber mehr kreative Ideen?
Noch eine: prüfe ob
all(x == cummax(x))
oder
all(x == cummin(x))
für monotones Ansteigen bzw. Abnehmen. Es scheint, dass cummax
viel schneller als diff
ist und außerdem weniger Speicher benötigt:
> 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
Ich wette, warum cummax
schneller ist als diff
, weil er nur Zahlen vergleichen muss, was schneller ist als die Berechnung von Unterschieden.
Edit : Auf Anfrage Ihres (ALi's) zusätzliche Tests, einschließlich Ihrer Antwort (Beachten Sie, dass ich jetzt von einem anderen Computer aus laufe, sodass die folgenden Ergebnisse nicht mit den obigen Ergebnissen verglichen werden sollten).
> 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
Eine Möglichkeit besteht darin, die Funktion diff()
zu verwenden, um die Unterschiede zwischen benachbarten Elementen in einem Vektor zu ermitteln.
Eine monoton steigende Funktion hat diff(x)
all> oder gleich 0:
f1 <- 1:10
f2 <- 10:1
> all(diff(f1) >= 0)
[1] TRUE
> all(diff(f2) >= 0)
[1] FALSE
Obwohl das Prüfen auf Gleichheit mit 0
nicht gern gesehen wird; Es könnte besser sein, < 0
zu verwenden und den Vergleich über !
zu negieren:
> all(!diff(f1) < 0)
[1] TRUE
> all(!diff(f2) < 0)
[1] FALSE
Der Grund dafür ist, dass Sie einen Computer verwenden, auf dem nicht alle Zahlen exakt dargestellt werden können. Sie können ein Ergebnis berechnen, das praktisch Null ist, aber nicht ganz Null, da die Zahlen in der Berechnung nicht exakt dargestellt werden konnten (d. H. Fließkommazahlen ). Wenn also foo
das Ergebnis einer Berechnung ist, könnte das Testen, ob es gleich 0 ist, möglicherweise zu einem Ergebnis führen, bei dem 0 ein kleines Bit größer oder kleiner als 0 sein sollte, was dann das falsche Ergebnis für eine zunehmende/abnehmende Funktion ergibt.
all(diff(x)<0)
(ersetzen Sie ggf. >
, <=
, >=
)
Für die aufsteigende Version können Sie is.unsorted()
verwenden:
x <- seq_len(1e7)
!is.unsorted(x)
> !is.unsorted(x)
[1] TRUE
Das ist auch ziemlich schnell:
> 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
Leider ist is.unsorted()
explizit für die Erhöhung der Reihenfolge. Wir haben ein bisschen Erfolg, wenn wir dies in die abnehmende Situation umwandeln, aber es ist immer noch konkurrenzfähig mit den anderen Optionen meines Systems:
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
Und bei einem größeren Problem ...
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
Wenn Sie eine streng zunehmende Sequenz erzwingen möchten, lesen Sie strictly
in ?is.unsorted
.
Eine interessante Antwort ist wie folgt:
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