回答編集履歴

4

前日と前々日の比較も追加

2020/01/21 09:11

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -97,3 +97,87 @@
97
97
 
98
98
 
99
99
  こっちのほうが見た目明らかにすっきりしていますね。
100
+
101
+
102
+
103
+ -----
104
+
105
+
106
+
107
+ 前日と前々日の比較もするのでしたね。
108
+
109
+ でしたら、このように変えてください。
110
+
111
+
112
+
113
+ 1行で書く場合
114
+
115
+ ```python
116
+
117
+ df['signal'] = df['close'].rolling(3, min_periods=1).apply(lambda sr: 1 if sr[1:] and sr[1] > sr[0] and sr[2:] and sr[2] > sr[1] else 0, raw=True).apply(lambda x: 'True' if x else '-')
118
+
119
+ ```
120
+
121
+
122
+
123
+ 見やすくしてみたもの
124
+
125
+ ```python
126
+
127
+ def aggregate(sr):
128
+
129
+ # `lambda sr: 1 if sr[1:] and sr[1] > sr[0] and sr[2:] and sr[2] > sr[1] else 0`に相当する関数
130
+
131
+ # データがあり、かつ先にあるデータのほうが値が小さい場合1を返し、それ以外なら0を返す。
132
+
133
+ if sr[1:] and sr[1] > sr[0] and sr[2:] and sr[2] > sr[1]:
134
+
135
+ return 1
136
+
137
+ return 0
138
+
139
+
140
+
141
+ # 2行ずつデータを処理する。min_periods=1を指定しないと、最初の行が処理されない。
142
+
143
+ rolling = df['close'].rolling(3, min_periods=1)
144
+
145
+
146
+
147
+ # raw=Trueはpandas側の将来的な変更に対処するため。
148
+
149
+ # なくても今は動くが、警告が出る。
150
+
151
+ aggregated = df.apply(aggregate, raw=True)
152
+
153
+
154
+
155
+ # aggregatedのそれぞれの値を'true'か'-'の文字列値に変えてdf['signal']に格納する。
156
+
157
+ df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
158
+
159
+ ```
160
+
161
+
162
+
163
+ forでやる方法
164
+
165
+ ```forでやる場合
166
+
167
+ x = []
168
+
169
+ for i, f in enumerate(df['close']):
170
+
171
+ if i == 0 or i == 1:
172
+
173
+ x.append('-')
174
+
175
+ continue
176
+
177
+ x.append('true' if f > df['close'].iloc[i-1] and df['close'].iloc[i-1] > df['close'].iloc[i-2] else '-')
178
+
179
+
180
+
181
+ df['signal'] = x
182
+
183
+ ```

3

冗長な記述を削除

2020/01/21 09:11

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -48,7 +48,7 @@
48
48
 
49
49
 
50
50
 
51
- # aggregatedを'true'か'-'の文字列値に変えてdf['signal']に格納する。
51
+ # aggregatedのそれぞれの値を'true'か'-'の文字列値に変えてdf['signal']に格納する。
52
52
 
53
53
  df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
54
54
 
@@ -90,7 +90,7 @@
90
90
 
91
91
 
92
92
 
93
- df['signal'] = pd.Series(x)
93
+ df['signal'] = x
94
94
 
95
95
  ```
96
96
 

2

詳しい解説を追加

2020/01/21 09:04

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -2,12 +2,98 @@
2
2
 
3
3
 
4
4
 
5
- ```
5
+ ```python
6
6
 
7
- df['signal'] = df.rolling(2, min_periods=1).apply(lambda sr: 1 if sr[1:] and sr[1] > sr[0] else 0, raw=True).apply(lambda x: 'True' if x['close'] else '-', axis=1)
7
+ df['signal'] = df['close'].rolling(2, min_periods=1).apply(lambda sr: 1 if sr[1:] and sr[1] > sr[0] else 0, raw=True).apply(lambda x: 'True' if x else '-')
8
8
 
9
9
  ```
10
10
 
11
11
 
12
12
 
13
- DataFrame.rollingは、複数の行または列にわたって集計するための関数です。
13
+ DataFrame.rollingやSeries.rollingは、複数の行または列にわたって集計するための関数です。
14
+
15
+
16
+
17
+ これを少し見やすくして解説します。
18
+
19
+
20
+
21
+ ```python
22
+
23
+ def aggregate(sr):
24
+
25
+ # `lambda sr: 1 if sr[1:] and sr[1] > sr[0] else 0`に相当する関数
26
+
27
+ # データがあり、かつ先にあるデータのほうが値が小さい場合1を返し、それ以外なら0を返す。
28
+
29
+ if sr[1:] and sr[1] > sr[0]:
30
+
31
+ return 1
32
+
33
+ return 0
34
+
35
+
36
+
37
+ # 2行ずつデータを処理する。min_periods=1を指定しないと、最初の行が処理されない。
38
+
39
+ rolling = df['close'].rolling(2, min_periods=1)
40
+
41
+
42
+
43
+ # raw=Trueはpandas側の将来的な変更に対処するため。
44
+
45
+ # なくても今は動くが、警告が出る。
46
+
47
+ aggregated = df.apply(aggregate, raw=True)
48
+
49
+
50
+
51
+ # aggregatedを'true'か'-'の文字列値に変えてdf['signal']に格納する。
52
+
53
+ df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
54
+
55
+ ```
56
+
57
+
58
+
59
+ 見やすくして簡単にコメントをつけてみました。
60
+
61
+ 複数行の処理には`rolling`メソッドを使います。
62
+
63
+ 今回の場合、`'close'`行のみ集計に使うので、`df['close']`でこの行のみに処理を行っています。
64
+
65
+
66
+
67
+ また、処理を2段階に分けているのは、`rolling.apply`に数値以外を返す関数は渡すことができないからです。
68
+
69
+
70
+
71
+ ここまでやるのであれば、おそらくfor文でやったほうがいいような気がします。
72
+
73
+ 一応その場合も書いておきます。
74
+
75
+
76
+
77
+ ```forでやる場合
78
+
79
+ x = []
80
+
81
+ for i, f in enumerate(df['close']):
82
+
83
+ if i == 0:
84
+
85
+ x.append('-')
86
+
87
+ continue
88
+
89
+ x.append('true' if f > df['close'].iloc[i-1] else '-')
90
+
91
+
92
+
93
+ df['signal'] = pd.Series(x)
94
+
95
+ ```
96
+
97
+
98
+
99
+ こっちのほうが見た目明らかにすっきりしていますね。

1

編集途中で送信してしまったため

2020/01/21 09:02

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -1,15 +1,13 @@
1
+ すこし冗長ですが、こういうやり方もあります。
2
+
3
+
4
+
1
5
  ```
2
6
 
3
- def signal(df):
4
-
5
- if df['close'].iloc[-1] > df['close'].iloc[-2]:
7
+ df['signal'] = df.rolling(2, min_periods=1).apply(lambda sr: 1 if sr[1:] and sr[1] > sr[0] else 0, raw=True).apply(lambda x: 'True' if x['close'] else '-', axis=1)
6
-
7
- return 'true'
8
-
9
- else:
10
-
11
- return '-'
12
-
13
- df['signal'] = df.apply(signal, axis=1)
14
8
 
15
9
  ```
10
+
11
+
12
+
13
+ DataFrame.rollingは、複数の行または列にわたって集計するための関数です。