回答編集履歴

5

追加

2019/04/10 12:23

投稿

YasuhiroNiji
YasuhiroNiji

スコア584

test CHANGED
@@ -1,4 +1,4 @@
1
- 「Cythonは試してみましたが殆ど速くなりませんでした。」と書いてありますが、以下のようにすべて型を定義すると今回は約2倍早くなりました。Cで書くのより2倍以上遅いということはないと思います。
1
+ 「Cythonは試してみましたが殆ど速くなりませんでした。」と書いてありますが、以下のようにすべて型を定義すると約2倍早くなりました。1万回の一重ループで内側はnumpyで処理していたのでそれぐらいのものだと思います。Cythonで書けばCより2倍以上遅いということはないと思います。
2
2
 
3
3
 
4
4
 
@@ -67,6 +67,8 @@
67
67
 
68
68
 
69
69
  ```python
70
+
71
+ import numpy as np
70
72
 
71
73
  import time as t
72
74
 

4

ミスの修正

2019/04/10 12:23

投稿

YasuhiroNiji
YasuhiroNiji

スコア584

test CHANGED
@@ -96,7 +96,7 @@
96
96
 
97
97
 
98
98
 
99
- 計算の最後の部分は、要約すると配列の各要素でその要素より後ろにそれより小さい値があれば1にするということなので、以下のように計算方法を変更すれば1000倍ぐらい速くなります。このロジックが実際に使えるかどうかはわかりませんが、いろいろ方法を試す前にロジックを考えた方がいいと思います。
99
+ 計算の最後の部分は、要約すると配列の各要素でその要素より後ろにそれより小さい値があれば2にするということなので、以下のように計算方法を変更すれば1000倍ぐらい速くなります。このロジックが実際に使えるかどうかはわかりませんが、いろいろ方法を試す前にロジックを考えた方がいいと思います。
100
100
 
101
101
 
102
102
 

3

ミスの修正

2019/04/10 12:14

投稿

YasuhiroNiji
YasuhiroNiji

スコア584

test CHANGED
@@ -58,7 +58,7 @@
58
58
 
59
59
  if sl[j] > sl[i]:
60
60
 
61
- msk[j] = 1
61
+ msk[j] = 2
62
62
 
63
63
  return msk
64
64
 
@@ -160,7 +160,7 @@
160
160
 
161
161
  if sl[j] > slmin:
162
162
 
163
- msk[j] = 1
163
+ msk[j] = 2
164
164
 
165
165
  else:
166
166
 

2

Cythonのコードを追加

2019/04/10 12:12

投稿

YasuhiroNiji
YasuhiroNiji

スコア584

test CHANGED
@@ -1,45 +1,171 @@
1
- 「Cythonは試してみましたが殆ど速くなりませんでした。」と書いてありますが、
1
+ 「Cythonは試してみましたが殆ど速くなりませんでした。」と書いてありますが、以下のようにすべて型を定義すると今回は約2倍早くなりました。Cで書くのより2倍以上遅いということはないと思います。
2
-
3
- 以下の部分は、配列の各要素でその要素より前にそれより大きい値があれば2にするというだけの計算なので、numpyでは無駄な計算をかなりしているので、Cythonによる処理高速化は可能です。
4
2
 
5
3
 
6
4
 
5
+ ```Cython
6
+
7
+ import cython
8
+
9
+ import numpy as np
10
+
11
+ cimport numpy as np
12
+
13
+
14
+
15
+ ctypedef np.float64_t np_float_t
16
+
17
+ ctypedef np.int32_t np_int_t
18
+
19
+
20
+
21
+ @cython.boundscheck(False)
22
+
23
+ @cython.wraparound(False)
24
+
7
- もし、Cythonで速くならなかったというのならば、そのコードを質問に記載してください。やりかたが間違っているだけです。
25
+ cpdef np.ndarray[np_int_t, ndim=1] func1(
26
+
27
+ np.ndarray[np_float_t, ndim=1] sl,
28
+
29
+ np.ndarray[np_float_t, ndim=1] ang):
30
+
31
+
32
+
33
+ cdef np.ndarray[np_int_t, ndim=1] msk
34
+
35
+ cdef int i, j
36
+
37
+ cdef int n = len(sl)
38
+
39
+ cdef double angmax = ang[0]
40
+
41
+
42
+
43
+ msk = np.ones(n, dtype='int32')
44
+
45
+ for i in range(1, n):
46
+
47
+ if angmax > ang[i]:
48
+
49
+ msk[i] = 3
50
+
51
+ else:
52
+
53
+ angmax = ang[i]
54
+
55
+
56
+
57
+ for j in range(i):
58
+
59
+ if sl[j] > sl[i]:
60
+
61
+ msk[j] = 1
62
+
63
+ return msk
64
+
65
+ ```
8
66
 
9
67
 
10
68
 
11
69
  ```python
12
70
 
13
- csl = sl[0:i+1]
71
+ import time as t
14
72
 
15
- ply = np.where(csl > sl[i])
16
73
 
17
- kly = np.size(ply)
18
74
 
75
+ def main()
76
+
77
+ start = t.time()
78
+
19
- if kly > 0: msk[ply] = 2
79
+ sl = np.random.rand(10000)
80
+
81
+ ang = np.random.rand(10000)
82
+
83
+ msk = func1(s1, ang)
84
+
85
+ print(msk)
86
+
87
+ print('time : ' + str(round((t.time() - start),3)) + ' [sec]')
88
+
89
+
90
+
91
+ if __name__ == "__main__":
92
+
93
+ main()
94
+
95
+ ```
96
+
97
+
98
+
99
+ 計算の最後の部分は、要約すると配列の各要素でその要素より後ろにそれより小さい値があれば1にするということなので、以下のように計算方法を変更すれば1000倍ぐらい速くなります。このロジックが実際に使えるかどうかはわかりませんが、いろいろ方法を試す前にロジックを考えた方がいいと思います。
20
100
 
21
101
 
22
102
 
23
103
  ```
24
104
 
105
+ import cython
25
106
 
107
+ import numpy as np
26
108
 
27
- また、以下の式も間違っていませんか。`msk = np.ones(n)`で`msk`は全ての要素が1の配列なのに、for文の中で msk[i] = 1 としても何もしたことになりませんが。。。
109
+ cimport numpy as np
28
110
 
29
111
 
30
112
 
31
- ```python
113
+ ctypedef np.float64_t np_float_t
32
114
 
33
- msk = np.ones(n)
115
+ ctypedef np.int32_t np_int_t
34
116
 
35
117
 
36
118
 
119
+ @cython.boundscheck(False)
120
+
121
+ @cython.wraparound(False)
122
+
123
+ cpdef np.ndarray[np_int_t, ndim=1] func2(
124
+
125
+ np.ndarray[np_float_t, ndim=1] sl,
126
+
127
+ np.ndarray[np_float_t, ndim=1] ang):
128
+
129
+
130
+
131
+ cdef np.ndarray[np_int_t, ndim=1] msk
132
+
133
+ cdef int i, j
134
+
135
+ cdef int n = len(sl)
136
+
137
+ cdef double angmax = ang[0]
138
+
139
+ cdef double slmin
140
+
141
+
142
+
143
+ msk = np.ones(n, dtype='int32')
144
+
37
145
  for i in range(1, n):
38
146
 
39
- maxidx = np.argmax([angmax, ang[i]])
147
+ if angmax > ang[i]:
40
148
 
41
- angmax = np.max([angmax, ang[i]])
149
+ msk[i] = 3
42
150
 
151
+ else:
152
+
153
+ angmax = ang[i]
154
+
155
+
156
+
43
- if maxidx == 0: msk[i] = 1
157
+ slmin = sl[n - 1]
158
+
159
+ for j in range(n - 1, -1, -1):
160
+
161
+ if sl[j] > slmin:
162
+
163
+ msk[j] = 1
164
+
165
+ else:
166
+
167
+ slmin = sl[j]
168
+
169
+ return msk
44
170
 
45
171
  ```

1

修正

2019/04/10 11:02

投稿

YasuhiroNiji
YasuhiroNiji

スコア584

test CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- もし、Cythonで速くならなかったというのならば、そのコードを質問に記載してください。やりかたが間違っていのを、Cythonのせいにすのは問題のある発言です。
7
+ もし、Cythonで速くならなかったというのならば、そのコードを質問に記載してください。やりかたが間違っているだけです。
8
8
 
9
9
 
10
10
 
@@ -24,7 +24,7 @@
24
24
 
25
25
 
26
26
 
27
- それ以前に、以下の式間違いがありませんか。`msk = np.ones(n)`で`msk`は全ての要素が1の配列なのに、for文の中で msk[i] = 1 としても何もしたことになりませんが。。。
27
+ また、以下の式間違っていませんか。`msk = np.ones(n)`で`msk`は全ての要素が1の配列なのに、for文の中で msk[i] = 1 としても何もしたことになりませんが。。。
28
28
 
29
29
 
30
30