numpy.arange()は間違ったエンドポイントを取得する場合がある

参考:
How does NumPy’s arange differ from this custom function? – StackOverflow
 
 
 

正しい(問題ない)例:

import numpy as np

np.arange(5), np.arange(10)

(array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))

np.arange(0, 5.0, 0.1), np.arange(0, 10.0, 0.1)

(array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ,
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1,
2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2,
3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3,
4.4, 4.5, 4.6, 4.7, 4.8, 4.9]),
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ,
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1,
2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2,
3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3,
4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. , 5.1, 5.2, 5.3, 5.4,
5.5, 5.6, 5.7, 5.8, 5.9, 6. , 6.1, 6.2, 6.3, 6.4, 6.5,
6.6, 6.7, 6.8, 6.9, 7. , 7.1, 7.2, 7.3, 7.4, 7.5, 7.6,
7.7, 7.8, 7.9, 8. , 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7,
8.8, 8.9, 9. , 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8,
9.9]))

間違った(問題がある)例:

np.arange(0, 2.1, 0.3), np.arange(0, 4.2, 0.3)

(array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1]),
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3. ,
3.3, 3.6, 3.9, 4.2]))

正しくは:

np.arange(0, 21, 3) * 0.1, np.arange(0, 42, 3) * 0.1, 

(array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8]),
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3. ,
3.3, 3.6, 3.9]))
 
 

多分,2進浮動小数点数に対する算術演算の問題に起因するんだろう.
 
 
 
 
 

np.arange(0, 2.1, 0.6), np.arange(0, 4.2, 0.6)

(array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1]),
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3. ,
3.3, 3.6, 3.9, 4.2]))

np.arange(0, 21, 0.3), np.arange(0, 42, 0.3)

(array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4,
2.7, 3. , 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1,
5.4, 5.7, 6. , 6.3, 6.6, 6.9, 7.2, 7.5, 7.8,
8.1, 8.4, 8.7, 9. , 9.3, 9.6, 9.9, 10.2, 10.5,
10.8, 11.1, 11.4, 11.7, 12. , 12.3, 12.6, 12.9, 13.2,
13.5, 13.8, 14.1, 14.4, 14.7, 15. , 15.3, 15.6, 15.9,
16.2, 16.5, 16.8, 17.1, 17.4, 17.7, 18. , 18.3, 18.6,
18.9, 19.2, 19.5, 19.8, 20.1, 20.4, 20.7]),
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4,
2.7, 3. , 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1,
5.4, 5.7, 6. , 6.3, 6.6, 6.9, 7.2, 7.5, 7.8,
8.1, 8.4, 8.7, 9. , 9.3, 9.6, 9.9, 10.2, 10.5,
10.8, 11.1, 11.4, 11.7, 12. , 12.3, 12.6, 12.9, 13.2,
13.5, 13.8, 14.1, 14.4, 14.7, 15. , 15.3, 15.6, 15.9,
16.2, 16.5, 16.8, 17.1, 17.4, 17.7, 18. , 18.3, 18.6,
18.9, 19.2, 19.5, 19.8, 20.1, 20.4, 20.7, 21. , 21.3,
21.6, 21.9, 22.2, 22.5, 22.8, 23.1, 23.4, 23.7, 24. ,
24.3, 24.6, 24.9, 25.2, 25.5, 25.8, 26.1, 26.4, 26.7,
27. , 27.3, 27.6, 27.9, 28.2, 28.5, 28.8, 29.1, 29.4,
29.7, 30. , 30.3, 30.6, 30.9, 31.2, 31.5, 31.8, 32.1,
32.4, 32.7, 33. , 33.3, 33.6, 33.9, 34.2, 34.5, 34.8,
35.1, 35.4, 35.7, 36. , 36.3, 36.6, 36.9, 37.2, 37.5,
37.8, 38.1, 38.4, 38.7, 39. , 39.3, 39.6, 39.9, 40.2,
40.5, 40.8, 41.1, 41.4, 41.7]))

np.arange(0, 2.7, 0.3)

array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7])

np.arange(2.0, 2.6, 0.2)

array([ 2. , 2.2, 2.4, 2.6])
 
 
 
解決策としては,よくnumpy.linspace()を用いる方法をみる.
エンドポイントが明示されるので,刻みさえ適切に設定してあげれば良い.

numpy arange for floating point start & stop – StackOverflow

start = 0.0
stop = 1.8
incr = 0.3

eps = 1e-4*(stop-start)
num = int((stop-start)/(incr-eps)+1)
np.linspace(start, stop, num)

array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])

start = 2.0
stop = 2.4
incr = 0.2

eps = 1e-4*(stop-start)
num = int((stop-start)/(incr-eps)+1)
np.linspace(start, stop, num)

array([ 2. , 2.2, 2.4])

数理的には上の方が尤もらしいけど,エンドポイントだけの話なので,
不格好だけどちょっとした時にはこれでも良いと思う.

a = np.arange(2.0, 2.6, 0.2)
a[a < 2.6]

array([ 2. , 2.2, 2.4])

a = np.arange(0, 2.1, 0.3)
b = np.arange(0, 4.2, 0.3)
a[a < 2.1], b[b < 4.2]

(array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8]),
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3. ,
3.3, 3.6, 3.9]))

for i in np.linspace(start, stop,num):
    print(repr(i))

0.0
0.29999999999999999
0.59999999999999998
0.89999999999999991
1.2
1.5
1.8

for i in a[a < 2.1]:
    print(repr(i))

0.0
0.29999999999999999
0.59999999999999998
0.89999999999999991
1.2
1.5
1.7999999999999998

for i in np.linspace(start, stop,num):
    print(repr(i))

2.0
2.2000000000000002
2.3999999999999999

for i in a[a < 2.6]:
    print(repr(i))

2.0
2.2000000000000002
2.4000000000000004

for i in np.arange(20, 26, 2) * 0.1:
    print(repr(i))

2.0
2.2000000000000002
2.4000000000000004
 
 
 

for i in np.arange(10, 1000, 0.1)[-10:]:
    print(repr(i))

998.99999999999648
999.0999999999965
999.19999999999652
999.29999999999643
999.39999999999645
999.49999999999648
999.5999999999965
999.69999999999652
999.79999999999643
999.89999999999645

for i in np.arange(0, 1000, 0.1)[-10:]:
    print(repr(i))

999.0
999.10000000000002
999.20000000000005
999.30000000000007
999.40000000000009
999.5
999.60000000000002
999.70000000000005
999.80000000000007
999.90000000000009

for i in np.arange(100, 10000, 1)[-10:]*0.1:
    print(repr(i))

999.0
999.10000000000002
999.20000000000005
999.30000000000007
999.40000000000009
999.5
999.60000000000002
999.70000000000005
999.80000000000007
999.90000000000009

広告
カテゴリー: 未分類 パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中