def align_intersect_timeseries(base, target): """ Align target time series to the base one. It assumes a regular time series for the base. """ from vtools.functions.api import interpolate_ts if base.interval < target.interval: raise ValueError( "Untested with coarser target and windowing may be wrong") window_common = range_intersect(base, target) start = align(window_common[0], base.interval, 1) end = align(window_common[1], base.interval, -1) base_windowed = base.window(start, end) target_aligned = interpolate_ts(target, base_windowed.times, method=LINEAR) props = copy.deepcopy(target.props) target_aligned._props = props return base_windowed, target_aligned
def calculate_metrics(tss, lags, interpolate_method='linear'): """ Calculate metrics. The first time series is the base, and other are controls. The root mean square error is calculated without a lag correction. and the shift with the maximum autocorrelation is a lag. The other metrics, Bias, NSE, and R are calculated after lag correction on controls, which are the second and latter time series. """ assert len(tss) > 1 ts_base = tss[0] metrics = [] tss_for_scatter = None for i in range(len(tss) - 1): ts_target = tss[i + 1] if ts_base is None or ts_target is None: metrics.append(None) continue window_common = get_common_window((ts_base, ts_target)) if window_common is None: metrics.append(None) continue ts1 = ts_base.window(*window_common) ts2 = ts_target.window(*window_common) if np.all(np.isnan(ts1.data)) or np.all(np.isnan(ts2.data)): metrics.append(None) continue if ts1.start != ts2.start or ts1.interval != ts2.interval: ts2_interpolated = interpolate_ts(ts_target, ts1, method=interpolate_method) rmse_ = rmse(ts1, ts2_interpolated) else: ts2_interpolated = ts2 rmse_ = rmse(ts1, ts2) # Items with the lag correction if lags[i] is None: bias = None nse = None corr = None else: if lags[i] != timedelta():
def calculate_lag(a, b, max_shift, period=None, resolution=time_interval(minutes=1), interpolate_method=None): """ Calculate lag of the second time series b, that maximizes the cross-correlation with a. Parameters ---------- a,b: vtools.data.timeseries.Timeseries Two time series to compare. The time extent of b must be the same or a superset of that of a. max_shift: interval Maximum pos/negative time shift to consider in cross-correlation (ie, from -max_shift to +max_shift) period: interval, optional Period that will be used to further clip the time_window of analysis to fit a periodicity. interpolate_method: str, optional Interpolate method to generate a time series with a lag-calculation interpolation Returns ------- lag : datetime.timedelta lag """ # Get the available range from the first time series a_windowed_by_b = a.window(b.start, b.end) time_window = (a_windowed_by_b.start, a_windowed_by_b.end) if (time_window[1] - time_window[0]).total_seconds() <= 0.: raise ValueError('No available time series in the given time_window') # Calculate actual time range to use start = time_window[0] + max_shift if period is not None: n_periods = np.floor( ((time_window[1] - max_shift) - start).total_seconds() / period.total_seconds()) if n_periods <= 0.: raise ValueError( "The time series is too short to cover one period.") end = start + time_interval(seconds=n_periods * period.total_seconds()) else: end = time_window[1] - max_shift if (end - start).total_seconds() < 0.: raise ValueError("The time series is too short.") # This is actual time series to calculate lag a_part = a.window(start, end) start = a_part.start end = a_part.end a_part_masked = np.ma.masked_invalid(a_part.data, np.nan) # Interpolate the second vector factor = a.interval.total_seconds() / resolution.total_seconds() if not factor - np.floor(factor) < 1.e-6: raise ValueError( 'The interval of the time series is not integer multiple of the resolution.' ) else: factor = int(np.floor(factor)) new_n = np.ceil((end - start + 2 * max_shift).total_seconds() / resolution.total_seconds()) + 1 max_shift_tick = int(max_shift.total_seconds() / resolution.total_seconds()) length = 2 * max_shift_tick + 1 n = len(a_part) if interpolate_method is None: interpolate_method = LINEAR b_interpolated = interpolate_ts(b, time_sequence(a_part.start - max_shift, resolution, new_n), method=interpolate_method) def unnorm_xcor(lag): lag_int = int(lag) b_part = b_interpolated.data[lag_int:lag_int + factor * n - 1:factor] return -np.ma.inner(a_part_masked, b_part) index = np.arange(-max_shift_tick, max_shift_tick + 1) brent = True if brent is True: from scipy.optimize import minimize_scalar res = minimize_scalar(unnorm_xcor, method='bounded', bounds=(0, length), options={'xatol': 0.5}) v0 = index[int(np.floor(res.x))] * resolution.total_seconds() else: re = np.empty(length) for i in range(length): re[i] = unnorm_xcor(i) v0 = index[np.argmax(-re)] * resolution.total_seconds() return time_interval(seconds=v0)
if lags[i] is None: bias = None nse = None corr = None else: if lags[i] != timedelta(): <<<<<<< HEAD ts_target_shifted = shift(ts_target, -lags[i]) ======= ts_target_shifted = shift(ts_target,-lags[i]) >>>>>>> revisions window_common = get_common_window((ts_base, ts_target_shifted)) ts1 = ts_base.window(*window_common) ts2 = ts_target_shifted.window(*window_common) if ts1.start != ts2.start or ts1.interval != ts2.interval: ts2_interpolated = interpolate_ts(ts_target_shifted, ts1, method=interpolate_method) else: ts2_interpolated = ts2 bias = median_error(ts2_interpolated, ts1) nse = skill_score(ts2_interpolated, ts1) corr = corr_coefficient(ts2_interpolated, ts1) metrics.append({'rmse': rmse_, 'bias': bias, 'nse': nse, 'corr': corr, 'lag': lags[i]}) if i == 0 and lags[0] is not None: tss_for_scatter = (ts1, ts2_interpolated) return metrics, tss_for_scatter def set_figure(): """ Set a Matplotlib figure and return it """