microdf-python 1.1.1__tar.gz → 1.1.2__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.
- {microdf_python-1.1.1/microdf_python.egg-info → microdf_python-1.1.2}/PKG-INFO +1 -1
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf/microdataframe.py +8 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf/microseries.py +21 -2
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf/tests/test_microseries_dataframe.py +30 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2/microdf_python.egg-info}/PKG-INFO +1 -1
- {microdf_python-1.1.1 → microdf_python-1.1.2}/pyproject.toml +1 -1
- {microdf_python-1.1.1 → microdf_python-1.1.2}/LICENSE +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/README.md +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf/__init__.py +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf/tests/conftest.py +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf_python.egg-info/SOURCES.txt +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf_python.egg-info/dependency_links.txt +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf_python.egg-info/requires.txt +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/microdf_python.egg-info/top_level.txt +0 -0
- {microdf_python-1.1.1 → microdf_python-1.1.2}/setup.cfg +0 -0
|
@@ -44,6 +44,10 @@ class _MicroLocIndexer:
|
|
|
44
44
|
self._parent_loc[key] = value
|
|
45
45
|
self._mdf._link_all_weights()
|
|
46
46
|
|
|
47
|
+
def __getattr__(self, name):
|
|
48
|
+
"""Delegate unknown attributes to the parent loc indexer."""
|
|
49
|
+
return getattr(self._parent_loc, name)
|
|
50
|
+
|
|
47
51
|
|
|
48
52
|
class _MicroILocIndexer:
|
|
49
53
|
"""Custom iloc indexer that returns MicroDataFrame with proper weights."""
|
|
@@ -85,6 +89,10 @@ class _MicroILocIndexer:
|
|
|
85
89
|
self._parent_iloc[key] = value
|
|
86
90
|
self._mdf._link_all_weights()
|
|
87
91
|
|
|
92
|
+
def __getattr__(self, name):
|
|
93
|
+
"""Delegate unknown attributes to the parent iloc indexer."""
|
|
94
|
+
return getattr(self._parent_iloc, name)
|
|
95
|
+
|
|
88
96
|
|
|
89
97
|
class MicroDataFrame(pd.DataFrame):
|
|
90
98
|
def __init__(self, *args, weights=None, **kwargs):
|
|
@@ -101,13 +101,32 @@ class MicroSeries(pd.Series):
|
|
|
101
101
|
return self.weights.sum()
|
|
102
102
|
|
|
103
103
|
@scalar_function
|
|
104
|
-
def mean(self) -> float:
|
|
104
|
+
def mean(self, skipna: bool = True) -> float:
|
|
105
105
|
"""Calculates the weighted mean of the MicroSeries.
|
|
106
106
|
|
|
107
|
+
:param skipna: Exclude NA/null values. If True (default), NaN values
|
|
108
|
+
are excluded. If False, returns NaN if any value is NaN.
|
|
109
|
+
:type skipna: bool
|
|
107
110
|
:returns: The weighted mean.
|
|
108
111
|
:rtype: float
|
|
109
112
|
"""
|
|
110
|
-
|
|
113
|
+
values = self.values
|
|
114
|
+
weights = self.weights
|
|
115
|
+
|
|
116
|
+
if skipna:
|
|
117
|
+
# Create mask for non-NaN values
|
|
118
|
+
mask = ~pd.isna(values)
|
|
119
|
+
if not mask.any():
|
|
120
|
+
# All values are NaN
|
|
121
|
+
return np.nan
|
|
122
|
+
values = values[mask]
|
|
123
|
+
weights = weights[mask]
|
|
124
|
+
|
|
125
|
+
# If skipna=False and there are any NaN values, return NaN
|
|
126
|
+
if not skipna and pd.isna(values).any():
|
|
127
|
+
return np.nan
|
|
128
|
+
|
|
129
|
+
return np.average(values, weights=weights)
|
|
111
130
|
|
|
112
131
|
def quantile(self, q: np.array) -> pd.Series:
|
|
113
132
|
"""Calculates weighted quantiles of the MicroSeries.
|
|
@@ -94,6 +94,36 @@ def test_mean() -> None:
|
|
|
94
94
|
pass
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
def test_mean_skipna() -> None:
|
|
98
|
+
# Test skipna=True (default) - should skip NaN values
|
|
99
|
+
arr = np.array([3.0, np.nan, 2.0])
|
|
100
|
+
w = np.array([4.0, 1.0, 1.0])
|
|
101
|
+
series = mdf.MicroSeries(arr, weights=w)
|
|
102
|
+
|
|
103
|
+
# skipna=True should exclude NaN and its weight
|
|
104
|
+
expected = np.average([3.0, 2.0], weights=[4.0, 1.0])
|
|
105
|
+
assert series.mean(skipna=True) == expected
|
|
106
|
+
assert series.mean() == expected # Default should be skipna=True
|
|
107
|
+
|
|
108
|
+
# Test skipna=False - should return NaN if any value is NaN
|
|
109
|
+
assert np.isnan(series.mean(skipna=False))
|
|
110
|
+
|
|
111
|
+
# Test with all NaN values
|
|
112
|
+
arr_all_nan = np.array([np.nan, np.nan, np.nan])
|
|
113
|
+
w_all_nan = np.array([1.0, 2.0, 3.0])
|
|
114
|
+
series_all_nan = mdf.MicroSeries(arr_all_nan, weights=w_all_nan)
|
|
115
|
+
assert np.isnan(series_all_nan.mean(skipna=True))
|
|
116
|
+
assert np.isnan(series_all_nan.mean(skipna=False))
|
|
117
|
+
|
|
118
|
+
# Test with no NaN values - skipna should not affect result
|
|
119
|
+
arr_no_nan = np.array([3.0, 5.0, 2.0])
|
|
120
|
+
w_no_nan = np.array([4.0, 1.0, 1.0])
|
|
121
|
+
series_no_nan = mdf.MicroSeries(arr_no_nan, weights=w_no_nan)
|
|
122
|
+
expected_no_nan = np.average(arr_no_nan, weights=w_no_nan)
|
|
123
|
+
assert series_no_nan.mean(skipna=True) == expected_no_nan
|
|
124
|
+
assert series_no_nan.mean(skipna=False) == expected_no_nan
|
|
125
|
+
|
|
126
|
+
|
|
97
127
|
def test_poverty_count() -> None:
|
|
98
128
|
arr = np.array([10000, 20000, 50000])
|
|
99
129
|
w = np.array([1123, 1144, 2211])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|