yuclid 0.1.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.
- yuclid/__init__.py +1 -0
- yuclid/cli.py +229 -0
- yuclid/log.py +56 -0
- yuclid/plot.py +1009 -0
- yuclid/run.py +1239 -0
- yuclid/spread.py +152 -0
- yuclid-0.1.0.dist-info/METADATA +15 -0
- yuclid-0.1.0.dist-info/RECORD +11 -0
- yuclid-0.1.0.dist-info/WHEEL +5 -0
- yuclid-0.1.0.dist-info/entry_points.txt +2 -0
- yuclid-0.1.0.dist-info/top_level.txt +1 -0
yuclid/spread.py
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
from yuclid.log import report, LogLevel
|
2
|
+
from scipy.stats import norm
|
3
|
+
import seaborn as sns
|
4
|
+
import pandas as pd
|
5
|
+
import numpy as np
|
6
|
+
import re
|
7
|
+
|
8
|
+
|
9
|
+
available_parametrized = {"sd", "pi", "rsd"}
|
10
|
+
available_non_parametrized = {
|
11
|
+
"mad",
|
12
|
+
"range",
|
13
|
+
"iqr",
|
14
|
+
}
|
15
|
+
available = [f"{name},N" for name in available_parametrized]
|
16
|
+
available += [name for name in available_non_parametrized]
|
17
|
+
|
18
|
+
|
19
|
+
def mad(y):
|
20
|
+
if not isinstance(y, np.ndarray):
|
21
|
+
y = np.array(y)
|
22
|
+
return np.median(np.abs(y - np.median(y)))
|
23
|
+
|
24
|
+
|
25
|
+
def lower(spread_measure):
|
26
|
+
n = re.search(r"\d+(\.\d+)?", spread_measure)
|
27
|
+
if spread_measure.startswith("sd"):
|
28
|
+
coeff = float(n.group())
|
29
|
+
return lambda y: y.mean() - coeff * y.std()
|
30
|
+
elif spread_measure.startswith("pi"):
|
31
|
+
p = float(n.group()) / 100.0
|
32
|
+
return lambda y: np.quantile(y, (1 - p) / 2)
|
33
|
+
elif spread_measure.startswith("rsd"):
|
34
|
+
coeff = float(n.group())
|
35
|
+
return lambda y: y.mean() - coeff * (1 / norm.ppf(0.75)) * mad(y)
|
36
|
+
elif spread_measure == "mad":
|
37
|
+
return lambda y: np.median(y) - mad(y)
|
38
|
+
elif spread_measure == "range":
|
39
|
+
return lambda y: y.min()
|
40
|
+
elif spread_measure == "iqr":
|
41
|
+
return lambda y: np.quantile(y, 0.25)
|
42
|
+
|
43
|
+
|
44
|
+
def upper(spread_measure):
|
45
|
+
n = re.search(r"\d+(\.\d+)?", spread_measure)
|
46
|
+
if spread_measure.startswith("sd"):
|
47
|
+
coeff = float(n.group())
|
48
|
+
return lambda y: y.mean() + coeff * y.std()
|
49
|
+
elif spread_measure.startswith("pi"):
|
50
|
+
p = float(n.group()) / 100.0
|
51
|
+
return lambda y: np.quantile(y, (1 + p) / 2)
|
52
|
+
elif spread_measure.startswith("rsd"):
|
53
|
+
coeff = float(n.group())
|
54
|
+
return lambda y: y.mean() + coeff * (1 / norm.ppf(0.75)) * mad(y)
|
55
|
+
elif spread_measure == "mad":
|
56
|
+
return lambda y: np.median(y) + mad(y)
|
57
|
+
elif spread_measure == "range":
|
58
|
+
return lambda y: y.max()
|
59
|
+
elif spread_measure == "iqr":
|
60
|
+
return lambda y: np.quantile(y, 0.75)
|
61
|
+
|
62
|
+
|
63
|
+
def assert_validity(spread_measure):
|
64
|
+
if not isinstance(spread_measure, str):
|
65
|
+
report(LogLevel.ERROR, "spread_measure must be a string")
|
66
|
+
return False
|
67
|
+
parts = spread_measure.split(",")
|
68
|
+
if parts[0] not in available_non_parametrized.union(available_parametrized):
|
69
|
+
report(
|
70
|
+
LogLevel.ERROR,
|
71
|
+
f"spread_measure '{spread_measure}' is not available",
|
72
|
+
hint="use one of: " + " - ".join(available),
|
73
|
+
)
|
74
|
+
return False
|
75
|
+
if parts[0] in available_parametrized:
|
76
|
+
if len(parts) < 2:
|
77
|
+
report(
|
78
|
+
LogLevel.ERROR,
|
79
|
+
f"spread_measure '{spread_measure}' is missing a parameter",
|
80
|
+
hint=f"try '{spread_measure},N' where N is a number",
|
81
|
+
)
|
82
|
+
return False
|
83
|
+
n = float(parts[1])
|
84
|
+
if parts[0] == "pi" and n < 0 or n > 100:
|
85
|
+
report(
|
86
|
+
LogLevel.ERROR,
|
87
|
+
"parameter for spread_measure 'pi' must be in [0, 100]",
|
88
|
+
)
|
89
|
+
return False
|
90
|
+
if parts[0] in ["sd", "rsd"] and n <= 0:
|
91
|
+
report(
|
92
|
+
LogLevel.ERROR,
|
93
|
+
"parameter for spread_measure 'sd' and 'rsd' must be positive",
|
94
|
+
)
|
95
|
+
return False
|
96
|
+
if parts[0] in available_non_parametrized:
|
97
|
+
if len(parts) != 1:
|
98
|
+
report(
|
99
|
+
LogLevel.ERROR,
|
100
|
+
f"spread_measure '{spread_measure}' must not have any parameters",
|
101
|
+
)
|
102
|
+
return False
|
103
|
+
return True
|
104
|
+
|
105
|
+
|
106
|
+
def draw(
|
107
|
+
ax, spread_measures, df, x, y, z=None, colors=None, palette=None, style="area"
|
108
|
+
):
|
109
|
+
alphas = {
|
110
|
+
"area": np.linspace(0.15, 0.05, len(spread_measures)),
|
111
|
+
"bar": np.linspace(0.30, 0.10, len(spread_measures)),
|
112
|
+
}[style]
|
113
|
+
|
114
|
+
x_dom = df[x].unique()
|
115
|
+
z_dom = df[z].unique()
|
116
|
+
groups = df.groupby([z, x])[y]
|
117
|
+
|
118
|
+
if isinstance(palette, str):
|
119
|
+
colors = sns.color_palette(palette)
|
120
|
+
palette = None
|
121
|
+
|
122
|
+
if colors is None and palette is None:
|
123
|
+
raise Exception("Missing color and palette")
|
124
|
+
|
125
|
+
for i, sm in enumerate(spread_measures):
|
126
|
+
ys_lower = groups.apply(lower(sm))
|
127
|
+
ys_upper = groups.apply(upper(sm))
|
128
|
+
for j, z_val in enumerate(z_dom):
|
129
|
+
if colors is not None:
|
130
|
+
color = colors[j % len(colors)]
|
131
|
+
else:
|
132
|
+
color = palette[z_val]
|
133
|
+
y_lower = ys_lower.xs(z_val)
|
134
|
+
y_upper = ys_upper.xs(z_val)
|
135
|
+
if style == "area":
|
136
|
+
ax.fill_between(
|
137
|
+
x_dom,
|
138
|
+
y_lower,
|
139
|
+
y_upper,
|
140
|
+
interpolate=True,
|
141
|
+
color=color,
|
142
|
+
alpha=alphas[i],
|
143
|
+
)
|
144
|
+
elif style == "bar":
|
145
|
+
ax.vlines(
|
146
|
+
x=x,
|
147
|
+
ymin=y_lower,
|
148
|
+
ymax=y_upper,
|
149
|
+
color=color,
|
150
|
+
alpha=alphas[i],
|
151
|
+
linewidth=4,
|
152
|
+
)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: yuclid
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A Python project.
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
6
|
+
Project-URL: Homepage, https://github.com/fsossai/yuclid
|
7
|
+
Requires-Python: >=3.8
|
8
|
+
Description-Content-Type: text/markdown
|
9
|
+
|
10
|
+
# Yuclid
|
11
|
+
|
12
|
+
*Combinatorially explode your experiments*
|
13
|
+
|
14
|
+
- **`yuclid run`**: Run experiments with with all combination of registered parameters.
|
15
|
+
- **`yuclid plot`**: Interactively visualizes the results produced by `yuclid run`.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
yuclid/__init__.py,sha256=Pru0BlFBASFCFo7McHdohtKkUtgMPDwbGfyUZlE2_Vw,21
|
2
|
+
yuclid/cli.py,sha256=l5WUY6Q6nwg7WRrAAPf5uaspG9zrEPE9BA9v3eYI_vE,6410
|
3
|
+
yuclid/log.py,sha256=GR_FVfNroumuonKguAPd6H1rKjxJKRc8tAS2sVNTbzE,1655
|
4
|
+
yuclid/plot.py,sha256=RV_bgkFDpOGxw7ankW7QsnBsyrholBtYKKj9jUtBAyM,30836
|
5
|
+
yuclid/run.py,sha256=V3tcFHWyXH2fs6aFR6vJi2c5DhDb-zDXJMWp-xUi8DM,44048
|
6
|
+
yuclid/spread.py,sha256=4Ci3nsu8n_dhG-AK2IWHKRElQ8oaGdw14LrgNu79biM,4938
|
7
|
+
yuclid-0.1.0.dist-info/METADATA,sha256=umoUK82Bh__fTcoLiFS64thJ6d5brdDWHWmkozzA9p8,473
|
8
|
+
yuclid-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
9
|
+
yuclid-0.1.0.dist-info/entry_points.txt,sha256=2AvTtyt5iBnjr6HnjqH_3PeSoq9UzIbT92qivmEbOYA,43
|
10
|
+
yuclid-0.1.0.dist-info/top_level.txt,sha256=cL5mb4h_4etwTsqhPvSnoVBXImIzPFGd3rINV1nEjPo,7
|
11
|
+
yuclid-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
yuclid
|