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

回答編集履歴

3

追記

2020/03/27 02:35

投稿

kirara0048
kirara0048

スコア1399

answer CHANGED
@@ -26,7 +26,8 @@
26
26
  たとえば、
27
27
 
28
28
  ```python
29
- s = pd.Series([10, 10, 10, 12, 12, 12, 13, 13, 13, 1, 10, 12, 13, 1, 10, 11, 1, 13, 12])
29
+ s = pd.Series([10, 10, 10, 12, 13, 13, 0, 0, 10, 12, 13, 10, 12, 10, 12, 13, 13])
30
+ # [10, 10, 10, 12, 13, 13, 10, 12, 13, , 10, 12, 13, 13]
30
31
  v = np.array([10, 12, 13])
31
32
 
32
33
  function(s.to_numpy(), v)
@@ -35,12 +36,94 @@
35
36
  # 1 10 1
36
37
  # 2 10 1
37
38
  # 3 12 1
38
- # 4 12 1
39
+ # 4 13 1
39
- # 5 12 1
40
+ # 5 13 1
40
- # 6 13 1
41
+ # 6 10 2
41
- # 7 13 1
42
+ # 7 12 2
42
- # 8 13 1
43
+ # 8 13 2
43
- # 9 10 2
44
+ # 9 10 3
44
- # 10 12 2
45
+ # 10 12 3
45
- # 11 13 2
46
+ # 11 13 3
47
+ # 12 13 3
48
+ ```
49
+
50
+ ## 挙動の解説
51
+
52
+ ### 1. 同じ値が連続する部分の除外
53
+
54
+ 「`10,12,13`はどれくらい連続しているか分からない」ということなので、同じ数が連続する部分をひとまとめにします。これは、インデックスを一つずらした配列と比較することで取得できます。
55
+
56
+ ```python
57
+ cut_index, = np.r_[True, a[1:] != a[:-1], True].nonzero()
58
+ short_a = a[cut_index[:-1]]
59
+
60
+ """
61
+ a : [10, 10, 10, 12, 13, 13, 0, 0, 10, 12, 13, 10, 12, 10, 12, 13, 13]
62
+
63
+ a[1:] : 10 [10, 10, 12, 13, 13, 0, 0, 10, 12, 13, 10, 12, 10, 12, 13, 13]
64
+ a[:-1] : [10, 10, 10, 12, 13, 13, 0, 0, 10, 12, 13, 10, 12, 10, 12, 13] 13
65
+ a[1:] != a[:-1] : [ F, F, T, T, F, T, F, T, T, T, T, T, T, T, T, F]
66
+ (concatenate) : [ T, F, F, T, T, F, T, F, T, T, T, T, T, T, T, T, F, T]
67
+
68
+ cut_index : [ 0, 3, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 17]
69
+ short_a : [10, 12, 13, 0, 10, 12, 13, 10, 12, 10, 12, 13, ]
70
+ """
71
+ ```
72
+
73
+ ### 2. 一致箇所の検索
74
+
75
+ 前節で作成した配列`short_a`から、`10,12,13`のまとまりを探します。
76
+ そのためにまず、`short_a`を3つずつ区切るためのインデックスを作成します。
77
+
78
+ ```python
79
+ slide_index = np.arange(short_a.size-v_size+1)[:, None] + np.arange(v_size)
80
+ print(slide_index)
81
+ # [[ 0 1 2]
82
+ # [ 1 2 3]
83
+ # [ 2 3 4]
84
+ # ...
85
+ # [ 7 8 9]
86
+ # [ 8 9 10]
87
+ # [ 9 10 11]]
88
+ ```
89
+
90
+ `v`と比較することで、`10,12,13`と一致する箇所を探します。
91
+
92
+ ```python
93
+ match = (short_a[slide_index] == v).all(1)
94
+
95
+ """
96
+ slide_a : [[10, 12, 13], [12, 13, 0], [13, 0, 10], [ 0, 10, 12], [10, 12, 13], ...]
97
+ v : [[10, 12, 13], [ > ], [ > ], [ > ], [ > ], ...]
98
+ match : [ True, False, False, False, True, ...]
99
+ """
100
+ ```
101
+
102
+ `match`で得られた`True`は、`10,12,13`の`10`の位置のみなので、`np.convolve()`を利用して`10,12,13`の位置が`True`になるようにします。
103
+
104
+ ```python
105
+ all_match = np.convolve(match, np.ones(v_size, dtype=int))
106
+
107
+ """
108
+ short_a : [10, 12, 13, 0, 10, 12, 13, 10, 12, 10, 12, 13]
109
+ match : [ T, F, F, F, T, F, F, F, F, T]
110
+ all_match : [ 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1]
111
+ """
112
+ ```
113
+
114
+ ### 3. 一致箇所の拡大復元
115
+
116
+ 前節で求めた`all_match`は、`10,10,10`のように同じ値が連続する部分がまとまった配列に対する位置なので、`np.repeat()`を用いて1.の逆を行います。
117
+
118
+ ```python
119
+ index, = np.repeat(all_match, np.ediff1d(cut_index)).nonzero()
120
+
121
+ """
122
+ a : [10, 10, 10, 12, 13, 13, 0, 0, 10, 12, 13, 10, 12, 10, 12, 13, 13]
123
+ cut_index : [ 0, 3, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 17]
124
+
125
+ all_match : [ 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, ]
126
+ (repeat) : [ 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1]
127
+ index : [ 0, 1, 2, 3, 4, 5, 8, 9, 10, 13, 14, 15, 16]
128
+ """
46
129
  ```

2

微修正

2020/03/27 02:35

投稿

kirara0048
kirara0048

スコア1399

answer CHANGED
@@ -18,7 +18,7 @@
18
18
  result_array = a[index]
19
19
  result_index = np.isin(index, cut_index[match.nonzero()[0]]).cumsum()
20
20
 
21
- return pd.DataFrame({'value': result_array, 'index': result_index})
21
+ return pd.DataFrame({'num': result_array, 'id': result_index})
22
22
  ```
23
23
 
24
24
  第一引数には対象のシリーズをnumpy配列に変換したものを、
@@ -30,17 +30,17 @@
30
30
  v = np.array([10, 12, 13])
31
31
 
32
32
  function(s.to_numpy(), v)
33
- # value index
33
+ # num id
34
- # 0 10 1
34
+ # 0 10 1
35
- # 1 10 1
35
+ # 1 10 1
36
- # 2 10 1
36
+ # 2 10 1
37
- # 3 12 1
37
+ # 3 12 1
38
- # 4 12 1
38
+ # 4 12 1
39
- # 5 12 1
39
+ # 5 12 1
40
- # 6 13 1
40
+ # 6 13 1
41
- # 7 13 1
41
+ # 7 13 1
42
- # 8 13 1
42
+ # 8 13 1
43
- # 9 10 2
43
+ # 9 10 2
44
- # 10 12 2
44
+ # 10 12 2
45
- # 11 13 2
45
+ # 11 13 2
46
46
  ```

1

微修正

2020/03/19 05:08

投稿

kirara0048
kirara0048

スコア1399

answer CHANGED
@@ -10,10 +10,10 @@
10
10
 
11
11
  cut_index, = np.r_[True, a[1:] != a[:-1], True].nonzero()
12
12
  short_a = a[cut_index[:-1]]
13
- slide_index = np.arange(short_a.size-v.size+1)[:, None] + np.arange(v.size)
13
+ slide_index = np.arange(short_a.size-v_size+1)[:, None] + np.arange(v_size)
14
14
  match = (short_a[slide_index] == v).all(1)
15
15
  all_match = np.convolve(match, np.ones(v_size, dtype=int))
16
- index = np.repeat(all_match, np.ediff1d(cut_index)).nonzero()[0]
16
+ index, = np.repeat(all_match, np.ediff1d(cut_index)).nonzero()
17
17
 
18
18
  result_array = a[index]
19
19
  result_index = np.isin(index, cut_index[match.nonzero()[0]]).cumsum()