betaMixPy 0.2.1__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: betaMixPy
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A Python package to find strong correlations among P variables, each with N observations.
5
5
  Home-page: https://pypi.org/project/betaMixPy/
6
6
  Author: Haim Bar
@@ -152,6 +152,8 @@ Two strategies:
152
152
 
153
153
  See [NEWS.md](NEWS.md) for the full changelog. Highlights:
154
154
 
155
+ - **0.2.2**: `getAdjMat(nodes=...)` uses the same inclusive threshold;
156
+ constant columns never get edges
155
157
  - **0.2.1**: `getAdjMat` edge count now matches `betaMix()`; fixed a
156
158
  `plotFittedBetaMix` crash; unused dependencies removed; full test suite
157
159
 
@@ -126,6 +126,8 @@ Two strategies:
126
126
 
127
127
  See [NEWS.md](NEWS.md) for the full changelog. Highlights:
128
128
 
129
+ - **0.2.2**: `getAdjMat(nodes=...)` uses the same inclusive threshold;
130
+ constant columns never get edges
129
131
  - **0.2.1**: `getAdjMat` edge count now matches `betaMix()`; fixed a
130
132
  `plotFittedBetaMix` crash; unused dependencies removed; full test suite
131
133
 
@@ -0,0 +1,3 @@
1
+ __version__ = "0.2.2" # single source of truth; setup.py reads this line
2
+
3
+ from .betaMixPy import *
@@ -118,13 +118,16 @@ def betaMix(M, tol=1e-4, calcAcc=1e-9, ppr=0.05, maxalpha=1e-4,
118
118
  if msg:
119
119
  print("Generating the z_ij statistics...")
120
120
 
121
- # Correlation matrix P×P (rowvar=False: each column is a variable)
122
- if method == "spearman":
123
- from scipy.stats import rankdata
124
- ranked = np.apply_along_axis(rankdata, 0, M)
125
- corM = np.corrcoef(ranked, rowvar=False)
126
- else:
127
- corM = np.corrcoef(M, rowvar=False)
121
+ # Correlation matrix P×P (rowvar=False: each column is a variable).
122
+ # Constant columns divide by zero here; the resulting NaNs are reported
123
+ # by the warnings above/below, so numpy's own RuntimeWarning is suppressed.
124
+ with np.errstate(divide="ignore", invalid="ignore"):
125
+ if method == "spearman":
126
+ from scipy.stats import rankdata
127
+ ranked = np.apply_along_axis(rankdata, 0, M)
128
+ corM = np.corrcoef(ranked, rowvar=False)
129
+ else:
130
+ corM = np.corrcoef(M, rowvar=False)
128
131
 
129
132
  if np.any(np.isnan(corM)):
130
133
  n_nans = int(np.sum(np.isnan(corM)))
@@ -277,7 +280,11 @@ def getAdjMat(res, ppthr=None, signed=False, nodes=None):
277
280
  signed -- if True, -1 for negative correlations (default False).
278
281
  nodes -- list of node indices (0-based) for a sparse submatrix (default None).
279
282
 
280
- Returns a P×P numpy array (or submatrix when nodes is given).
283
+ Returns a P×P numpy array (or submatrix when nodes is given). A pair is
284
+ an edge when 1 - r^2 <= ppthr, so with the default threshold the edge
285
+ count equals res['edges']. Pairs with r == 0 exactly (which only arise
286
+ from zero-variance columns) are never edges, so constant columns stay
287
+ isolated even when ppthr = 1.
281
288
  """
282
289
  if ppthr is None:
283
290
  ppthr = res["ppthr"]
@@ -290,14 +297,16 @@ def getAdjMat(res, ppthr=None, signed=False, nodes=None):
290
297
  raise ValueError(f"getAdjMat: 'nodes' must be in [0, {P-1}]")
291
298
  # Find all neighbors of the requested nodes
292
299
  rows = corM[nodes, :] # shape (len(nodes), P)
293
- is_edge = (1.0 - rows ** 2) < ppthr # bool, shape (len(nodes), P)
300
+ is_edge = ((1.0 - rows ** 2) <= ppthr) & (rows != 0) # bool, shape (len(nodes), P)
294
301
  nbr_mask = np.any(is_edge, axis=0)
295
302
  selected = np.sort(np.union1d(nodes, np.where(nbr_mask)[0]))
296
303
  corM = corM[np.ix_(selected, selected)]
297
304
 
298
305
  # Use <= so the boundary pair (z_j == ppthr) is included, matching the
299
- # edge count reported by betaMix() which also uses <=.
300
- A = (1.0 - corM ** 2) <= ppthr
306
+ # edge count reported by betaMix() which also uses <=. r == 0 exactly
307
+ # only arises from zero-variance columns (correlation set to 0); exclude
308
+ # it so such nodes stay isolated even when ppthr = 1.
309
+ A = ((1.0 - corM ** 2) <= ppthr) & (corM != 0)
301
310
  if signed:
302
311
  A = A.astype(float)
303
312
  neg = (corM < 0) & (A > 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: betaMixPy
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A Python package to find strong correlations among P variables, each with N observations.
5
5
  Home-page: https://pypi.org/project/betaMixPy/
6
6
  Author: Haim Bar
@@ -152,6 +152,8 @@ Two strategies:
152
152
 
153
153
  See [NEWS.md](NEWS.md) for the full changelog. Highlights:
154
154
 
155
+ - **0.2.2**: `getAdjMat(nodes=...)` uses the same inclusive threshold;
156
+ constant columns never get edges
155
157
  - **0.2.1**: `getAdjMat` edge count now matches `betaMix()`; fixed a
156
158
  `plotFittedBetaMix` crash; unused dependencies removed; full test suite
157
159
 
@@ -178,6 +178,26 @@ class TestGetAdjMat:
178
178
  with pytest.raises(ValueError, match="nodes"):
179
179
  bx.getAdjMat(dry_res, nodes=[9999])
180
180
 
181
+ def test_node_submatrix_includes_boundary_neighbour(self, dry_res):
182
+ # Threshold exactly at node 0's strongest pair: that neighbour must be
183
+ # selected (<=, not <), giving a 2×2 submatrix with one edge.
184
+ z_row = 1.0 - dry_res["angleMat"][0, 1:] ** 2
185
+ A = bx.getAdjMat(dry_res, ppthr=z_row.min(), nodes=[0])
186
+ assert A.shape == (2, 2)
187
+ assert A[0, 1] == 1.0
188
+
189
+ def test_constant_column_isolated_at_ppthr_one(self, tiny_M):
190
+ M = tiny_M.copy()
191
+ M[:, 2] = 0.0
192
+ with pytest.warns(UserWarning):
193
+ res = bx.betaMix(M, msg=False)
194
+ A = bx.getAdjMat(res, ppthr=1.0)
195
+ assert np.all(A[2, :] == 0) and np.all(A[:, 2] == 0)
196
+ # non-constant pairs are all edges at ppthr = 1
197
+ others = [0, 1, 3]
198
+ sub = A[np.ix_(others, others)]
199
+ assert np.all(sub[~np.eye(3, dtype=bool)] == 1.0)
200
+
181
201
 
182
202
  # ---------------------------------------------------------------------------
183
203
  # clusteringCoef
@@ -1,3 +0,0 @@
1
- __version__ = "0.2.1" # single source of truth; setup.py reads this line
2
-
3
- from .betaMixPy import *
File without changes
File without changes
File without changes