mumpy-toolkit 0.2.0__py3-none-any.whl
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.
- mumpy/__init__.py +128 -0
- mumpy/_core.py +218 -0
- mumpy/_math.py +283 -0
- mumpy/_parallel.py +142 -0
- mumpy/db.py +289 -0
- mumpy/fft.py +132 -0
- mumpy/frame.py +428 -0
- mumpy/io.py +196 -0
- mumpy/linalg.py +62 -0
- mumpy/metrics.py +187 -0
- mumpy/ml.py +443 -0
- mumpy/nn.py +278 -0
- mumpy/preprocessing.py +259 -0
- mumpy/random.py +99 -0
- mumpy/stats.py +122 -0
- mumpy/utils.py +105 -0
- mumpy/viz.py +81 -0
- mumpy_toolkit-0.2.0.dist-info/METADATA +200 -0
- mumpy_toolkit-0.2.0.dist-info/RECORD +22 -0
- mumpy_toolkit-0.2.0.dist-info/WHEEL +5 -0
- mumpy_toolkit-0.2.0.dist-info/licenses/LICENSE +21 -0
- mumpy_toolkit-0.2.0.dist-info/top_level.txt +1 -0
mumpy/stats.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""mumpy.stats: descriptive statistics & exploratory analysis for analysts."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"describe", "corr", "cov", "zscore", "iqr_outliers", "z_outliers",
|
|
8
|
+
"histogram", "percentile", "mode", "skew", "kurtosis",
|
|
9
|
+
"correlation_matrix", "crosstab", "value_counts",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def describe(a, percentiles=(25, 50, 75)):
|
|
14
|
+
a = np.asanyarray(a, dtype=float).ravel()
|
|
15
|
+
a = a[~np.isnan(a)]
|
|
16
|
+
if a.size == 0:
|
|
17
|
+
return {"count": 0}
|
|
18
|
+
return {
|
|
19
|
+
"count": int(a.size),
|
|
20
|
+
"mean": float(a.mean()),
|
|
21
|
+
"std": float(a.std()),
|
|
22
|
+
"min": float(a.min()),
|
|
23
|
+
**{f"{int(p)}%": float(np.percentile(a, p)) for p in percentiles},
|
|
24
|
+
"max": float(a.max()),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def corr(x, y):
|
|
29
|
+
x = np.asanyarray(x, dtype=float).ravel()
|
|
30
|
+
y = np.asanyarray(y, dtype=float).ravel()
|
|
31
|
+
mask = ~(np.isnan(x) | np.isnan(y))
|
|
32
|
+
x, y = x[mask], y[mask]
|
|
33
|
+
if x.size < 2:
|
|
34
|
+
return float("nan")
|
|
35
|
+
return float(np.corrcoef(x, y)[0, 1])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cov(x, y, ddof=0):
|
|
39
|
+
x = np.asanyarray(x, dtype=float).ravel()
|
|
40
|
+
y = np.asanyarray(y, dtype=float).ravel()
|
|
41
|
+
mask = ~(np.isnan(x) | np.isnan(y))
|
|
42
|
+
return float(np.cov(x[mask], y[mask], ddof=ddof)[0, 1])
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def correlation_matrix(X):
|
|
46
|
+
X = np.asanyarray(X, dtype=float)
|
|
47
|
+
col_mean = np.nanmean(X, axis=0)
|
|
48
|
+
idx = np.where(np.isnan(X))
|
|
49
|
+
X = X.copy()
|
|
50
|
+
X[idx] = np.take(col_mean, idx[1])
|
|
51
|
+
return np.corrcoef(X, rowvar=False)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def zscore(a, axis=None, ddof=0):
|
|
55
|
+
a = np.asanyarray(a, dtype=float)
|
|
56
|
+
m = np.nanmean(a, axis=axis, keepdims=True)
|
|
57
|
+
s = np.nanstd(a, axis=axis, ddof=ddof, keepdims=True)
|
|
58
|
+
s = np.where(s == 0, 1.0, s)
|
|
59
|
+
return (a - m) / s
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def iqr_outliers(a, factor=1.5):
|
|
63
|
+
a = np.asanyarray(a, dtype=float).ravel()
|
|
64
|
+
q1, q3 = np.nanpercentile(a, [25, 75])
|
|
65
|
+
iqr = q3 - q1
|
|
66
|
+
lo, hi = q1 - factor * iqr, q3 + factor * iqr
|
|
67
|
+
return (a < lo) | (a > hi), (float(lo), float(hi))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def z_outliers(a, thresh=3.0):
|
|
71
|
+
z = np.abs(zscore(a))
|
|
72
|
+
return (z > thresh).ravel() if z.ndim == 1 else (z > thresh), thresh
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def histogram(a, bins=10, range=None):
|
|
76
|
+
a = np.asanyarray(a, dtype=float).ravel()
|
|
77
|
+
counts, edges = np.histogram(a[~np.isnan(a)], bins=bins, range=range)
|
|
78
|
+
return counts, edges
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def percentile(a, q):
|
|
82
|
+
return np.nanpercentile(np.asanyarray(a, dtype=float), q)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def mode(a):
|
|
86
|
+
vals, counts = np.unique(np.asanyarray(a).ravel(), return_counts=True)
|
|
87
|
+
return vals[int(np.argmax(counts))]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def skew(a):
|
|
91
|
+
a = np.asanyarray(a, dtype=float).ravel()
|
|
92
|
+
a = a[~np.isnan(a)]
|
|
93
|
+
m, s = a.mean(), a.std()
|
|
94
|
+
if s == 0 or a.size < 3:
|
|
95
|
+
return 0.0
|
|
96
|
+
return float((((a - m) / s) ** 3).mean())
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def kurtosis(a, fisher=True):
|
|
100
|
+
a = np.asanyarray(a, dtype=float).ravel()
|
|
101
|
+
a = a[~np.isnan(a)]
|
|
102
|
+
m, s = a.mean(), a.std()
|
|
103
|
+
if s == 0 or a.size < 4:
|
|
104
|
+
return 0.0
|
|
105
|
+
k = float((((a - m) / s) ** 4).mean())
|
|
106
|
+
return k - 3.0 if fisher else k
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def value_counts(a):
|
|
110
|
+
vals, counts = np.unique(np.asanyarray(a).ravel(), return_counts=True)
|
|
111
|
+
order = np.argsort(-counts)
|
|
112
|
+
return list(zip(vals[order].tolist(), counts[order].tolist()))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def crosstab(a, b):
|
|
116
|
+
a = np.asanyarray(a).ravel()
|
|
117
|
+
b = np.asanyarray(b).ravel()
|
|
118
|
+
ua, ia = np.unique(a, return_inverse=True)
|
|
119
|
+
ub, ib = np.unique(b, return_inverse=True)
|
|
120
|
+
table = np.zeros((len(ua), len(ub)), dtype=int)
|
|
121
|
+
np.add.at(table, (ia, ib), 1)
|
|
122
|
+
return table, ua.tolist(), ub.tolist()
|
mumpy/utils.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""mumpy utils: seeds, timing, chunking, memory helpers, missing-value utils."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import numpy as np
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"seed", "timer", "timeit", "chunks", "asnumpy", "is_mumpy",
|
|
10
|
+
"memory_usage", "count_nan", "drop_nan", "fill_nan",
|
|
11
|
+
"normalize", "standardize", "one_hot",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def seed(s=None):
|
|
16
|
+
"""Set global seeds for reproducibility (numpy + mumpy.random + python random)."""
|
|
17
|
+
import random as _pr
|
|
18
|
+
np.random.seed(s if s is None else int(s) % (2**32 - 1))
|
|
19
|
+
try:
|
|
20
|
+
from . import random as _cr
|
|
21
|
+
_cr.seed(s)
|
|
22
|
+
except Exception:
|
|
23
|
+
pass
|
|
24
|
+
_pr.seed(s)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@contextmanager
|
|
28
|
+
def timer(name="elapsed"):
|
|
29
|
+
t0 = time.perf_counter()
|
|
30
|
+
yield
|
|
31
|
+
print(f"{name}: {(time.perf_counter() - t0) * 1000:.2f}ms")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def timeit(func, *args, repeat=5, warmup=1, **kw):
|
|
35
|
+
for _ in range(warmup):
|
|
36
|
+
func(*args, **kw)
|
|
37
|
+
best = min(
|
|
38
|
+
(lambda: (t0 := time.perf_counter(), func(*args, **kw),
|
|
39
|
+
time.perf_counter() - t0)[2])()
|
|
40
|
+
for _ in range(repeat)
|
|
41
|
+
)
|
|
42
|
+
return best
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def chunks(n, size):
|
|
46
|
+
for i in range(0, n, size):
|
|
47
|
+
yield (i, min(i + size, n))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def asnumpy(a):
|
|
51
|
+
return np.asanyarray(a).view(np.ndarray)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def is_mumpy(a):
|
|
55
|
+
from ._core import ndarray
|
|
56
|
+
return isinstance(a, ndarray)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# backward compat with the old `cumpy` name
|
|
60
|
+
is_cumpy = is_mumpy
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def memory_usage(a):
|
|
64
|
+
a = np.asanyarray(a)
|
|
65
|
+
return int(a.nbytes)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def count_nan(a):
|
|
69
|
+
return int(np.isnan(np.asanyarray(a, dtype=float)).sum())
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def drop_nan(a):
|
|
73
|
+
a = np.asanyarray(a)
|
|
74
|
+
mask = ~np.isnan(a.astype(float)) if np.issubdtype(a.dtype, np.number) else np.zeros(len(a), bool)
|
|
75
|
+
return a[mask] if a.ndim == 1 else a
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def fill_nan(a, value=0.0):
|
|
79
|
+
a = np.asanyarray(a).astype(float, copy=True)
|
|
80
|
+
a[np.isnan(a)] = value
|
|
81
|
+
return a
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def normalize(a, axis=None):
|
|
85
|
+
a = np.asanyarray(a, dtype=float)
|
|
86
|
+
n = np.linalg.norm(a, axis=axis, keepdims=True)
|
|
87
|
+
n[n == 0] = 1.0
|
|
88
|
+
return a / n
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def standardize(a, axis=0):
|
|
92
|
+
a = np.asanyarray(a, dtype=float)
|
|
93
|
+
m = a.mean(axis=axis, keepdims=True)
|
|
94
|
+
s = a.std(axis=axis, keepdims=True)
|
|
95
|
+
s[s == 0] = 1.0
|
|
96
|
+
return (a - m) / s
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def one_hot(labels, num_classes=None):
|
|
100
|
+
labels = np.asanyarray(labels).astype(int).ravel()
|
|
101
|
+
if num_classes is None:
|
|
102
|
+
num_classes = int(labels.max()) + 1 if labels.size else 0
|
|
103
|
+
out = np.zeros((labels.size, num_classes), dtype=float)
|
|
104
|
+
out[np.arange(labels.size), labels] = 1.0
|
|
105
|
+
return out
|
mumpy/viz.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""mumpy.viz: one-line plots for quick EDA (requires matplotlib, optional)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
__all__ = ["hist", "scatter", "line", "heatmap", "corr_heatmap", "boxplot"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _plt():
|
|
10
|
+
try:
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
return plt
|
|
13
|
+
except ImportError as e:
|
|
14
|
+
raise ImportError("pip install matplotlib") from e
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def hist(a, bins=30, title=None, show=False):
|
|
18
|
+
plt = _plt()
|
|
19
|
+
plt.figure()
|
|
20
|
+
plt.hist(np.asanyarray(a, dtype=float).ravel(), bins=bins)
|
|
21
|
+
if title:
|
|
22
|
+
plt.title(title)
|
|
23
|
+
if show:
|
|
24
|
+
plt.show()
|
|
25
|
+
return plt.gca()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def scatter(x, y, title=None, show=False):
|
|
29
|
+
plt = _plt()
|
|
30
|
+
plt.figure()
|
|
31
|
+
plt.scatter(np.asanyarray(x).ravel(), np.asanyarray(y).ravel(), alpha=0.6)
|
|
32
|
+
if title:
|
|
33
|
+
plt.title(title)
|
|
34
|
+
if show:
|
|
35
|
+
plt.show()
|
|
36
|
+
return plt.gca()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def line(*series, title=None, show=False):
|
|
40
|
+
plt = _plt()
|
|
41
|
+
plt.figure()
|
|
42
|
+
for s in series:
|
|
43
|
+
plt.plot(np.asanyarray(s).ravel())
|
|
44
|
+
if title:
|
|
45
|
+
plt.title(title)
|
|
46
|
+
if show:
|
|
47
|
+
plt.show()
|
|
48
|
+
return plt.gca()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def heatmap(m, title=None, show=False):
|
|
52
|
+
plt = _plt()
|
|
53
|
+
plt.figure()
|
|
54
|
+
plt.imshow(np.asanyarray(m, dtype=float), aspect="auto")
|
|
55
|
+
plt.colorbar()
|
|
56
|
+
if title:
|
|
57
|
+
plt.title(title)
|
|
58
|
+
if show:
|
|
59
|
+
plt.show()
|
|
60
|
+
return plt.gca()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def corr_heatmap(X, labels=None, show=False):
|
|
64
|
+
X = np.asanyarray(X, dtype=float)
|
|
65
|
+
C = np.corrcoef(X, rowvar=False)
|
|
66
|
+
ax = heatmap(C, title="Correlation", show=False)
|
|
67
|
+
if labels is not None:
|
|
68
|
+
ax.set_xticks(range(len(labels)), labels, rotation=45)
|
|
69
|
+
ax.set_yticks(range(len(labels)), labels)
|
|
70
|
+
if show:
|
|
71
|
+
_plt().show()
|
|
72
|
+
return ax
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def boxplot(*cols, labels=None, show=False):
|
|
76
|
+
plt = _plt()
|
|
77
|
+
plt.figure()
|
|
78
|
+
plt.boxplot([np.asanyarray(c, dtype=float).ravel() for c in cols], labels=labels)
|
|
79
|
+
if show:
|
|
80
|
+
plt.show()
|
|
81
|
+
return plt.gca()
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mumpy-toolkit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: NumPy-compatible array library with multithreaded ufuncs, fused ops, plus built-in IO, SQL databases, DataFrame, stats, preprocessing, metrics, ML and tiny DL
|
|
5
|
+
Author-email: salim-studio <salim-studio@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/salim-studio/mumpy
|
|
8
|
+
Project-URL: Repository, https://github.com/salim-studio/mumpy
|
|
9
|
+
Project-URL: Issues, https://github.com/salim-studio/mumpy/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/salim-studio/mumpy#readme
|
|
11
|
+
Project-URL: Changelog, https://github.com/salim-studio/mumpy/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: numpy,arrays,dataframe,sql,machine-learning,deep-learning,statistics,preprocessing
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
24
|
+
Classifier: Topic :: Database
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: numpy>=1.24
|
|
29
|
+
Provides-Extra: fast
|
|
30
|
+
Requires-Dist: scipy>=1.10; extra == "fast"
|
|
31
|
+
Provides-Extra: io
|
|
32
|
+
Requires-Dist: pandas>=1.5; extra == "io"
|
|
33
|
+
Requires-Dist: pyarrow>=10; extra == "io"
|
|
34
|
+
Provides-Extra: db
|
|
35
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "db"
|
|
36
|
+
Requires-Dist: duckdb>=0.8; extra == "db"
|
|
37
|
+
Provides-Extra: viz
|
|
38
|
+
Requires-Dist: matplotlib>=3.5; extra == "viz"
|
|
39
|
+
Provides-Extra: all
|
|
40
|
+
Requires-Dist: scipy>=1.10; extra == "all"
|
|
41
|
+
Requires-Dist: pandas>=1.5; extra == "all"
|
|
42
|
+
Requires-Dist: pyarrow>=10; extra == "all"
|
|
43
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "all"
|
|
44
|
+
Requires-Dist: duckdb>=0.8; extra == "all"
|
|
45
|
+
Requires-Dist: matplotlib>=3.5; extra == "all"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
<p align="center">
|
|
49
|
+
<img src="assets/banner.svg" alt="mumpy banner" width="100%"/>
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<img src="assets/logo.svg" alt="mumpy logo" width="96"/>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<h1 align="center">mumpy</h1>
|
|
57
|
+
|
|
58
|
+
<p align="center"><strong>NumPy you know. Speed you feel. Tools you actually need.</strong></p>
|
|
59
|
+
|
|
60
|
+
<p align="center">
|
|
61
|
+
<a href="https://github.com/salim-studio/mumpy/actions"><img src="https://github.com/salim-studio/mumpy/actions/workflows/ci.yml/badge.svg" alt="CI"/></a>
|
|
62
|
+
<img src="https://img.shields.io/badge/version-0.2.0-4F46E5" alt="version"/>
|
|
63
|
+
<img src="https://img.shields.io/badge/python-3.9%2B-06B6D4" alt="python"/>
|
|
64
|
+
<img src="https://img.shields.io/badge/numpy-compatible-013243" alt="numpy compatible"/>
|
|
65
|
+
<img src="https://img.shields.io/badge/license-MIT-FDE047" alt="license"/>
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
**mumpy** is a drop-in, NumPy-compatible library that goes further: multithreaded compute,
|
|
69
|
+
fused operations, plus a built-in toolkit for data loading, SQL databases, dataframes,
|
|
70
|
+
statistics, preprocessing, classic ML and tiny deep learning — with zero hard dependencies
|
|
71
|
+
beyond NumPy.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import mumpy as mp
|
|
75
|
+
|
|
76
|
+
# 1) Faster NumPy (parallel ufuncs + fused ops)
|
|
77
|
+
a = mp.arange(10_000_000)
|
|
78
|
+
b = mp.sqrt(a) # multithreaded over all cores
|
|
79
|
+
c = mp.fma(a, b, 1.0) # a*b+c in a single pass, half the peak memory
|
|
80
|
+
|
|
81
|
+
# 2) Databases (sqlite built-in; postgres/mysql via SQLAlchemy, OLAP via DuckDB)
|
|
82
|
+
db = mp.db.connect("data.db")
|
|
83
|
+
db.create_table("users", {"id": "INTEGER PRIMARY KEY", "name": "TEXT", "age": "INTEGER"})
|
|
84
|
+
db.insert_many("users", [{"name": "ada", "age": 36}])
|
|
85
|
+
ages = db.read_numpy("SELECT age FROM users")
|
|
86
|
+
|
|
87
|
+
# 3) Lightweight DataFrame for analysts (no pandas required)
|
|
88
|
+
df = mp.frame.DataFrame({"age": [20, 30, 40], "salary": [100, 200, 300]})
|
|
89
|
+
df.describe()
|
|
90
|
+
df.groupby("age").mean()
|
|
91
|
+
df.query("age > 25")
|
|
92
|
+
|
|
93
|
+
# 4) Classic ML with a scikit-learn-like API (pure NumPy)
|
|
94
|
+
model = mp.ml.LogisticRegression().fit(X_train, y_train)
|
|
95
|
+
pred = model.predict(X_test)
|
|
96
|
+
|
|
97
|
+
# 5) Tiny deep learning (pure NumPy)
|
|
98
|
+
net = mp.nn.Sequential([mp.nn.Dense(4, 16), mp.nn.ReLU(), mp.nn.Dense(16, 1)])
|
|
99
|
+
net.fit(X, y, epochs=200, lr=0.01)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Why faster than NumPy?
|
|
103
|
+
|
|
104
|
+
| Technique | Detail |
|
|
105
|
+
|---|---|
|
|
106
|
+
| Parallel ufuncs | Compute-bound element-wise ops (`sqrt/exp/sin/cos/…`) split across a thread pool |
|
|
107
|
+
| Fused ops | `fma/fms/fnma/lerp` instead of `a*b+c` (half the peak memory, one pass) |
|
|
108
|
+
| Parallel FFT | `scipy.fft` with `workers=-1` when SciPy is installed |
|
|
109
|
+
| `einsum(optimize=True)` | Faster contraction paths |
|
|
110
|
+
| Contiguous linalg | `batch_matmul/cho_solve/ridge_solve` ensure cache-friendly layouts |
|
|
111
|
+
|
|
112
|
+
> Honest note: bandwidth-bound reductions (`sum/mean`) delegate to NumPy directly —
|
|
113
|
+
> a single thread already saturates RAM bandwidth, and threading only adds overhead there.
|
|
114
|
+
|
|
115
|
+
## Modules
|
|
116
|
+
|
|
117
|
+
| Module | For | Highlights |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `mp.io` | Everyone | `load_csv/save_csv/load_npy/load_npz/load_json/memmap/load_parquet/load_excel/read_auto` |
|
|
120
|
+
| `mp.db` | Backend devs & analysts | `connect/read_numpy/read_pandas/write_numpy/from_csv/query/to_parquet` |
|
|
121
|
+
| `mp.frame` | Data analysts | `DataFrame/filter/sort/groupby/merge/describe/corr/read_csv/read_sql/to_pandas` |
|
|
122
|
+
| `mp.stats` | Exploratory analysis | `describe/corr/zscore/iqr_outliers/histogram/skew/kurtosis/crosstab` |
|
|
123
|
+
| `mp.preprocessing` | Data science | `StandardScaler/MinMaxScaler/RobustScaler/OneHotEncoder/LabelEncoder/SimpleImputer/train_test_split/Pipeline` |
|
|
124
|
+
| `mp.metrics` | Model evaluation | `mse/rmse/mae/r2/accuracy/precision/recall/f1/confusion_matrix/roc_auc/log_loss` |
|
|
125
|
+
| `mp.ml` | Machine learning | `LinearRegression/Ridge/LogisticRegression/KNN/NaiveBayes/DecisionTree/RandomForest/KMeans/PCA` |
|
|
126
|
+
| `mp.nn` | Deep learning | `Sequential/Dense/ReLU/Sigmoid/Tanh/Softmax/Dropout/Adam/SGD/MSE/BCE/CrossEntropy` |
|
|
127
|
+
| `mp.viz` | Quick plots | `hist/scatter/line/heatmap/corr_heatmap` (matplotlib, optional) |
|
|
128
|
+
| `mp.utils` | Everyone | `seed/timer/timeit/one_hot/standardize/fill_nan/memory_usage` |
|
|
129
|
+
|
|
130
|
+
## Installation
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pip install mumpy-toolkit # core (numpy only)
|
|
134
|
+
pip install "mumpy-toolkit[fast]" # + scipy for parallel FFT
|
|
135
|
+
pip install "mumpy-toolkit[all]" # scipy, pandas, pyarrow, sqlalchemy, duckdb, matplotlib
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
From source:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
git clone https://github.com/salim-studio/mumpy.git
|
|
142
|
+
cd mumpy
|
|
143
|
+
pip install -e ".[all]"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Compatibility
|
|
147
|
+
|
|
148
|
+
- `mumpy.ndarray` subclasses `np.ndarray` — any NumPy-consuming code accepts it unchanged.
|
|
149
|
+
- `mp.asnumpy(x)` returns a plain zero-copy `np.ndarray` view.
|
|
150
|
+
- `mp.set_workers(1)` reproduces pure-NumPy behavior for fair comparison.
|
|
151
|
+
- `DataFrame.to_pandas()/from_pandas()` bridge to pandas; `Database` works with stdlib
|
|
152
|
+
sqlite and optionally SQLAlchemy (PostgreSQL/MySQL) and DuckDB.
|
|
153
|
+
- Migrating from the old name? `import cumpy` still works via a compatibility shim.
|
|
154
|
+
|
|
155
|
+
## Benchmarks & tests
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
python benchmarks/bench.py
|
|
159
|
+
python -m pytest tests/ -q
|
|
160
|
+
python examples_mumpy.py # end-to-end: synthetic data -> DB -> DataFrame -> ML
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## End-to-end example (synthetic data → DB → ML)
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import numpy as np
|
|
167
|
+
import mumpy as mp
|
|
168
|
+
|
|
169
|
+
rng = np.random.default_rng(0)
|
|
170
|
+
X = rng.normal(size=(200, 3))
|
|
171
|
+
y = (X[:, 0] + X[:, 1] > 0).astype(int)
|
|
172
|
+
|
|
173
|
+
with mp.db.connect(":memory:") as db:
|
|
174
|
+
db.write_numpy("data", np.column_stack([X, y]), columns=["f0", "f1", "f2", "label"])
|
|
175
|
+
df = mp.frame.DataFrame.read_sql("SELECT * FROM data", db)
|
|
176
|
+
|
|
177
|
+
print(df.describe())
|
|
178
|
+
Xtr, Xte, ytr, yte = mp.ml.train_test_split(
|
|
179
|
+
df.to_numpy(["f0", "f1", "f2"]), df["label"].to_numpy(), test_size=0.2)
|
|
180
|
+
acc = mp.metrics.accuracy(
|
|
181
|
+
yte, mp.ml.LogisticRegression(lr=0.5, epochs=500).fit(Xtr, ytr).predict(Xte))
|
|
182
|
+
print("accuracy:", acc)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Roadmap
|
|
186
|
+
|
|
187
|
+
- [ ] PyPI release + versioned changelog
|
|
188
|
+
- [ ] Optional Rust/Numba backend for ufuncs
|
|
189
|
+
- [ ] `mp.sql` query builder + lazy frames
|
|
190
|
+
- [ ] More estimators (Gradient Boosting, Isolation Forest)
|
|
191
|
+
- [ ] ONNX export for `mp.nn`
|
|
192
|
+
|
|
193
|
+
## Contributing
|
|
194
|
+
|
|
195
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and feature requests are welcome via
|
|
196
|
+
[issues](https://github.com/salim-studio/mumpy/issues) — please use the templates.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT — see [LICENSE](LICENSE). © salim-studio.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
mumpy/__init__.py,sha256=EpM-tHY9N23cki0ElqJjgdJHay5GVY1-N_JxHR6LcHA,5756
|
|
2
|
+
mumpy/_core.py,sha256=KLeRSRUS0PHUQKHyZ6PszWzuybg_KQuqqIzS9ANgQD0,7492
|
|
3
|
+
mumpy/_math.py,sha256=F23GD_wtJjeMpYBplXTazYK9F42t5MAnEUqSGga4Qcs,8846
|
|
4
|
+
mumpy/_parallel.py,sha256=GNe7UjKQjvlV3bAivhhD0RAi7DKbqJMgUZCO-KnjnFw,5592
|
|
5
|
+
mumpy/db.py,sha256=LsntQ1iMk6iBjRdjOHfoSgGrN18Ytb4X5edfwcjaxy0,10674
|
|
6
|
+
mumpy/fft.py,sha256=PV8p2ZEgkrCGkuFRV964kNJYgZWMp-t6Z9T5YHhqGVo,4483
|
|
7
|
+
mumpy/frame.py,sha256=fd7vj6cHUGEkYNI0SooGBCkYyfDRfFoBu8clSEi5G0Y,15869
|
|
8
|
+
mumpy/io.py,sha256=oFE_exgx8sYhQVnhQzEZILitAgRkWoVsLELGOm97eno,5900
|
|
9
|
+
mumpy/linalg.py,sha256=T_KtF8jC-LHlx8GyM6E5n1EWHJlJmQWWJ0-gopEs8LM,1854
|
|
10
|
+
mumpy/metrics.py,sha256=t3DYEvJFPqp-lN0oMVC1ocMTtHCbIiYo0372AayDCH8,7096
|
|
11
|
+
mumpy/ml.py,sha256=FVuLCCvHu7qgxaqeL2KgRJqBGnr-cn5DTQub7D1cOvM,15462
|
|
12
|
+
mumpy/nn.py,sha256=Ntlrd9ju5-LZlPiKDGqX0E3pnooMMs_pL2IBpjm_YB0,8186
|
|
13
|
+
mumpy/preprocessing.py,sha256=Ga-v3kM8nSniOxwRvf8LuhsNp6EmaD7cMj77UX33-e4,8117
|
|
14
|
+
mumpy/random.py,sha256=Q8oFOSf-washlm-Ne9niQHLR8WJc-lMXNjEUrLwRqTI,2480
|
|
15
|
+
mumpy/stats.py,sha256=7Tv3eyBxiaCui8s8BQi0FNbkdntn-moX_R6xaTnqlhA,3575
|
|
16
|
+
mumpy/utils.py,sha256=yWMHjIjS-PFqIztPKCYfojThnar6DqfrRhszMoJp5Ks,2645
|
|
17
|
+
mumpy/viz.py,sha256=17PrKiMut6Lm_aZrR_9fRZUXHDK-3nJuODMox-6g3L4,2017
|
|
18
|
+
mumpy_toolkit-0.2.0.dist-info/licenses/LICENSE,sha256=hDYVKKPqNhSZ9rd347j-lmHJTI0g35WOPTYMp8SMh9Q,1069
|
|
19
|
+
mumpy_toolkit-0.2.0.dist-info/METADATA,sha256=eof0OoEzWpYFLEILACpJswlP1OaJv7ImcR3zvFNJ3V4,8470
|
|
20
|
+
mumpy_toolkit-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
21
|
+
mumpy_toolkit-0.2.0.dist-info/top_level.txt,sha256=mniPO61dR6cmqnvOLmWVGwe4QsTTDxPRJE6_-lV3LZk,6
|
|
22
|
+
mumpy_toolkit-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 salim-studio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mumpy
|