Coverage for python/lsst/pipe/tasks/statistic.py: 90%

55 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-09 03:58 -0700

1# This file is part of pipe_tasks. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22__all__ = ['Statistic', 'Count', 'Median', 'Percentile', 'StandardDeviation', 'SigmaIQR', 'SigmaMAD', 

23 'Statistics'] 

24 

25from abc import ABCMeta, abstractmethod 

26from astropy.stats import mad_std 

27from dataclasses import dataclass 

28import numpy as np 

29from scipy.stats import iqr 

30 

31 

32class Statistic(metaclass=ABCMeta): 

33 """Compute a statistic from a list of values. 

34 """ 

35 # TODO: Make this a property after upgrade to Python 3.9 

36 @classmethod 

37 @abstractmethod 

38 def name(cls): 

39 pass 

40 

41 @abstractmethod 

42 def value(self, values): 

43 """Return the value of the statistic given a set of values. 

44 

45 Parameters 

46 ---------- 

47 values : `Collection` [`float`] 

48 A set of values to compute the statistic for. 

49 Returns 

50 ------- 

51 statistic : `float` 

52 The value of the statistic. 

53 """ 

54 pass 

55 

56 

57class Count(Statistic): 

58 @classmethod 

59 def name(cls): 

60 return "count" 

61 

62 """The median of a set of values.""" 

63 def value(self, values): 

64 return len(values) 

65 

66 

67class Median(Statistic): 

68 @classmethod 

69 def name(cls): 

70 return "median" 

71 

72 """The median of a set of values.""" 

73 def value(self, values): 

74 return np.median(values) 

75 

76 

77@dataclass(frozen=True) 

78class Percentile(Statistic): 

79 """An arbitrary percentile. 

80 

81 Parameters 

82 ---------- 

83 percentile : `float` 

84 A valid percentile (0 <= p <= 100). 

85 """ 

86 percentile: float 

87 

88 @classmethod 

89 def name(cls): 

90 return "percentile" 

91 

92 def value(self, values): 

93 return np.percentile(values, self.percentile) 

94 

95 

96class StandardDeviation(Statistic): 

97 """The standard deviation (sigma).""" 

98 @classmethod 

99 def name(cls): 

100 return "std" 

101 

102 def value(self, values): 

103 return np.std(values) 

104 

105 

106class SigmaIQR(Statistic): 

107 """The re-scaled inter-quartile range (sigma equivalent).""" 

108 @classmethod 

109 def name(cls): 

110 return "sigma_iqr" 

111 

112 def value(self, values): 

113 return iqr(values, scale='normal') 

114 

115 

116class SigmaMAD(Statistic): 

117 """The re-scaled median absolute deviation (sigma equivalent).""" 

118 @classmethod 

119 def name(cls): 

120 return "sigma_mad" 

121 

122 def value(self, values): 

123 return mad_std(values) 

124 

125 

126Statistics = { 

127 stat.name(): stat 

128 for stat in (Count, Median, Percentile, StandardDeviation, SigmaIQR, SigmaMAD) 

129}