polars-ta 0.4.7__py3-none-any.whl → 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
polars_ta/utils/numba_.py CHANGED
@@ -6,6 +6,7 @@ from typing import List
6
6
 
7
7
  import numpy as np
8
8
  from numba import jit
9
+ from numpy import full
9
10
  from numpy.lib.stride_tricks import sliding_window_view
10
11
  from polars import Series, Expr, struct, DataFrame
11
12
 
@@ -15,6 +16,90 @@ batches_i1_o1这一类的函数输入不支持Series,只支持numpy。设计
15
16
  """
16
17
 
17
18
 
19
+ @jit(nopython=True, nogil=True, fastmath=True, cache=True)
20
+ def isnan(x):
21
+ # https://github.com/numba/numba/issues/2919#issuecomment-747377615
22
+ if int(x) == -9223372036854775808:
23
+ return True
24
+ else:
25
+ return False
26
+
27
+
28
+ @jit(nopython=True, nogil=True, cache=True)
29
+ def full_with_window_size(arr, fill_value, dtype=None, window_size: int = 1):
30
+ out = full(arr.shape[0] + window_size - 1, fill_value, dtype=dtype)
31
+ out[window_size - 1:] = arr
32
+ return out
33
+
34
+
35
+ @jit(nopython=True, nogil=True, cache=True)
36
+ def sliding_window_with_min_periods(arr, window_size: int, min_periods: int):
37
+ windows = sliding_window_view(arr, window_size)
38
+ valid_counts = np.sum(~np.isnan(windows), axis=1)
39
+ # 修改这一行,使用布尔索引而不是np.where
40
+ result = windows.copy()
41
+ result[valid_counts < min_periods] = np.nan
42
+ return result
43
+
44
+
45
+ @jit(nopython=True, nogil=True, cache=True)
46
+ def _roll_1(x1: np.ndarray, window: int, min_periods: int, func):
47
+ """TODO 只是模板演示,无法编译通过"""
48
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
49
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
50
+ out1[:] = np.nan
51
+ for i, v1 in enumerate(a1):
52
+ if np.isnan(v1).all():
53
+ continue
54
+ out1[i] = func(v1)
55
+ return out1[:x1.shape[0]]
56
+
57
+
58
+ @jit(nopython=True, nogil=True, cache=True)
59
+ def _roll_2(x1, x2, window, min_periods, func):
60
+ """TODO 只是模板演示,无法编译通过"""
61
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
62
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
63
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
64
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
65
+ out1[:] = np.nan
66
+ for i, (v1, v2) in enumerate(zip(a1, a2)):
67
+ if np.isnan(v1).all():
68
+ continue
69
+ if np.isnan(v2).all():
70
+ continue
71
+ out1[i] = func(v1, v2)
72
+ return out1[:x1.shape[0]]
73
+
74
+
75
+ @jit(nopython=True, nogil=True, cache=True)
76
+ def _roll_3(x1, x2, x3, window, min_periods, func):
77
+ """TODO 只是模板演示,无法编译通过"""
78
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
79
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
80
+ out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
81
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
82
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
83
+ a3 = sliding_window_with_min_periods(out3, window, min_periods)
84
+ out1[:] = np.nan
85
+ for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
86
+ if np.isnan(v1).all():
87
+ continue
88
+ if np.isnan(v2).all():
89
+ continue
90
+ if np.isnan(v3).all():
91
+ continue
92
+ out1[i] = func(v1, v2, v3)
93
+ return out1[:x1.shape[0]]
94
+
95
+
96
+ def struct_to_numpy(xx, n: int, dtype=None):
97
+ if dtype is None:
98
+ return [xx.struct[i].to_numpy() for i in range(n)]
99
+ else:
100
+ return [xx.struct[i].to_numpy().astype(dtype) for i in range(n)]
101
+
102
+
18
103
  def batches_i1_o1(x1: np.ndarray, func, *args, dtype=None) -> Series:
19
104
  return Series(func(x1, *args), nan_to_null=True, dtype=dtype)
20
105
 
@@ -24,15 +109,11 @@ def batches_i2_o1(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
24
109
 
25
110
 
26
111
  def batches_i1_o2(x1: np.ndarray, func, *args, dtype=None) -> Series:
27
- out = func(x1, *args)
28
- ss = [Series(x, nan_to_null=True, dtype=dtype) for x in out]
29
- return DataFrame(ss).to_struct()
112
+ return DataFrame(func(x1, *args), nan_to_null=True).to_struct()
30
113
 
31
114
 
32
115
  def batches_i2_o2(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
33
- out = func(*xx, *args)
34
- ss = [Series(x, nan_to_null=True, dtype=dtype) for x in out]
35
- return DataFrame(ss).to_struct()
116
+ return DataFrame(func(*xx, *args), nan_to_null=True).to_struct()
36
117
 
37
118
 
38
119
  def batches_i2_o2_v2(xx: List[np.ndarray], func, *args, dtype=None) -> Series:
@@ -76,4 +157,4 @@ def roll_sum(x: Expr, n: int) -> Expr:
76
157
 
77
158
 
78
159
  def roll_cov(a: Expr, b: Expr, n: int) -> Expr:
79
- return struct([a, b]).map_batches(lambda xx: batches_i2_o1([xx.struct[i].to_numpy() for i in range(2)], nb_roll_cov, n))
160
+ return struct([a, b]).map_batches(lambda xx: batches_i2_o1(struct_to_numpy(xx, 2), nb_roll_cov, n))
@@ -35,7 +35,7 @@ def get_window_bounds(
35
35
  return start, end
36
36
 
37
37
 
38
- def roll_rank(x: Series, d: int, pct: bool = True, method: str = 'average', ascending: bool = True):
38
+ def roll_rank(x: Series, d: int, minp: int, pct: bool = True, method: str = 'average', ascending: bool = True):
39
39
  start, end = get_window_bounds(len(x), d)
40
40
  """
41
41
  https://github.com/pandas-dev/pandas/blob/main/pandas/_libs/window/aggregations.pyx#L1281
@@ -46,11 +46,11 @@ def roll_rank(x: Series, d: int, pct: bool = True, method: str = 'average', asce
46
46
 
47
47
  O(N log(window)) implementation using skip list
48
48
  """
49
- ret = _roll_rank(x.to_numpy().astype(float), start, end, d, pct, method, ascending)
49
+ ret = _roll_rank(x.to_numpy().astype(float), start, end, minp, pct, method, ascending)
50
50
  return Series(ret, nan_to_null=True)
51
51
 
52
52
 
53
- def roll_kurt(x, d):
53
+ def roll_kurt(x, d: int, minp: int):
54
54
  start, end = get_window_bounds(len(x), d)
55
55
  """
56
56
  https://github.com/pandas-dev/pandas/blob/main/pandas/_libs/window/aggregations.pyx#L803
@@ -58,5 +58,5 @@ def roll_kurt(x, d):
58
58
  def roll_kurt(ndarray[float64_t] values, ndarray[int64_t] start,
59
59
  ndarray[int64_t] end, int64_t minp) -> np.ndarray:
60
60
  """
61
- ret = _roll_kurt(x.to_numpy().astype(float), start, end, d)
61
+ ret = _roll_kurt(x.to_numpy().astype(float), start, end, minp)
62
62
  return Series(ret, nan_to_null=True)
polars_ta/wq/_nb.py CHANGED
@@ -1,107 +1,121 @@
1
1
  import numpy as np
2
- from numba import jit, float64, bool_
3
- from numpy import argmax, argmin, prod, mean, std, full, vstack, corrcoef
2
+ from numba import jit, float64, boolean
3
+ from numpy import argmax, argmin, full, vstack, corrcoef, nanprod, nanmean, nanstd
4
4
  from numpy.lib.stride_tricks import sliding_window_view
5
5
 
6
+ from polars_ta.utils.numba_ import isnan, full_with_window_size, sliding_window_with_min_periods
6
7
 
7
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
8
- def roll_argmax(x1, window, reverse):
9
- out = full(x1.shape, np.nan, dtype=np.float64)
10
- if len(x1) < window:
11
- return out
12
- a1 = sliding_window_view(x1, window)
8
+
9
+ @jit(nopython=True, nogil=True, cache=True)
10
+ def roll_argmax(x1, window, min_periods, reverse):
11
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
12
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
13
+ out1[:] = np.nan
13
14
  if reverse:
14
15
  a1 = a1[:, ::-1]
15
16
  for i, v1 in enumerate(a1):
16
- out[i + window - 1] = argmax(v1)
17
- return out
17
+ if np.isnan(v1).all():
18
+ continue
19
+ out1[i] = argmax(v1)
20
+ return out1[:x1.shape[0]]
18
21
 
19
22
 
20
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
21
- def roll_argmin(x1, window, reverse):
22
- out = full(x1.shape, np.nan, dtype=np.float64)
23
- if len(x1) < window:
24
- return out
25
- a1 = sliding_window_view(x1, window)
23
+ @jit(nopython=True, nogil=True, cache=True)
24
+ def roll_argmin(x1, window, min_periods, reverse):
25
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
26
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
27
+ out1[:] = np.nan
26
28
  if reverse:
27
29
  a1 = a1[:, ::-1]
28
30
  for i, v1 in enumerate(a1):
29
- out[i + window - 1] = argmin(v1)
30
- return out
31
+ if np.isnan(v1).all():
32
+ continue
33
+ out1[i] = argmin(v1)
34
+ return out1[:x1.shape[0]]
31
35
 
32
36
 
33
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
34
- def roll_prod(x1, window):
35
- out = full(x1.shape, np.nan, dtype=np.float64)
36
- if len(x1) < window:
37
- return out
38
- a1 = sliding_window_view(x1, window)
37
+ @jit(nopython=True, nogil=True, cache=True)
38
+ def roll_prod(x1, window, min_periods):
39
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
40
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
41
+ out1[:] = np.nan
39
42
  for i, v1 in enumerate(a1):
40
- out[i + window - 1] = prod(v1)
41
- return out
43
+ if np.isnan(v1).all():
44
+ continue
45
+ out1[i] = nanprod(v1)
46
+ return out1[:x1.shape[0]]
42
47
 
43
48
 
44
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
49
+ @jit(nopython=True, nogil=True, cache=True)
45
50
  def _co_kurtosis(a1, a2):
46
- t1 = a1 - mean(a1)
47
- t2 = a2 - mean(a2)
48
- t3 = std(a1)
49
- t4 = std(a2)
50
- return mean(t1 * (t2 ** 3)) / (t3 * (t4 ** 3))
51
+ t1 = a1 - nanmean(a1)
52
+ t2 = a2 - nanmean(a2)
53
+ t3 = nanstd(a1)
54
+ t4 = nanstd(a2)
55
+ return nanmean(t1 * (t2 ** 3)) / (t3 * (t4 ** 3))
51
56
 
52
57
 
53
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
54
- def roll_co_kurtosis(x1, x2, window):
55
- out = full(x1.shape, np.nan, dtype=np.float64)
56
- if len(x1) < window:
57
- return out
58
- a1 = sliding_window_view(x1, window)
59
- a2 = sliding_window_view(x2, window)
58
+ @jit(nopython=True, nogil=True, cache=True)
59
+ def roll_co_kurtosis(x1, x2, window, min_periods):
60
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
61
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
62
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
63
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
64
+ out1[:] = np.nan
60
65
  for i, (v1, v2) in enumerate(zip(a1, a2)):
61
- out[i + window - 1] = _co_kurtosis(v1, v2)
62
- return out
66
+ if np.isnan(v1).all():
67
+ continue
68
+ if np.isnan(v2).all():
69
+ continue
70
+ out1[i] = _co_kurtosis(v1, v2)
71
+ return out1[:x1.shape[0]]
63
72
 
64
73
 
65
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
74
+ @jit(nopython=True, nogil=True, cache=True)
66
75
  def _co_skewness(a1, a2):
67
- t1 = a1 - mean(a1)
68
- t2 = a2 - mean(a2)
69
- t3 = std(a1)
70
- t4 = std(a2)
71
- return mean(t1 * (t2 ** 2)) / (t3 * (t4 ** 2))
76
+ t1 = a1 - nanmean(a1)
77
+ t2 = a2 - nanmean(a2)
78
+ t3 = nanstd(a1)
79
+ t4 = nanstd(a2)
80
+ return nanmean(t1 * (t2 ** 2)) / (t3 * (t4 ** 2))
72
81
 
73
82
 
74
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
75
- def roll_co_skewness(x1, x2, window):
76
- out = full(x1.shape, np.nan, dtype=np.float64)
77
- if len(x1) < window:
78
- return out
79
- a1 = sliding_window_view(x1, window)
80
- a2 = sliding_window_view(x2, window)
83
+ @jit(nopython=True, nogil=True, cache=True)
84
+ def roll_co_skewness(x1, x2, window, min_periods):
85
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
86
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
87
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
88
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
89
+ out1[:] = np.nan
81
90
  for i, (v1, v2) in enumerate(zip(a1, a2)):
82
- out[i + window - 1] = _co_skewness(v1, v2)
83
- return out
91
+ if np.isnan(v1).all():
92
+ continue
93
+ if np.isnan(v2).all():
94
+ continue
95
+ out1[i] = _co_skewness(v1, v2)
96
+ return out1[:x1.shape[0]]
84
97
 
85
98
 
86
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
99
+ @jit(nopython=True, nogil=True, cache=True)
87
100
  def _moment(a1, k):
88
101
  """centeral moment
89
102
  中心矩阵"""
90
- return mean((a1 - mean(a1)) ** k)
103
+ return nanmean((a1 - nanmean(a1)) ** k)
91
104
 
92
105
 
93
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
94
- def roll_moment(x1, window, k):
95
- out = full(x1.shape, np.nan, dtype=np.float64)
96
- if len(x1) < window:
97
- return out
98
- a1 = sliding_window_view(x1, window)
106
+ @jit(nopython=True, nogil=True, cache=True)
107
+ def roll_moment(x1, window, min_periods, k):
108
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
109
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
110
+ out1[:] = np.nan
99
111
  for i, v1 in enumerate(a1):
100
- out[i + window - 1] = _moment(v1, k)
101
- return out
112
+ if np.isnan(v1).all():
113
+ continue
114
+ out1[i] = _moment(v1, k)
115
+ return out1[:x1.shape[0]]
102
116
 
103
117
 
104
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
118
+ @jit(nopython=True, nogil=True, cache=True)
105
119
  def _partial_corr(a1, a2, a3):
106
120
  """TODO 不知是否正确,需要检查"""
107
121
  c = corrcoef(vstack((a1, a2, a3)))
@@ -114,50 +128,55 @@ def _partial_corr(a1, a2, a3):
114
128
  return t1 / (t2 * t3)
115
129
 
116
130
 
117
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
118
- def roll_partial_corr(x1, x2, x3, window):
119
- out = full(x1.shape, np.nan, dtype=np.float64)
120
- if len(x1) < window:
121
- return out
122
- a1 = sliding_window_view(x1, window)
123
- a2 = sliding_window_view(x2, window)
124
- a3 = sliding_window_view(x3, window)
131
+ @jit(nopython=True, nogil=True, cache=True)
132
+ def roll_partial_corr(x1, x2, x3, window, min_periods):
133
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
134
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
135
+ out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
136
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
137
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
138
+ a3 = sliding_window_with_min_periods(out3, window, min_periods)
139
+ out1[:] = np.nan
125
140
  for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
126
- out[i + window - 1] = _partial_corr(v1, v2, v3)
127
- return out
141
+ if np.isnan(v1).all():
142
+ continue
143
+ if np.isnan(v2).all():
144
+ continue
145
+ if np.isnan(v3).all():
146
+ continue
147
+ out1[i] = _partial_corr(v1, v2, v3)
148
+ return out1[:x1.shape[0]]
128
149
 
129
150
 
130
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
151
+ @jit(nopython=True, nogil=True, cache=True)
131
152
  def _triple_corr(a1, a2, a3):
132
- t1 = a1 - mean(a1)
133
- t2 = a2 - mean(a2)
134
- t3 = a3 - mean(a3)
135
- t4 = std(a1)
136
- t5 = std(a2)
137
- t6 = std(a3)
138
- return mean(t1 * t2 * t3) / (t4 * t5 * t6)
153
+ t1 = a1 - nanmean(a1)
154
+ t2 = a2 - nanmean(a2)
155
+ t3 = a3 - nanmean(a3)
156
+ t4 = nanstd(a1)
157
+ t5 = nanstd(a2)
158
+ t6 = nanstd(a3)
159
+ return nanmean(t1 * t2 * t3) / (t4 * t5 * t6)
139
160
 
140
161
 
141
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
142
- def roll_triple_corr(x1, x2, x3, window):
143
- out = full(x1.shape, np.nan, dtype=np.float64)
144
- if len(x1) < window:
145
- return out
146
- a1 = sliding_window_view(x1, window)
147
- a2 = sliding_window_view(x2, window)
148
- a3 = sliding_window_view(x3, window)
162
+ @jit(nopython=True, nogil=True, cache=True)
163
+ def roll_triple_corr(x1, x2, x3, window, min_periods):
164
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
165
+ out2 = full_with_window_size(x2, np.nan, dtype=np.float64, window_size=window)
166
+ out3 = full_with_window_size(x3, np.nan, dtype=np.float64, window_size=window)
167
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
168
+ a2 = sliding_window_with_min_periods(out2, window, min_periods)
169
+ a3 = sliding_window_with_min_periods(out3, window, min_periods)
170
+ out1[:] = np.nan
149
171
  for i, (v1, v2, v3) in enumerate(zip(a1, a2, a3)):
150
- out[i + window - 1] = _triple_corr(v1, v2, v3)
151
- return out
152
-
153
-
154
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
155
- def isnan(x):
156
- # https://github.com/numba/numba/issues/2919#issuecomment-747377615
157
- if int(x) == -9223372036854775808:
158
- return True
159
- else:
160
- return False
172
+ if np.isnan(v1).all():
173
+ continue
174
+ if np.isnan(v2).all():
175
+ continue
176
+ if np.isnan(v3).all():
177
+ continue
178
+ out1[i] = _triple_corr(v1, v2, v3)
179
+ return out1[:x1.shape[0]]
161
180
 
162
181
 
163
182
  @jit(nopython=True, nogil=True, fastmath=True, cache=True)
@@ -217,7 +236,8 @@ def _sum_split_by(x1, x2, window=10, n=2):
217
236
  return out1, out2
218
237
 
219
238
 
220
- @jit(float64[:](bool_[:], bool_[:], bool_[:], bool_[:], bool_, bool_), nopython=True, fastmath=True, nogil=True, cache=True)
239
+ @jit(float64[:](boolean[:], boolean[:], boolean[:], boolean[:], boolean, boolean),
240
+ nopython=True, nogil=True, cache=True)
221
241
  def _signals_to_size(is_long_entry: np.ndarray, is_long_exit: np.ndarray,
222
242
  is_short_entry: np.ndarray, is_short_exit: np.ndarray,
223
243
  accumulate: bool = False,
@@ -289,27 +309,31 @@ def _signals_to_size(is_long_entry: np.ndarray, is_long_exit: np.ndarray,
289
309
  return out
290
310
 
291
311
 
292
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
293
- def roll_decay_linear(x1, window):
294
- out = full(x1.shape, np.nan, dtype=np.float64)
295
- if len(x1) < window:
296
- return out
312
+ @jit(nopython=True, nogil=True, cache=True)
313
+ def roll_decay_linear(x1, window, min_periods):
297
314
  weights = np.arange(1., window + 1)
298
- # print(weights)
299
- a1 = sliding_window_view(x1, window)
315
+
316
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
317
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
318
+ out1[:] = np.nan
300
319
  for i, v1 in enumerate(a1):
301
- out[i + window - 1] = np.average(v1, weights=weights)
302
- return out
320
+ if np.isnan(v1).all():
321
+ continue
322
+ mask = ~np.isnan(v1)
323
+ out1[i] = np.average(v1[mask], weights=weights[mask])
324
+ return out1[:x1.shape[0]]
303
325
 
304
326
 
305
- @jit(nopython=True, nogil=True, fastmath=True, cache=True)
306
- def roll_decay_exp_window(x1, window, factor):
307
- out = full(x1.shape, np.nan, dtype=np.float64)
308
- if len(x1) < window:
309
- return out
327
+ @jit(nopython=True, nogil=True, cache=True)
328
+ def roll_decay_exp_window(x1, window, min_periods, factor):
310
329
  weights = factor ** np.arange(window - 1, -1, -1)
311
- # print(weights)
312
- a1 = sliding_window_view(x1, window)
330
+
331
+ out1 = full_with_window_size(x1, np.nan, dtype=np.float64, window_size=window)
332
+ a1 = sliding_window_with_min_periods(out1, window, min_periods)
333
+ out1[:] = np.nan
313
334
  for i, v1 in enumerate(a1):
314
- out[i + window - 1] = np.average(v1, weights=weights)
315
- return out
335
+ if np.isnan(v1).all():
336
+ continue
337
+ mask = ~np.isnan(v1)
338
+ out1[i] = np.average(v1[mask], weights=weights[mask])
339
+ return out1[:x1.shape[0]]