tpattern 0.1.0__tar.gz → 0.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.
Files changed (31) hide show
  1. {tpattern-0.1.0/tpattern.egg-info → tpattern-0.1.2}/PKG-INFO +7 -2
  2. {tpattern-0.1.0 → tpattern-0.1.2}/README.md +6 -1
  3. {tpattern-0.1.0 → tpattern-0.1.2}/pyproject.toml +1 -1
  4. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/__init__.py +1 -1
  5. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/advisor.py +83 -1
  6. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/detect.py +35 -8
  7. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/significance.py +8 -2
  8. {tpattern-0.1.0 → tpattern-0.1.2/tpattern.egg-info}/PKG-INFO +7 -2
  9. {tpattern-0.1.0 → tpattern-0.1.2}/LICENSE +0 -0
  10. {tpattern-0.1.0 → tpattern-0.1.2}/setup.cfg +0 -0
  11. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_calibrated_pins.py +0 -0
  12. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_contrast.py +0 -0
  13. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_dedup.py +0 -0
  14. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_guided.py +0 -0
  15. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_reproduction.py +0 -0
  16. {tpattern-0.1.0 → tpattern-0.1.2}/tests/test_synthetic.py +0 -0
  17. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/ci.py +0 -0
  18. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/contrast.py +0 -0
  19. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/diagnostics.py +0 -0
  20. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/guided.py +0 -0
  21. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/io.py +0 -0
  22. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/methods.py +0 -0
  23. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/pattern.py +0 -0
  24. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/randomise.py +0 -0
  25. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/report.py +0 -0
  26. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/synthetic.py +0 -0
  27. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern/viz.py +0 -0
  28. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern.egg-info/SOURCES.txt +0 -0
  29. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern.egg-info/dependency_links.txt +0 -0
  30. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern.egg-info/requires.txt +0 -0
  31. {tpattern-0.1.0 → tpattern-0.1.2}/tpattern.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tpattern
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Open, auditable temporal & sequential pattern analysis (T-patterns) for sport and behaviour
5
5
  Author-email: Andrew Callaway <acallaway@bournemouth.ac.uk>
6
6
  License: MIT
@@ -75,7 +75,12 @@ model and clear reporting:
75
75
 
76
76
  ## Installation
77
77
 
78
- From source (until published on PyPI):
78
+ ```bash
79
+ pip install tpattern
80
+ ```
81
+
82
+ Add the guided-wizard extras with `pip install tpattern[gui]`. To work from source
83
+ instead (for development or to run the reproduction scripts and shipped data):
79
84
 
80
85
  ```bash
81
86
  git clone https://github.com/ajcallaway/TPattern.git
@@ -39,7 +39,12 @@ model and clear reporting:
39
39
 
40
40
  ## Installation
41
41
 
42
- From source (until published on PyPI):
42
+ ```bash
43
+ pip install tpattern
44
+ ```
45
+
46
+ Add the guided-wizard extras with `pip install tpattern[gui]`. To work from source
47
+ instead (for development or to run the reproduction scripts and shipped data):
43
48
 
44
49
  ```bash
45
50
  git clone https://github.com/ajcallaway/TPattern.git
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tpattern"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "Open, auditable temporal & sequential pattern analysis (T-patterns) for sport and behaviour"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -19,7 +19,7 @@ from .methods import methods_text
19
19
  from .guided import run_analysis, launch
20
20
  from .contrast import group_contrast, contrast_items
21
21
 
22
- __version__ = "0.1.0"
22
+ __version__ = "0.1.2"
23
23
 
24
24
  __all__ = [
25
25
  "Observation", "read_observation", "read_sample", "read_table",
@@ -191,5 +191,87 @@ def recommend(observations, *, min_count: int = 15,
191
191
  evidence={"n_obs": n_obs},
192
192
  )
193
193
 
194
+ # --- Frequent-event exclusion (a detection-time choice; matches Config.freq_exclude) ---
195
+ # A near-ubiquitous event type links to almost everything, so it acts as a universal
196
+ # connector and inflates the pattern hierarchy. The default excludes any type whose mean
197
+ # occurrences per observation exceed 1.50 from *building* patterns (they stay in Level 0).
198
+ # This is consequential, so the advisor surfaces it rather than leaving it a silent default.
199
+ threshold = 1.50
200
+ totals: dict[str, int] = {}
201
+ for o in observations:
202
+ for _, ev in o.events:
203
+ totals[ev] = totals.get(ev, 0) + 1
204
+ means = {ev: totals[ev] / n_obs for ev in totals} if n_obs else {}
205
+ frequent = sorted((ev for ev, m in means.items() if m > threshold),
206
+ key=lambda e: -means[e])
207
+ if frequent:
208
+ lst = ", ".join(f"{e} ({means[e]:.2f}/obs)" for e in frequent)
209
+ freq_choice = Choice(
210
+ "Frequent-event exclusion",
211
+ f"exclude {len(frequent)} type(s) from pattern-building (default)",
212
+ rationale=(f"{len(frequent)} event type(s) occur more than {threshold} times per "
213
+ f"observation on average and are excluded by default from building "
214
+ f"multi-event patterns (they remain in the Level-0 univariate set): "
215
+ f"{lst}. Excluding a near-ubiquitous event stops it acting as a universal "
216
+ f"connector and inflating the hierarchy; retaining it "
217
+ f"(Config(exclude_events=[]), or a higher freq_exclude) keeps its "
218
+ f"connector patterns at the cost of combinatorial growth. Because this "
219
+ f"materially changes the pattern set, it is reported here rather than "
220
+ f"applied silently."),
221
+ plain=("<b>Very common events are set aside from pattern-building.</b> An event that "
222
+ "happens many times in almost every sequence (here: " + ", ".join(frequent) +
223
+ ") links to nearly everything, so leaving it in would flood the results with "
224
+ "patterns that are really just 'this common event, then anything'. By default "
225
+ "we keep such events in the counts but not in the built patterns. <i>Why it "
226
+ "matters:</i> it keeps the patterns meaningful; if that event is central to "
227
+ "your question you can choose to keep it in."),
228
+ evidence={"threshold": threshold, "frequent": {e: means[e] for e in frequent}},
229
+ )
230
+ else:
231
+ freq_choice = Choice(
232
+ "Frequent-event exclusion", "none needed",
233
+ rationale=(f"No event type exceeds {threshold} occurrences per observation on "
234
+ f"average, so none is excluded from pattern-building."),
235
+ plain=("No single event is common enough to swamp the patterns, so every event type "
236
+ "is kept in the analysis."),
237
+ evidence={"threshold": threshold, "frequent": {}},
238
+ )
239
+
240
+ # --- Minimum occurrence (detection floor; matches Config.min_occurrence) ---
241
+ min_occ_choice = Choice(
242
+ "Minimum occurrence", "3 (the field floor)",
243
+ rationale=("A pattern is kept only if it recurs at least this many times (default 3, the "
244
+ "T-pattern convention); below three occurrences the occurrence-based surrogate "
245
+ "test is too coarse to calibrate. Impact of raising it: fewer but "
246
+ "better-supported patterns — it removes the near-threshold tail (which "
247
+ "calibration discards anyway) and shrinks the multiple-comparison family, at "
248
+ "the cost of missing genuinely rare structure. Lowering it below three is not "
249
+ "recommended."),
250
+ plain=("<b>How many times a chain must repeat to count.</b> The default is three. "
251
+ "<i>Raise it</i> to report only patterns that recur often and drop rare, borderline "
252
+ "ones; <i>lowering</i> is not advised — two or three occurrences is already the "
253
+ "smallest number the chance test can judge."),
254
+ evidence={"min_occurrence": 3, "n_obs": n_obs},
255
+ )
256
+
257
+ # --- Number of surrogates B (Monte-Carlo resolution; matches calibrate's B) ---
258
+ B_choice = Choice(
259
+ "Number of surrogates (B)", "200 to screen; thousands to confirm one pattern",
260
+ rationale=("The Monte-Carlo empirical p-value cannot fall below 1/(B+1), so B sets the "
261
+ "finest significance any single pattern can reach. B=200 is ample for "
262
+ "false-discovery screening; a family-wise confirmatory claim needs 1/(B+1) "
263
+ "below the family threshold alpha/m — i.e. B greater than m/alpha — which for a "
264
+ "typical pattern family is in the thousands. Impact of raising B: a lower "
265
+ "p-floor and a smoother empirical p, at a runtime cost that grows linearly in "
266
+ "B; too small a B silently caps significance and can leave a real pattern "
267
+ "unconfirmable."),
268
+ plain=("<b>How many reshuffled datasets to test against.</b> More surrogates give a finer, "
269
+ "more trustworthy p-value but are proportionally slower. <i>Use about 200</i> to "
270
+ "screen many patterns; <i>raise into the thousands</i> to confirm one specific "
271
+ "pattern, because the smallest possible p-value is 1 divided by (B+1)."),
272
+ evidence={"floor_at_200": 1/201, "floor_at_2000": 1/2001},
273
+ )
274
+
194
275
  return Recommendation(n_obs=n_obs, n_events=n_events,
195
- choices=[null_choice, lag_choice, err_choice])
276
+ choices=[freq_choice, min_occ_choice, null_choice, lag_choice,
277
+ err_choice, B_choice])
@@ -42,17 +42,44 @@ from .pattern import Instance, Pattern
42
42
  @dataclass
43
43
  class Config:
44
44
  """Detection settings. The defaults reproduce THEME's parameters, so most users
45
- change only a couple of things:
45
+ change only a couple of things. Every field below is user-editable; each carries
46
+ a mathematical reason to change it and a consequence if you do — stated here and,
47
+ for the data-driven ones, advised from your data by ``advisor.recommend``.
48
+
49
+ Data-driven (let ``advisor.recommend(observations)`` set these, with reasons):
46
50
 
47
51
  * ``min_lag`` — set to 1 on frame-coded data (video timestamps), where events
48
52
  sharing a timestamp are co-occurrence, not sequence. Default 0 = THEME's
49
- behaviour (co-timing allowed).
50
- * ``freq_exclude`` the frequent-event exclusion (mean occurrences per
51
- observation above which a type is barred from building patterns).
52
-
53
- Not sure what to pick? ``advisor.recommend(observations)`` inspects the data and
54
- suggests ``min_lag`` (and the null / error control used at ``calibrate``), with
55
- the reasoning. Everything else can be left at its default.
53
+ behaviour. Impact: at 0, co-timed events read as directional sequences
54
+ (Δt = 0 has no defined order spurious patterns); at 1 they are reported as
55
+ co-occurrence instead.
56
+ * ``freq_exclude`` — mean occurrences per observation above which a type is
57
+ barred from *building* patterns. Impact: raise/disable to keep a near-ubiquitous
58
+ connector (risking combinatorial growth of the hierarchy); lower to exclude more
59
+ types. The excluded type is still counted at Level 0.
60
+ * ``min_occurrence`` — fewest times a chain must recur to be kept. Impact: below
61
+ ~3 the occurrence test is too coarse to calibrate; raise it to drop the rare,
62
+ near-threshold tail and shrink the multiple-comparison family.
63
+
64
+ Documented defaults (sensible as-is; change only with a specific reason):
65
+
66
+ * ``alpha`` — threshold on the critical-interval binomial-tail p that accepts a
67
+ time window. Impact: lower → tighter, fewer windows; higher → more candidate
68
+ structure. Final significance comes from ``calibrate``, so this mainly ranks
69
+ strength, not truth.
70
+ * ``lumping_factor`` — treat B as part of A (and drop it from further search)
71
+ when the forward conditional prob N_AB/N_A exceeds this. Impact: set 0.7–1.0 on
72
+ dense data to bound combinatorial blow-up; None (default) keeps every pair
73
+ separate.
74
+ * ``min_samples_frac`` — a pattern must occur in at least this fraction of
75
+ observations (anti-monotone support; pruned during the search). Impact: set
76
+ (e.g. 0.1) to require patterns be widespread rather than one-offs.
77
+ * ``exclude_events`` — explicit include/exclude list; overrides the frequency
78
+ rule. Impact: force-keep a central event or force-drop a nuisance one by hand;
79
+ ``[]`` disables exclusion entirely.
80
+
81
+ The null and the error-rate control (FDR q-target, family-wise α) are set at
82
+ ``calibrate`` — see its docstring for their maths and impact.
56
83
  """
57
84
 
58
85
  alpha: float = 0.005 # Significance Level
@@ -134,10 +134,16 @@ def calibrate(observations, config: Config | None = None, *,
134
134
  "rotation"/"shuffle" are THEME-style nulls.
135
135
  B : int
136
136
  Number of surrogate datasets. The empirical p-value cannot fall below
137
- 1/(B+1), so family-wise (FWER) claims need B in the thousands; FDR is fine
138
- at B=200.
137
+ 1/(B+1), so family-wise (FWER) claims need B > m/alpha (m = patterns tested,
138
+ typically thousands); FDR is fine at B=200. Impact: too small silently caps
139
+ significance — a genuine pattern cannot clear the correction floor; larger B
140
+ gives a finer p at a runtime cost linear in B.
139
141
  alpha, q_target : float
140
142
  Family-wise level (Holm) and false-discovery target (Benjamini-Hochberg).
143
+ Impact: lower q_target → fewer, safer FDR survivors; lower alpha → very few
144
+ confirmatory FWER patterns (raise alpha to 0.05 for the conventional bar).
145
+ FDR flags more (a few flukes) and is for screening; FWER flags fewer, very
146
+ safely, and is for a single confirmatory claim.
141
147
  seed : int
142
148
  Fixes the surrogate draw, so results are reproducible.
143
149
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tpattern
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Open, auditable temporal & sequential pattern analysis (T-patterns) for sport and behaviour
5
5
  Author-email: Andrew Callaway <acallaway@bournemouth.ac.uk>
6
6
  License: MIT
@@ -75,7 +75,12 @@ model and clear reporting:
75
75
 
76
76
  ## Installation
77
77
 
78
- From source (until published on PyPI):
78
+ ```bash
79
+ pip install tpattern
80
+ ```
81
+
82
+ Add the guided-wizard extras with `pip install tpattern[gui]`. To work from source
83
+ instead (for development or to run the reproduction scripts and shipped data):
79
84
 
80
85
  ```bash
81
86
  git clone https://github.com/ajcallaway/TPattern.git
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