Coverage for src/scores/stats/statistical_tests/acovf.py: 100%

1"""

2 Estimate autocovariances

3

4 Barebones reimplementation of the `acovf` from `statsmodels.api.tsa.acovf`,

5 for use only with `scores.stats.test.diebold_mariano`

6

7 Package: https://www.statsmodels.org/devel/

8

9 Code reference: https://github.com/statsmodels/statsmodels/blob/main/statsmodels/tsa/stattools.py

10

11 Notes:

12 All type checking and other features have been removed, as they aren't needed for the

13 `diebold_mariano` function.

14

15 Why:

16 Reduce dependant packages

17

18## Source License

19

20 Copyright (C) 2006, Jonathan E. Taylor

21 All rights reserved.

22

23 Copyright (c) 2006-2008 Scipy Developers.

24 All rights reserved.

25

26 Copyright (c) 2009-2018 statsmodels Developers.

27 All rights reserved.

28

29

30 Redistribution and use in source and binary forms, with or without

31 modification, are permitted provided that the following conditions are met:

32

33 a. Redistributions of source code must retain the above copyright notice,

34 this list of conditions and the following disclaimer.

35 b. Redistributions in binary form must reproduce the above copyright

36 notice, this list of conditions and the following disclaimer in the

37 documentation and/or other materials provided with the distribution.

38 c. Neither the name of statsmodels nor the names of its contributors

39 may be used to endorse or promote products derived from this software

40 without specific prior written permission.

41

42

43 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

44 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

45 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

46 ARE DISCLAIMED. IN NO EVENT SHALL STATSMODELS OR CONTRIBUTORS BE LIABLE FOR

47 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

48 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

49 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

50 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

51 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

52 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH

53 DAMAGE.

54"""

55

56 import numpy as np

57

58 __all__ = ["acovf"]

59

60

61 def _next_regular(target):

62 """

63 Find the next regular number greater than or equal to target.

64 Regular numbers are composites of the prime factors 2, 3, and 5.

65 Also known as 5-smooth numbers or Hamming numbers, these are the optimal

66 size for inputs to FFTPACK.

67

68 Target must be a positive integer.

69 """

70 if target <= 6:

71 return target

72

73 # Quickly check if it's already a power of 2

74 if not (target & (target - 1)):

75 return target

76

77 match = float("inf") # Anything found will be smaller

78 p5 = 1

79 while p5 < target:

80 p35 = p5

81 while p35 < target:

82 # Ceiling integer division, avoiding conversion to float

83 # (quotient = ceil(target / p35))

84 quotient = -(-target // p35)

85 # Quickly find next power of 2 >= quotient

86 p2 = 2 ** ((quotient - 1).bit_length())

87

88 N = p2 * p35

89 if N == target:

90 return N

91 elif N < match:

92 match = N

93 p35 *= 3

94 if p35 == target:

95 return p35

96 if p35 < match:

97 match = p35

98 p5 *= 5

99 if p5 == target:

100 return p5

101 if p5 < match:

102 match = p5

103 return match

104

105

106 def acovf(x):

107 """

108 Estimate autocovariances.

109

110 Args:

111 x (array_like):

112 Time series data. Must be 1d.

113

114 Returns:

115 (np.ndarray):

116 The estimated autocovariances.

117

118 References:

119 [1] Parzen, E., 1963. On spectral analysis with missing observations

120 and amplitude modulation. Sankhya: The Indian Journal of

121 Statistics, Series A, pp.383-392.

122 """

123

124 xo = x - x.mean()

125

126 n = len(x)

127

128 d = n * np.ones(2 * n - 1)

129

130 nobs = len(xo)

131 n = _next_regular(2 * nobs + 1)

132 Frf = np.fft.fft(xo, n=n)

133 acov = np.fft.ifft(Frf * np.conjugate(Frf))[:nobs] / d[nobs - 1 :]

134 acov = acov.real

135

136 return acov