43

ベクトルとして、一連の数列が与えられfooます。タスクは、単調に増加していることを見つけることですfoo-すべてのアイテムが次のアイテム以下である-または単調に減少している-すべてのアイテムが次のアイテム以上である。

確かにこれはループを通して見つけることができますが、もっと創造的なアイデアはありますか?

4

5 に答える 5

61

もう1つ:確認してください

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 
于 2012-10-26T21:39:12.503 に答える
14

1 つのオプションは、diff()関数を使用して、ベクトル内の隣接する要素間の差を与えることです。

単調に増加する関数は、diff(x)すべてが 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

これは、すべての数値を正確に表現できるとは限らないコンピューターを使用しているためです。計算中の数値を正確に表すことができなかった (つまり、浮動小数点数) ため、実際にはゼロであるが完全にゼロではない結果を計算する場合があります。したがって、fooが計算の結果である場合、それが 0 に等しいかどうかをテストすると、0 が 0 よりも少し大きいか小さいかという結果になる可能性があり、増加/減少関数の結果が間違っている可能性があります。

于 2012-10-26T20:31:15.670 に答える
10

増加するバージョンの場合、次を使用できます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

厳密に増加するシーケンスを強制する場合は、 を参照strictlyしてください?is.unsorted

于 2016-05-05T20:39:58.653 に答える
7

all(diff(x)<0)>(必要に応じて、、、に<=置き換えます>=)

于 2012-10-26T20:27:06.003 に答える
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
于 2012-10-26T20:27:15.590 に答える