Coverage for python/lsst/analysis/tools/actions/scalar/scalarActions.py: 61%
69 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-20 09:55 +0000
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-20 09:55 +0000
1from __future__ import annotations
3import operator
4from typing import cast
6import numpy as np
7import scipy.stats as sps
8from lsst.pex.config import ChoiceField, Field
10from ...interfaces import KeyedData, KeyedDataSchema, Scalar, ScalarAction, Vector
13class MedianAction(ScalarAction):
14 vectorKey = Field[str]("Key of Vector to median")
16 def getInputSchema(self) -> KeyedDataSchema:
17 return ((self.vectorKey, Vector),)
19 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
20 mask = self.getMask(**kwargs)
21 return cast(Scalar, float(np.nanmedian(cast(Vector, data[self.vectorKey.format(**kwargs)])[mask])))
24class MeanAction(ScalarAction):
25 vectorKey = Field[str]("Key of Vector from which to calculate mean")
27 def getInputSchema(self) -> KeyedDataSchema:
28 return ((self.vectorKey, Vector),)
30 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
31 mask = self.getMask(**kwargs)
32 return cast(Scalar, float(np.nanmean(cast(Vector, data[self.vectorKey.format(**kwargs)])[mask])))
35class StdevAction(ScalarAction):
36 vectorKey = Field[str]("Key of Vector from which to calculate std deviation")
38 def getInputSchema(self) -> KeyedDataSchema:
39 return ((self.vectorKey, Vector),)
41 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
42 mask = self.getMask(**kwargs)
43 return cast(Scalar, float(np.nanstd(cast(Vector, data[self.vectorKey.format(**kwargs)])[mask])))
46class SigmaMadAction(ScalarAction):
47 vectorKey = Field[str]("Key of Vector to median")
49 def getInputSchema(self) -> KeyedDataSchema:
50 return ((self.vectorKey, Vector),)
52 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
53 mask = self.getMask(**kwargs)
54 return cast(
55 Scalar,
56 float(
57 sps.median_abs_deviation(
58 data[self.vectorKey.format(**kwargs)][mask], # type: ignore
59 scale="normal",
60 nan_policy="omit",
61 )
62 ),
63 )
66class CountAction(ScalarAction):
67 vectorKey = Field[str]("Key of Vector to median")
69 def getInputSchema(self) -> KeyedDataSchema:
70 return ((self.vectorKey, Vector),)
72 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
73 mask = self.getMask(**kwargs)
74 arr = cast(Vector, data[self.vectorKey.format(**kwargs)])[mask]
75 arr = arr[~np.isnan(arr)]
76 return cast(Scalar, len(arr))
79class ApproxFloor(ScalarAction):
80 vectorKey = Field[str](doc="Key for the vector to perform action on", optional=False)
82 def getInputSchema(self) -> KeyedDataSchema:
83 return ((self.vectorKey, Vector),)
85 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
86 mask = self.getMask(**kwargs)
87 value = np.sort(data[self.vectorKey.format(**kwargs)][mask]) # type: ignore
88 x = len(value) // 10
89 return cast(Scalar, float(np.nanmedian(value[-x:])))
92class FracThreshold(ScalarAction):
93 """Compute the fraction of a distribution that is above or below a
94 specified threshold. The operator is specified as a string, for example,
95 "lt", "le", "ge", "gt" for the mathematical operations <, <=, >=, >. To
96 compute the fraction of elements with values less than a given threshold,
97 use op="le".
98 """
100 op = ChoiceField[str](
101 doc="Operator name string.",
102 allowed={
103 "lt": "less than threshold",
104 "le": "less than or equal to threshold",
105 "ge": "greater than or equal to threshold",
106 "gt": "greater than threshold",
107 },
108 )
109 threshold = Field[float](doc="Threshold to apply.")
110 vectorKey = Field[str](doc="Name of column")
111 percent = Field[bool](doc="Express result as percentage", default=False)
113 def getInputSchema(self, **kwargs) -> KeyedDataSchema:
114 return ((self.vectorKey.format(**kwargs), Vector),)
116 def __call__(self, data: KeyedData, **kwargs) -> Scalar:
117 mask = self.getMask(**kwargs)
118 values = data[self.vectorKey.format(**kwargs)]
119 values = values[mask] # type: ignore
120 values = values[np.logical_not(np.isnan(values))]
121 result = cast(
122 Scalar,
123 float(np.sum(getattr(operator, self.op)(values, self.threshold)) / len(values)), # type: ignore
124 )
125 if self.percent:
126 return 100.0 * result
127 else:
128 return result