microdf-python 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microdf-python
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Weighted pandas DataFrames and Series for survey microdata
5
5
  Author-email: Max Ghenis <max@policyengine.org>
6
6
  License: MIT
@@ -310,8 +310,9 @@ class MicroDataFrame(pd.DataFrame):
310
310
 
311
311
  if isinstance(weights, str):
312
312
  self.weights_col = weights
313
+ # Keep stored weights independent from edits to the source column.
313
314
  self.weights = pd.Series(
314
- np.asarray(self[weights]),
315
+ np.array(self[weights], copy=True),
315
316
  index=self.index,
316
317
  dtype=float,
317
318
  )
@@ -362,9 +363,9 @@ class MicroDataFrame(pd.DataFrame):
362
363
  if preserve_old and self.weights_col is not None:
363
364
  self["old_" + self.weights_col] = self.weights
364
365
 
365
- self.weights = np.array(self[column])
366
- self.weights_col = column
367
- self._link_all_weights()
366
+ # Delegate to set_weights: it validates length and builds an
367
+ # index-aligned float Series rather than a bare ndarray.
368
+ self.set_weights(column)
368
369
 
369
370
  def nullify_weights(self) -> None:
370
371
  """Set all weights to 1, effectively making the DataFrame unweighted.
@@ -372,8 +373,10 @@ class MicroDataFrame(pd.DataFrame):
372
373
  This is useful for comparing weighted and unweighted statistics or when
373
374
  you want to temporarily ignore weights.
374
375
  """
375
- self.weights = np.ones(len(self))
376
- self._link_all_weights()
376
+ # Route through set_weights so self.weights stays an index-aligned
377
+ # float Series. Assigning a bare ndarray here broke every caller
378
+ # that treats it as a Series (equals(), reindex() in __getitem__).
379
+ self.set_weights(np.ones(len(self)))
377
380
 
378
381
  def __getitem__(
379
382
  self, key: Union[str, List]
@@ -157,7 +157,11 @@ class MicroSeries(pd.Series):
157
157
  This is useful for comparing weighted and unweighted statistics or when
158
158
  you want to temporarily ignore weights.
159
159
  """
160
- self.weights = pd.Series(np.ones(len(self)), dtype=float)
160
+ # Index the ones against self.index: weighted ops are label-aligned
161
+ # (self.multiply(self.weights) in .sum()/.weight()), so a default
162
+ # RangeIndex here silently produces all-NaN and collapses every
163
+ # aggregation to 0 whenever the caller uses a non-default index.
164
+ self.weights = pd.Series(np.ones(len(self)), index=self.index, dtype=float)
161
165
 
162
166
  @vector_function
163
167
  def weight(self) -> pd.Series:
@@ -0,0 +1,61 @@
1
+ import warnings
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import pytest
6
+
7
+ import microdf as mdf
8
+
9
+
10
+ def test_weights_stay_a_series_after_nullify():
11
+ """nullify_weights must leave weights as an index-aligned Series."""
12
+ df = mdf.MicroDataFrame(pd.DataFrame({"x": [1, 2, 3]}), weights=[4, 5, 6])
13
+ df.nullify_weights()
14
+ assert isinstance(df.weights, pd.Series)
15
+ assert list(df.weights.index) == list(df.index)
16
+ assert df.equals(df)
17
+ assert df.sum()["x"] == 6
18
+
19
+
20
+ def test_weights_stay_a_series_after_set_weight_col():
21
+ """The deprecated set_weight_col must also produce a Series."""
22
+ df = mdf.MicroDataFrame(pd.DataFrame({"x": [1, 2, 3], "w": [1.0, 2.0, 3.0]}))
23
+ with warnings.catch_warnings():
24
+ warnings.simplefilter("ignore", DeprecationWarning)
25
+ df.set_weight_col("w")
26
+ assert isinstance(df.weights, pd.Series)
27
+ assert df.weights_col == "w"
28
+ assert df.equals(df)
29
+ assert df.sum()["x"] == 14
30
+
31
+
32
+ @pytest.mark.parametrize("dtype", ["int64", "float64"])
33
+ def test_weight_column_edits_do_not_change_stored_weights(dtype):
34
+ """Selecting a weight column takes a copy of its current values."""
35
+ df = mdf.MicroDataFrame(
36
+ {"x": [10, 20], "w": np.array([1, 2], dtype=dtype)},
37
+ index=[10, 20],
38
+ )
39
+ with pytest.warns(DeprecationWarning):
40
+ df.set_weight_col("w")
41
+
42
+ df.loc[10, "w"] = 100
43
+
44
+ np.testing.assert_array_equal(df.weights, [1, 2])
45
+ assert df.sum()["x"] == 10 * 1 + 20 * 2
46
+
47
+
48
+ @pytest.mark.parametrize("dtype", ["int64", "float64"])
49
+ def test_stored_weight_edits_do_not_change_weight_column(dtype):
50
+ """Changing stored weights leaves the source column values intact."""
51
+ df = mdf.MicroDataFrame(
52
+ {"x": [10, 20], "w": np.array([1, 2], dtype=dtype)},
53
+ index=[10, 20],
54
+ )
55
+ with pytest.warns(DeprecationWarning):
56
+ df.set_weight_col("w")
57
+
58
+ df.weights.iloc[0] = 100
59
+
60
+ np.testing.assert_array_equal(df["w"], [1, 2])
61
+ assert df.sum()["x"] == 10 * 100 + 20 * 2
@@ -0,0 +1,10 @@
1
+ import microdf as mdf
2
+
3
+
4
+ def test_nullify_weights_non_default_index():
5
+ """nullify_weights must align to the index, not a fresh RangeIndex."""
6
+ s = mdf.MicroSeries([1, 2, 3], index=[10, 11, 12], weights=[1, 2, 3])
7
+ s.nullify_weights()
8
+ assert s.sum() == 6
9
+ assert s.mean() == 2
10
+ assert list(s.weights.index) == [10, 11, 12]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microdf-python
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Weighted pandas DataFrames and Series for survey microdata
5
5
  Author-email: Max Ghenis <max@policyengine.org>
6
6
  License: MIT
@@ -5,7 +5,9 @@ microdf/__init__.py
5
5
  microdf/microdataframe.py
6
6
  microdf/microseries.py
7
7
  microdf/tests/conftest.py
8
+ microdf/tests/test_dataframe_weight_storage.py
8
9
  microdf/tests/test_microseries_dataframe.py
10
+ microdf/tests/test_nullify_weights_index.py
9
11
  microdf/tests/test_pandas3_compatibility.py
10
12
  microdf_python.egg-info/PKG-INFO
11
13
  microdf_python.egg-info/SOURCES.txt
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "microdf-python"
7
- version = "1.3.2"
7
+ version = "1.3.4"
8
8
  description = "Weighted pandas DataFrames and Series for survey microdata"
9
9
  readme = "README.md"
10
10
  authors = [
File without changes
File without changes
File without changes