bepad 0.1.0__tar.gz → 0.1.1__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.
- {bepad-0.1.0 → bepad-0.1.1}/PKG-INFO +1 -1
- {bepad-0.1.0 → bepad-0.1.1}/bepad/__init__.py +1 -1
- {bepad-0.1.0 → bepad-0.1.1}/bepad/associator.py +11 -14
- {bepad-0.1.0 → bepad-0.1.1}/bepad/data.py +55 -10
- {bepad-0.1.0 → bepad-0.1.1}/bepad/metrics.py +5 -7
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/PKG-INFO +1 -1
- {bepad-0.1.0 → bepad-0.1.1}/pyproject.toml +1 -1
- {bepad-0.1.0 → bepad-0.1.1}/LICENSE +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/README.md +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/__main__.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/__init__.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/config.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/geo.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/labels.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/pool.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/release.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/utdquake.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/build/windows.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/leaderboard.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/plots.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/stats.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad/torch.py +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/SOURCES.txt +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/dependency_links.txt +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/entry_points.txt +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/requires.txt +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/bepad.egg-info/top_level.txt +0 -0
- {bepad-0.1.0 → bepad-0.1.1}/setup.cfg +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
class MyMethod(bepad.Associator): ... # template for reusable associators
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
__version__ = "0.1.
|
|
9
|
+
__version__ = "0.1.1"
|
|
10
10
|
|
|
11
11
|
from .data import CORE_NAME, CORE_NETWORKS, LABEL_COLUMNS, Release, Split, download, load, open, predictions_frame # noqa: E402,A004
|
|
12
12
|
from .metrics import evaluate # noqa: E402
|
|
@@ -90,26 +90,23 @@ class Associator:
|
|
|
90
90
|
raise NotImplementedError
|
|
91
91
|
|
|
92
92
|
# --- provided ------------------------------------------------------------------
|
|
93
|
-
def run(self, split="test", networks=None, scenarios=None, max_windows=None,
|
|
94
|
-
root=None, progress=True):
|
|
93
|
+
def run(self, split="test", networks=None, scenarios=None, max_windows=None, window_ids=None, workers=1,
|
|
94
|
+
release=None, root=None, progress=True):
|
|
95
95
|
"""Run on every window of a split and score it. Returns a :class:`Result`.
|
|
96
96
|
|
|
97
97
|
``workers``: number of CPU processes (windows are independent).
|
|
98
|
-
``scenarios`` / ``max_windows`` run a subset (quick tests
|
|
99
|
-
marked partial and are not ranked on the leaderboard.
|
|
98
|
+
``scenarios`` / ``max_windows`` / ``window_ids`` run a subset (quick tests, as in
|
|
99
|
+
:func:`bepad.load`); such runs are marked partial and are not ranked on the leaderboard.
|
|
100
100
|
"""
|
|
101
101
|
from .data import RELEASE, load
|
|
102
102
|
from .metrics import evaluate
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
keep = keep[keep.scenario.isin(scenarios)]
|
|
109
|
-
if max_windows is not None:
|
|
110
|
-
keep = keep.groupby("network", group_keys=False).head(max_windows)
|
|
104
|
+
subset = scenarios is not None or max_windows is not None or window_ids is not None
|
|
105
|
+
data = load(split, networks=networks, labels=False, release=release or RELEASE, root=root,
|
|
106
|
+
scenarios=scenarios, max_windows=max_windows, window_ids=window_ids)
|
|
107
|
+
keep = data.windows
|
|
111
108
|
ids = set(keep.window_id)
|
|
112
|
-
todo = [(win.window_id, win.meta["network"], win.picks, win.stations) for win in data
|
|
109
|
+
todo = [(win.window_id, win.meta["network"], win.picks, win.stations) for win in data]
|
|
113
110
|
rows, locs, secs, t0, n = [], [], [], time.time(), len(todo)
|
|
114
111
|
_RUNNING[0] = self
|
|
115
112
|
if workers > 1:
|
|
@@ -137,8 +134,8 @@ class Associator:
|
|
|
137
134
|
meta = {
|
|
138
135
|
"split": split, "release": data.release.path.name,
|
|
139
136
|
"networks": sorted(keep.network.unique()),
|
|
140
|
-
"n_windows": n, "complete":
|
|
141
|
-
"scenarios": "all" if scenarios is None else list(scenarios),
|
|
137
|
+
"n_windows": n, "complete": not subset,
|
|
138
|
+
"scenarios": "all" if scenarios is None else ([scenarios] if isinstance(scenarios, str) else list(scenarios)),
|
|
142
139
|
"workers": workers, "runtime_s": round(runtime, 2),
|
|
143
140
|
"seconds_per_window": round(float(np.mean(secs)), 4) if secs else None, # time inside associate()
|
|
144
141
|
"hardware": f"{platform.processor() or platform.machine()} ({platform.system()})",
|
|
@@ -97,24 +97,36 @@ class Release:
|
|
|
97
97
|
def scenarios(self):
|
|
98
98
|
return json.loads((self.path / "scenarios.json").read_text())
|
|
99
99
|
|
|
100
|
-
def _read(self, split, table, networks, columns=None):
|
|
100
|
+
def _read(self, split, table, networks, columns=None, window_ids=None):
|
|
101
101
|
files = sorted((self.path / split / table).glob("network=*.parquet"))
|
|
102
102
|
if networks is not None:
|
|
103
103
|
keep = {f"network={n}.parquet" for n in networks}
|
|
104
104
|
files = [f for f in files if f.name in keep]
|
|
105
105
|
if not files:
|
|
106
106
|
raise FileNotFoundError(f"no {table} files for split={split!r}, networks={networks}")
|
|
107
|
-
|
|
107
|
+
if window_ids is None:
|
|
108
|
+
return pd.concat([pd.read_parquet(f, columns=columns) for f in files], ignore_index=True)
|
|
109
|
+
return pd.concat([_read_windows(f, columns, window_ids) for f in files], ignore_index=True)
|
|
108
110
|
|
|
109
|
-
def load(self, split, networks=None, labels=True):
|
|
110
|
-
"""Load one split. ``labels=False`` returns only what an associator may use.
|
|
111
|
+
def load(self, split, networks=None, labels=True, scenarios=None, max_windows=None, window_ids=None):
|
|
112
|
+
"""Load one split. ``labels=False`` returns only what an associator may use.
|
|
113
|
+
|
|
114
|
+
To save memory, load only some windows: ``scenarios`` (names, e.g. ``"ev-med__noise-high"``),
|
|
115
|
+
``max_windows`` (a fixed random sample of at most this many windows per network) or
|
|
116
|
+
``window_ids``. Only the rows of those windows are read.
|
|
117
|
+
"""
|
|
111
118
|
cols = None if labels else list(INPUT_COLUMNS)
|
|
119
|
+
windows = self._read(split, "windows", networks)
|
|
120
|
+
ids = None
|
|
121
|
+
if scenarios is not None or max_windows is not None or window_ids is not None:
|
|
122
|
+
windows = _select(windows, scenarios, max_windows, window_ids)
|
|
123
|
+
ids = set(windows["window_id"])
|
|
112
124
|
s = Split(
|
|
113
|
-
windows=
|
|
114
|
-
picks=self._read(split, "picks", networks, columns=cols),
|
|
115
|
-
window_stations=self._read(split, "window_stations", networks),
|
|
125
|
+
windows=windows,
|
|
126
|
+
picks=self._read(split, "picks", networks, columns=cols, window_ids=ids),
|
|
127
|
+
window_stations=self._read(split, "window_stations", networks, window_ids=ids),
|
|
116
128
|
stations=pd.read_parquet(self.path / "stations.parquet"),
|
|
117
|
-
events=self._read(split, "events", networks) if labels else None,
|
|
129
|
+
events=self._read(split, "events", networks, window_ids=ids) if labels else None,
|
|
118
130
|
labels=labels,
|
|
119
131
|
)
|
|
120
132
|
s.release, s.name = self, split
|
|
@@ -132,6 +144,32 @@ CORE_NAME = "BEPAD-10"
|
|
|
132
144
|
CORE_NETWORKS = ["R05", "R07", "R01", "nc", "tx", "JMA", "CM", "R09", "ak", "NOA"]
|
|
133
145
|
|
|
134
146
|
|
|
147
|
+
def _select(windows, scenarios=None, max_windows=None, window_ids=None):
|
|
148
|
+
"""The windows kept by :meth:`Release.load` (scenario names, a sample per network, or ids)."""
|
|
149
|
+
if window_ids is not None:
|
|
150
|
+
windows = windows[windows["window_id"].isin(set(window_ids))]
|
|
151
|
+
if scenarios is not None:
|
|
152
|
+
windows = windows[windows["scenario"].isin([scenarios] if isinstance(scenarios, str) else scenarios)]
|
|
153
|
+
if max_windows is not None:
|
|
154
|
+
windows = (windows.groupby("network", group_keys=False)
|
|
155
|
+
.apply(lambda g: g.sample(min(len(g), max_windows), random_state=0).sort_index()))
|
|
156
|
+
return windows
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _read_windows(file, columns, window_ids, batch_size=200_000):
|
|
160
|
+
"""Rows of one parquet file whose window is in ``window_ids``, read in batches (low memory)."""
|
|
161
|
+
import pyarrow as pa
|
|
162
|
+
import pyarrow.compute as pc
|
|
163
|
+
import pyarrow.parquet as pq
|
|
164
|
+
|
|
165
|
+
pf = pq.ParquetFile(file, pre_buffer=False, buffer_size=1 << 20) # stream, do not read the file at once
|
|
166
|
+
schema = pa.schema([pf.schema_arrow.field(c) for c in columns]) if columns else pf.schema_arrow
|
|
167
|
+
ids = pa.array(sorted(window_ids), type=schema.field("window_id").type)
|
|
168
|
+
parts = [b.filter(pc.is_in(b.column("window_id"), value_set=ids))
|
|
169
|
+
for b in pf.iter_batches(batch_size=batch_size, columns=columns)]
|
|
170
|
+
return pa.Table.from_batches(parts, schema=schema).to_pandas()
|
|
171
|
+
|
|
172
|
+
|
|
135
173
|
def _networks(networks):
|
|
136
174
|
"""``"core"`` in a list of networks stands for the core networks."""
|
|
137
175
|
if networks is None:
|
|
@@ -164,7 +202,8 @@ def open(path): # noqa: A001 -- mirrors the usual `dataset.open` idiom
|
|
|
164
202
|
return Release(path)
|
|
165
203
|
|
|
166
204
|
|
|
167
|
-
def load(split="test", networks=None, labels=True, release=RELEASE, root=None, repo_id=REPO_ID
|
|
205
|
+
def load(split="test", networks=None, labels=True, release=RELEASE, root=None, repo_id=REPO_ID,
|
|
206
|
+
scenarios=None, max_windows=None, window_ids=None):
|
|
168
207
|
"""Load one split as a :class:`Split` (iterate it to get windows).
|
|
169
208
|
|
|
170
209
|
``root``: a local release folder (default: the ``BEPAD_ROOT`` environment
|
|
@@ -172,11 +211,17 @@ def load(split="test", networks=None, labels=True, release=RELEASE, root=None, r
|
|
|
172
211
|
(``repo_id``, ``release``) and cached.
|
|
173
212
|
``labels=False`` returns only what an associator may use. ``networks=["core"]``: the
|
|
174
213
|
:data:`CORE_NETWORKS`.
|
|
214
|
+
Less memory: ``scenarios`` (e.g. ``"ev-med__noise-high"``), ``max_windows`` (a fixed random
|
|
215
|
+
sample of at most this many windows per network) or ``window_ids`` (their networks are then
|
|
216
|
+
the only ones downloaded and read).
|
|
175
217
|
"""
|
|
218
|
+
if networks is None and window_ids is not None: # a window_id starts with its network: "tx.test..."
|
|
219
|
+
networks = sorted({w.split(".", 1)[0] for w in window_ids})
|
|
176
220
|
networks = _networks(networks)
|
|
177
221
|
root = root or os.environ.get("BEPAD_ROOT") # a local copy, e.g. export BEPAD_ROOT=data/releases/v0.1
|
|
178
222
|
path = Path(root) if root else download(release, splits=(split,), networks=networks, repo_id=repo_id)
|
|
179
|
-
return Release(path).load(split, networks=networks, labels=labels
|
|
223
|
+
return Release(path).load(split, networks=networks, labels=labels, scenarios=scenarios,
|
|
224
|
+
max_windows=max_windows, window_ids=window_ids)
|
|
180
225
|
|
|
181
226
|
|
|
182
227
|
def predictions_frame(window_ids, pick_idx, pred_event):
|
|
@@ -301,15 +301,13 @@ def evaluate(predictions, release, split="test", networks=None, min_shared=3, wi
|
|
|
301
301
|
if not isinstance(predictions, pd.DataFrame):
|
|
302
302
|
p = Path(predictions)
|
|
303
303
|
predictions = pd.read_parquet(p) if p.suffix == ".parquet" else pd.read_csv(p)
|
|
304
|
+
keep = set(window_ids) if window_ids is not None else None # a partial run: read only its rows
|
|
304
305
|
windows = rel._read(split, "windows", networks)
|
|
305
|
-
|
|
306
|
-
events = rel._read(split, "events", networks, columns=["window_id", "event_idx", "scorable", "latitude",
|
|
307
|
-
"longitude", "depth", "t0_rel_s"])
|
|
308
|
-
if window_ids is not None:
|
|
309
|
-
keep = set(window_ids)
|
|
306
|
+
if keep is not None:
|
|
310
307
|
windows = windows[windows.window_id.isin(keep)]
|
|
311
|
-
|
|
312
|
-
|
|
308
|
+
picks = rel._read(split, "picks", networks, columns=["window_id", "pick_idx", "event_idx"], window_ids=keep)
|
|
309
|
+
events = rel._read(split, "events", networks, columns=["window_id", "event_idx", "scorable", "latitude",
|
|
310
|
+
"longitude", "depth", "t0_rel_s"], window_ids=keep)
|
|
313
311
|
checks = check_predictions(predictions, picks)
|
|
314
312
|
if checks["n_missing_picks"]:
|
|
315
313
|
print(f"[evaluate] warning: {checks['n_missing_picks']} picks have no prediction -> counted as noise")
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|