Skip to content

Commit d6aeda2

Browse files
authored
Refactors Quantity to have a standard error property (#215)
1 parent 6a3e303 commit d6aeda2

2 files changed

Lines changed: 29 additions & 33 deletions

File tree

sasdata/quantities/quantity.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,9 +1531,9 @@ def apply_operation(
15311531
operation(*[history.operation_tree for history in histories], **extra_parameters), references
15321532
)
15331533

1534-
def has_variance(self):
1534+
def has_error(self):
15351535
for key in self.references:
1536-
if self.references[key].has_variance:
1536+
if self.references[key].has_error:
15371537
return True
15381538

15391539
return False
@@ -1570,23 +1570,19 @@ def __init__(
15701570
self.hash_value = -1
15711571
""" Hash based on value and uncertainty for data, -1 if it is a derived hash value """
15721572

1573-
self._variance = None
1574-
""" Contains the variance if it is data driven """
1573+
self._standard_error = standard_error
1574+
""" Contains the standard error if it is data driven """
15751575

15761576
if standard_error is None:
15771577
self.hash_value = hash_data_via_numpy(hash_seed, value)
15781578
else:
1579-
self._variance = standard_error**2
15801579
self.hash_value = hash_data_via_numpy(hash_seed, value, standard_error)
15811580

15821581
self.history = QuantityHistory.variable(self)
15831582

15841583
self._id_header = id_header
15851584
self.name = name
15861585

1587-
self._id_header = id_header
1588-
self.name = name
1589-
15901586
# TODO: Adding this method as a temporary measure but we need a single
15911587
# method that does this.
15921588
def with_standard_error(self, standard_error: "Quantity"):
@@ -1604,17 +1600,21 @@ def with_standard_error(self, standard_error: "Quantity"):
16041600
)
16051601

16061602
@property
1607-
def has_variance(self):
1608-
return self._variance is not None
1603+
def has_error(self):
1604+
return self._standard_error is not None
16091605

16101606
@property
1611-
def variance(self) -> "Quantity":
1612-
"""Get the variance of this object"""
1613-
if self._variance is None:
1614-
return Quantity(np.zeros_like(self.value), self.units**2, name=self.name, id_header=self._id_header)
1607+
def standard_error(self) -> "Quantity":
1608+
"""Get the standard error of this object"""
1609+
if self.has_error:
1610+
return Quantity(self._standard_error, self.units, name=self.name, id_header=self._id_header)
16151611
else:
1616-
return Quantity(self._variance, self.units**2)
1612+
return Quantity(np.zeros_like(self.value), self.units, name=self.name, id_header=self._id_header)
16171613

1614+
@property
1615+
def variance(self) -> "Quantity":
1616+
"""Get the variance of this object"""
1617+
return self.standard_error**2
16181618

16191619
@property
16201620
def unique_id(self) -> str:
@@ -1636,9 +1636,6 @@ def _base62_hash(self) -> str:
16361636
current_hash = (current_hash - digit) // 62
16371637
return hashed
16381638

1639-
def standard_deviation(self) -> "Quantity":
1640-
return self.variance**0.5
1641-
16421639
def in_units_of(self, units: Unit) -> QuantityType:
16431640
"""Get this quantity in other units"""
16441641
if self.units.equivalent(units):
@@ -1669,16 +1666,15 @@ def in_si(self):
16691666
return self.in_units_of(si_units)
16701667

16711668
def in_units_of_with_standard_error(self, units):
1672-
variance = self.variance
1673-
units_squared = units**2
1669+
standard_error = self.standard_error
16741670

1675-
if variance.units.equivalent(units_squared):
1676-
return self.in_units_of(units), np.sqrt(self.variance.in_units_of(units_squared))
1671+
if standard_error.units.equivalent(units):
1672+
return self.in_units_of(units), self.standard_error.in_units_of(units)
16771673
else:
1678-
raise UnitError(f"Target units ({units}) not compatible with existing units ({variance.units}).")
1674+
raise UnitError(f"Target units ({units}) not compatible with existing units ({standard_error.units}).")
16791675

16801676
def in_si_with_standard_error(self):
1681-
if self.has_variance:
1677+
if self.has_error:
16821678
return self.in_units_of_with_standard_error(self.units.si_equivalent())
16831679
else:
16841680
return self.in_si(), None
@@ -1837,7 +1833,7 @@ def _array_repr_format(arr: np.ndarray):
18371833
def __repr__(self):
18381834
if isinstance(self.units, NamedUnit):
18391835
value = self.value
1840-
error = self.standard_deviation().in_units_of(self.units)
1836+
error = self.standard_error.in_units_of(self.units)
18411837
unit_string = self.units.symbol
18421838

18431839
else:
@@ -1848,12 +1844,12 @@ def __repr__(self):
18481844
# Get the array in short form
18491845
numeric_string = self._array_repr_format(value)
18501846

1851-
if self.has_variance:
1847+
if self.has_error:
18521848
numeric_string += " ± " + self._array_repr_format(error)
18531849

18541850
else:
18551851
numeric_string = f"{value}"
1856-
if self.has_variance:
1852+
if self.has_error:
18571853
numeric_string += f" ± {error}"
18581854

18591855
return numeric_string + " " + unit_string
@@ -1912,19 +1908,19 @@ def __init__(self, value: QuantityType, units: Unit, history: QuantityHistory):
19121908

19131909
self.history = history
19141910
self._variance_cache = None
1915-
self._has_variance = history.has_variance()
1911+
self._has_error = history.has_error()
19161912

19171913
def to_units_of(self, new_units: Unit) -> "Quantity[QuantityType]":
19181914
# TODO: Lots of tests needed for this
19191915
return DerivedQuantity(value=self.in_units_of(new_units), units=new_units, history=self.history)
19201916

19211917
@property
1922-
def has_variance(self):
1923-
return self._has_variance
1918+
def has_error(self):
1919+
return self._has_error
19241920

19251921
@property
1926-
def variance(self) -> Quantity:
1922+
def standard_error(self) -> Quantity:
19271923
if self._variance_cache is None:
19281924
self._variance_cache = self.history.variance_propagate(self.units)
19291925

1930-
return self._variance_cache
1926+
return self._variance_cache**0.5

test/sasdataloader/utest_sasdataload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ def test_load_file(test_case: BaseTestCase):
393393
for index, values in expected.items():
394394
for column, expected_value in values.items():
395395
if is_uncertainty(column):
396-
assert loaded._data_contents[column[1::]]._variance[index] == pytest.approx(expected_value**2)
396+
assert loaded._data_contents[column[1::]]._standard_error[index] == pytest.approx(expected_value)
397397
else:
398398
assert loaded._data_contents[column].value[index] == pytest.approx(expected_value)
399399

0 commit comments

Comments
 (0)