teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

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

2020/01/21 09:11

投稿

frodo821
frodo821

スコア322

answer CHANGED
@@ -47,4 +47,46 @@
47
47
  df['signal'] = x
48
48
  ```
49
49
 
50
- こっちのほうが見た目明らかにすっきりしていますね。
50
+ こっちのほうが見た目明らかにすっきりしていますね。
51
+
52
+ -----
53
+
54
+ 前日と前々日の比較もするのでしたね。
55
+ でしたら、このように変えてください。
56
+
57
+ 1行で書く場合
58
+ ```python
59
+ 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 '-')
60
+ ```
61
+
62
+ 見やすくしてみたもの
63
+ ```python
64
+ def aggregate(sr):
65
+ # `lambda sr: 1 if sr[1:] and sr[1] > sr[0] and sr[2:] and sr[2] > sr[1] else 0`に相当する関数
66
+ # データがあり、かつ先にあるデータのほうが値が小さい場合1を返し、それ以外なら0を返す。
67
+ if sr[1:] and sr[1] > sr[0] and sr[2:] and sr[2] > sr[1]:
68
+ return 1
69
+ return 0
70
+
71
+ # 2行ずつデータを処理する。min_periods=1を指定しないと、最初の行が処理されない。
72
+ rolling = df['close'].rolling(3, min_periods=1)
73
+
74
+ # raw=Trueはpandas側の将来的な変更に対処するため。
75
+ # なくても今は動くが、警告が出る。
76
+ aggregated = df.apply(aggregate, raw=True)
77
+
78
+ # aggregatedのそれぞれの値を'true'か'-'の文字列値に変えてdf['signal']に格納する。
79
+ df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
80
+ ```
81
+
82
+ forでやる方法
83
+ ```forでやる場合
84
+ x = []
85
+ for i, f in enumerate(df['close']):
86
+ if i == 0 or i == 1:
87
+ x.append('-')
88
+ continue
89
+ x.append('true' if f > df['close'].iloc[i-1] and df['close'].iloc[i-1] > df['close'].iloc[i-2] else '-')
90
+
91
+ df['signal'] = x
92
+ ```

3

冗長な記述を削除

2020/01/21 09:11

投稿

frodo821
frodo821

スコア322

answer CHANGED
@@ -23,7 +23,7 @@
23
23
  # なくても今は動くが、警告が出る。
24
24
  aggregated = df.apply(aggregate, raw=True)
25
25
 
26
- # aggregatedを'true'か'-'の文字列値に変えてdf['signal']に格納する。
26
+ # aggregatedのそれぞれの値を'true'か'-'の文字列値に変えてdf['signal']に格納する。
27
27
  df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
28
28
  ```
29
29
 
@@ -44,7 +44,7 @@
44
44
  continue
45
45
  x.append('true' if f > df['close'].iloc[i-1] else '-')
46
46
 
47
- df['signal'] = pd.Series(x)
47
+ df['signal'] = x
48
48
  ```
49
49
 
50
50
  こっちのほうが見た目明らかにすっきりしていますね。

2

詳しい解説を追加

2020/01/21 09:04

投稿

frodo821
frodo821

スコア322

answer CHANGED
@@ -1,7 +1,50 @@
1
1
  すこし冗長ですが、こういうやり方もあります。
2
2
 
3
+ ```python
4
+ 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 '-')
3
5
  ```
6
+
7
+ DataFrame.rollingやSeries.rollingは、複数の行または列にわたって集計するための関数です。
8
+
9
+ これを少し見やすくして解説します。
10
+
11
+ ```python
12
+ def aggregate(sr):
13
+ # `lambda sr: 1 if sr[1:] and sr[1] > sr[0] else 0`に相当する関数
14
+ # データがあり、かつ先にあるデータのほうが値が小さい場合1を返し、それ以外なら0を返す。
15
+ if sr[1:] and sr[1] > sr[0]:
16
+ return 1
17
+ return 0
18
+
19
+ # 2行ずつデータを処理する。min_periods=1を指定しないと、最初の行が処理されない。
20
+ rolling = df['close'].rolling(2, min_periods=1)
21
+
22
+ # raw=Trueはpandas側の将来的な変更に対処するため。
23
+ # なくても今は動くが、警告が出る。
24
+ aggregated = df.apply(aggregate, raw=True)
25
+
26
+ # aggregatedを'true'か'-'の文字列値に変えてdf['signal']に格納する。
4
- 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)
27
+ df['signal'] = aggregated.apply(lambda x: 'true' if x else '-')
5
28
  ```
6
29
 
30
+ 見やすくして簡単にコメントをつけてみました。
31
+ 複数行の処理には`rolling`メソッドを使います。
32
+ 今回の場合、`'close'`行のみ集計に使うので、`df['close']`でこの行のみに処理を行っています。
33
+
7
- DataFrame.rollingは、複数の行または列わたっ集計すための関数です。
34
+ また、処理を2段階分けるのは、`rolling.apply`に数値以外を返す関数は渡すことがきないからです。
35
+
36
+ ここまでやるのであれば、おそらくfor文でやったほうがいいような気がします。
37
+ 一応その場合も書いておきます。
38
+
39
+ ```forでやる場合
40
+ x = []
41
+ for i, f in enumerate(df['close']):
42
+ if i == 0:
43
+ x.append('-')
44
+ continue
45
+ x.append('true' if f > df['close'].iloc[i-1] else '-')
46
+
47
+ df['signal'] = pd.Series(x)
48
+ ```
49
+
50
+ こっちのほうが見た目明らかにすっきりしていますね。

1

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

2020/01/21 09:02

投稿

frodo821
frodo821

スコア322

answer CHANGED
@@ -1,8 +1,7 @@
1
+ すこし冗長ですが、こういうやり方もあります。
2
+
1
3
  ```
2
- def signal(df):
3
- if df['close'].iloc[-1] > df['close'].iloc[-2]:
4
+ 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)
4
- return 'true'
5
- else:
6
- return '-'
7
- df['signal'] = df.apply(signal, axis=1)
8
- ```
5
+ ```
6
+
7
+ DataFrame.rollingは、複数の行または列にわたって集計するための関数です。