Skip to content

Commit 9edac4d

Browse files
immproved inefficiency in fct group_frequency
1 parent e608755 commit 9edac4d

File tree

2 files changed

+70
-43
lines changed

2 files changed

+70
-43
lines changed

climada/util/interpolation.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -344,16 +344,36 @@ def group_frequency(frequency, value, n_sig_dig=2):
344344
if frequency.size == 0 and value.size == 0:
345345
return ([], [])
346346

347-
if len(value) != len(np.unique(sig_dig_list(value, n_sig_dig=n_sig_dig))):
348-
#check ordering of value
349-
if not all(sorted(value) == value):
347+
# round values and group them
348+
value = round_to_sig_digits(value, n_sig_dig)
349+
value_unique, start_indices = np.unique(value, return_index=True)
350+
351+
if value_unique.size != frequency.size:
352+
if not all(sorted(start_indices) == start_indices):
350353
raise ValueError('Value array must be sorted in ascending order.')
351354
# add frequency for equal value
352-
value, start_indices = np.unique(
353-
sig_dig_list(value, n_sig_dig=n_sig_dig), return_index=True)
354-
start_indices = np.insert(start_indices, len(value), len(frequency))
355-
frequency = np.array([
356-
sum(frequency[start_indices[i]:start_indices[i+1]])
357-
for i in range(len(value))
358-
])
355+
start_indices = np.insert(start_indices, value_unique.size, frequency.size)
356+
frequency = np.add.reduceat(frequency, start_indices[:-1])
357+
return frequency, value_unique
358+
359359
return frequency, value
360+
361+
def round_to_sig_digits(x, n_sig_dig):
362+
"""round each element array to a number of significant digits
363+
364+
Parameters
365+
----------
366+
x : array-like
367+
array to be rounded
368+
n_sig_dig : int
369+
number of significant digits.
370+
371+
Returns
372+
-------
373+
np.array
374+
rounded array
375+
"""
376+
x = np.asarray(x)
377+
x_positive = np.where(np.isfinite(x) & (x != 0), np.abs(x), 10**(n_sig_dig-1))
378+
mags = 10 ** (n_sig_dig - 1 - np.floor(np.log10(x_positive)))
379+
return np.round(x * mags) / mags

climada/util/test/test_interpolation.py

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import unittest
2323
import numpy as np
2424

25-
from climada.util.interpolation import interpolate_ev, stepfunction_ev, group_frequency, preprocess_and_interpolate_ev
25+
import climada.util.interpolation as u_interp
2626

2727

2828
class TestFitMethods(unittest.TestCase):
@@ -34,15 +34,15 @@ def test_interpolate_ev_linear_interp(self):
3434
y_train = np.array([8., 4., 2.])
3535
x_test = np.array([0., 3., 4., 6.])
3636
np.testing.assert_allclose(
37-
interpolate_ev(x_test, x_train, y_train),
37+
u_interp.interpolate_ev(x_test, x_train, y_train),
3838
np.array([np.nan, 4., 3., np.nan])
3939
)
4040
np.testing.assert_allclose(
41-
interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate_constant'),
41+
u_interp.interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate_constant'),
4242
np.array([8., 4., 3., np.nan])
4343
)
4444
np.testing.assert_allclose(
45-
interpolate_ev(x_test, x_train, y_train,
45+
u_interp.interpolate_ev(x_test, x_train, y_train,
4646
extrapolation='extrapolate_constant', y_asymptotic = 0),
4747
np.array([8., 4., 3., 0.])
4848
)
@@ -53,16 +53,16 @@ def test_interpolate_ev_threshold_parameters(self):
5353
y_train = np.array([4., 1., 4.])
5454
x_test = np.array([-1., 3., 4.])
5555
np.testing.assert_allclose(
56-
interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate_constant'),
56+
u_interp.interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate_constant'),
5757
np.array([4., 1., 2.])
5858
)
5959
np.testing.assert_allclose(
60-
interpolate_ev(x_test, x_train, y_train, x_threshold=1.,
60+
u_interp.interpolate_ev(x_test, x_train, y_train, x_threshold=1.,
6161
extrapolation='extrapolate_constant'),
6262
np.array([1., 1., 2.])
6363
)
6464
np.testing.assert_allclose(
65-
interpolate_ev(x_test, x_train, y_train, y_threshold=2.,
65+
u_interp.interpolate_ev(x_test, x_train, y_train, y_threshold=2.,
6666
extrapolation='extrapolate_constant'),
6767
np.array([4., 4., 4.])
6868
)
@@ -73,26 +73,26 @@ def test_interpolate_ev_scale_parameters(self):
7373
y_train = np.array([1., 3.])
7474
x_test = np.array([1e0, 1e2])
7575
np.testing.assert_allclose(
76-
interpolate_ev(x_test, x_train, y_train, logx=True, extrapolation='extrapolate'),
76+
u_interp.interpolate_ev(x_test, x_train, y_train, logx=True, extrapolation='extrapolate'),
7777
np.array([0., 2.])
7878
)
7979
np.testing.assert_allclose(
80-
interpolate_ev(x_test, x_train, y_train, logx=True,
80+
u_interp.interpolate_ev(x_test, x_train, y_train, logx=True,
8181
extrapolation='extrapolate_constant'),
8282
np.array([1., 2.])
8383
)
8484
x_train = np.array([1., 3.])
8585
y_train = np.array([1e1, 1e3])
8686
x_test = np.array([0., 2.])
8787
np.testing.assert_allclose(
88-
interpolate_ev(x_test, x_train, y_train, logy=True, extrapolation='extrapolate'),
88+
u_interp.interpolate_ev(x_test, x_train, y_train, logy=True, extrapolation='extrapolate'),
8989
np.array([1e0, 1e2])
9090
)
9191
x_train = np.array([1e1, 1e3])
9292
y_train = np.array([1e1, 1e5])
9393
x_test = np.array([1e0, 1e2])
9494
np.testing.assert_allclose(
95-
interpolate_ev(x_test, x_train, y_train, logx=True, logy=True,
95+
u_interp.interpolate_ev(x_test, x_train, y_train, logx=True, logy=True,
9696
extrapolation='extrapolate'),
9797
np.array([1e-1, 1e3])
9898
)
@@ -103,7 +103,7 @@ def test_interpolate_ev_degenerate_input(self):
103103
x_test = np.array([0., 2., 4.])
104104
y_train = np.zeros(3)
105105
np.testing.assert_allclose(
106-
interpolate_ev(x_test, x_train, y_train),
106+
u_interp.interpolate_ev(x_test, x_train, y_train),
107107
np.array([np.nan, 0., 0.])
108108
)
109109

@@ -113,27 +113,27 @@ def test_interpolate_ev_small_input(self):
113113
y_train = np.array([2.])
114114
x_test = np.array([0., 1., 2.])
115115
np.testing.assert_allclose(
116-
interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate'),
116+
u_interp.interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate'),
117117
np.array([2., 2., np.nan])
118118
)
119119
np.testing.assert_allclose(
120-
interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate', y_asymptotic=0),
120+
u_interp.interpolate_ev(x_test, x_train, y_train, extrapolation='extrapolate', y_asymptotic=0),
121121
np.array([2., 2., 0.])
122122
)
123123
np.testing.assert_allclose(
124-
interpolate_ev(x_test, x_train, y_train),
124+
u_interp.interpolate_ev(x_test, x_train, y_train),
125125
np.full(3, np.nan)
126126
)
127127

128128
x_train = np.array([])
129129
y_train = np.array([])
130130
x_test = np.array([0., 1., 2.])
131131
np.testing.assert_allclose(
132-
interpolate_ev(x_test, x_train, y_train),
132+
u_interp.interpolate_ev(x_test, x_train, y_train),
133133
np.full(3, np.nan)
134134
)
135135
np.testing.assert_allclose(
136-
interpolate_ev(x_test, x_train, y_train,
136+
u_interp.interpolate_ev(x_test, x_train, y_train,
137137
extrapolation='extrapolate_constant', y_asymptotic=0),
138138
np.zeros(3)
139139
)
@@ -144,11 +144,11 @@ def test_stepfunction_ev(self):
144144
y_train = np.array([8., 4., 2.])
145145
x_test = np.array([0., 3., 4., 6.])
146146
np.testing.assert_allclose(
147-
stepfunction_ev(x_test, x_train, y_train),
147+
u_interp.stepfunction_ev(x_test, x_train, y_train),
148148
np.array([8., 4., 2., np.nan])
149149
)
150150
np.testing.assert_allclose(
151-
stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0.),
151+
u_interp.stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0.),
152152
np.array([8., 4., 2., 0.])
153153
)
154154

@@ -158,39 +158,46 @@ def test_stepfunction_ev_small_input(self):
158158
y_train = np.array([2.])
159159
x_test = np.array([0., 1., 2.])
160160
np.testing.assert_allclose(
161-
stepfunction_ev(x_test, x_train, y_train),
161+
u_interp.stepfunction_ev(x_test, x_train, y_train),
162162
np.array([2., 2., np.nan])
163163
)
164164
np.testing.assert_allclose(
165-
stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0),
165+
u_interp.stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0),
166166
np.array([2., 2., 0.])
167167
)
168168
x_train = np.array([])
169169
y_train = np.array([])
170170
x_test = np.array([0., 1., 2.])
171171
np.testing.assert_allclose(
172-
stepfunction_ev(x_test, x_train, y_train),
172+
u_interp.stepfunction_ev(x_test, x_train, y_train),
173173
np.full(3, np.nan)
174174
)
175175
np.testing.assert_allclose(
176-
stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0),
176+
u_interp.stepfunction_ev(x_test, x_train, y_train, y_asymptotic=0),
177177
np.zeros(3)
178178
)
179179

180180
def test_frequency_group(self):
181181
"""Test frequency grouping method"""
182182
frequency = np.ones(6)
183-
intensity = np.array([1., 1., 1., 2., 3., 3])
183+
intensity = np.array([1.00001, .999, 1., 2., 3., 3])
184184
np.testing.assert_allclose(
185-
group_frequency(frequency, intensity),
185+
u_interp.group_frequency(frequency, intensity),
186186
([3, 1, 2], [1, 2, 3])
187187
)
188188
np.testing.assert_allclose(
189-
group_frequency([], []),
189+
u_interp.group_frequency([], []),
190190
([], [])
191191
)
192192
with self.assertRaises(ValueError):
193-
group_frequency(frequency, intensity[::-1])
193+
u_interp.group_frequency(frequency, intensity[::-1])
194+
195+
def test_round_to_sig_digits(self):
196+
array = [.00111, 999., 55.5, 0., -1.001, -1.08]
197+
np.testing.assert_allclose(
198+
u_interp.round_to_sig_digits(array, n_sig_dig=2),
199+
[.0011, 1000., 56, 0., -1., -1.1]
200+
)
194201

195202
def test_preprocess_and_interpolate_ev(self):
196203
"""Test wrapper function"""
@@ -202,30 +209,30 @@ def test_preprocess_and_interpolate_ev(self):
202209
# test interpolation
203210
np.testing.assert_allclose(
204211
[np.nan, 55., np.nan],
205-
preprocess_and_interpolate_ev(test_frequency, None, frequency, values)
212+
u_interp.preprocess_and_interpolate_ev(test_frequency, None, frequency, values)
206213
)
207214
np.testing.assert_allclose(
208215
[np.nan, .55, np.nan],
209-
preprocess_and_interpolate_ev(None, test_values, frequency, values)
216+
u_interp.preprocess_and_interpolate_ev(None, test_values, frequency, values)
210217
)
211218

212219
# test extrapolation with constants
213220
np.testing.assert_allclose(
214221
[100. , 55., 0.],
215-
preprocess_and_interpolate_ev(test_frequency, None, frequency, values,
222+
u_interp.preprocess_and_interpolate_ev(test_frequency, None, frequency, values,
216223
method='extrapolate_constant', y_asymptotic=0.)
217224
)
218225
np.testing.assert_allclose(
219226
[1., .55, np.nan],
220-
preprocess_and_interpolate_ev(None, test_values, frequency, values,
227+
u_interp.preprocess_and_interpolate_ev(None, test_values, frequency, values,
221228
method='extrapolate_constant')
222229
)
223230

224231
# test error raising
225232
with self.assertRaises(ValueError):
226-
preprocess_and_interpolate_ev(test_frequency, test_values, frequency, values)
233+
u_interp.preprocess_and_interpolate_ev(test_frequency, test_values, frequency, values)
227234
with self.assertRaises(ValueError):
228-
preprocess_and_interpolate_ev(None, None, frequency, values)
235+
u_interp.preprocess_and_interpolate_ev(None, None, frequency, values)
229236

230237
# Execute Tests
231238
if __name__ == "__main__":

0 commit comments

Comments
 (0)