spells-mtg 0.5.1__tar.gz → 0.5.3__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.
Potentially problematic release.
This version of spells-mtg might be problematic. Click here for more details.
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/PKG-INFO +3 -2
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/README.md +2 -1
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/pyproject.toml +1 -1
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/columns.py +15 -3
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/draft_data.py +7 -5
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/enums.py +1 -0
- spells_mtg-0.5.3/spells/extension.py +182 -0
- spells_mtg-0.5.1/spells/extension.py +0 -40
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/LICENSE +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/__init__.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/cache.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/cards.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/external.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/filter.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/manifest.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/spells/schema.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/tests/__init__.py +0 -0
- {spells_mtg-0.5.1 → spells_mtg-0.5.3}/tests/filter_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: spells-mtg
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: analaysis of 17Lands.com public datasets
|
|
5
5
|
Author-Email: Joel Barnes <oelarnes@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -294,7 +294,8 @@ summon(
|
|
|
294
294
|
columns: list[str] | None = None,
|
|
295
295
|
group_by: list[str] | None = None,
|
|
296
296
|
filter_spec: dict | None = None,
|
|
297
|
-
extensions:
|
|
297
|
+
extensions: dict[str, ColSpec] | None = None,
|
|
298
|
+
card_context: pl.DataFrame | dict[str, dict[str, Any] | None = None,
|
|
298
299
|
read_cache: bool = True,
|
|
299
300
|
write_cache: bool = True,
|
|
300
301
|
) -> polars.DataFrame
|
|
@@ -283,7 +283,8 @@ summon(
|
|
|
283
283
|
columns: list[str] | None = None,
|
|
284
284
|
group_by: list[str] | None = None,
|
|
285
285
|
filter_spec: dict | None = None,
|
|
286
|
-
extensions:
|
|
286
|
+
extensions: dict[str, ColSpec] | None = None,
|
|
287
|
+
card_context: pl.DataFrame | dict[str, dict[str, Any] | None = None,
|
|
287
288
|
read_cache: bool = True,
|
|
288
289
|
write_cache: bool = True,
|
|
289
290
|
) -> polars.DataFrame
|
|
@@ -5,7 +5,6 @@ import polars as pl
|
|
|
5
5
|
|
|
6
6
|
from spells.enums import View, ColName, ColType
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
@dataclass(frozen=True)
|
|
10
9
|
class ColSpec:
|
|
11
10
|
col_type: ColType
|
|
@@ -40,7 +39,7 @@ default_columns = [
|
|
|
40
39
|
ColName.GIH_WR,
|
|
41
40
|
]
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
_specs: dict[str, ColSpec] = {
|
|
44
43
|
ColName.NAME: ColSpec(
|
|
45
44
|
col_type=ColType.GROUP_BY,
|
|
46
45
|
views=[View.CARD],
|
|
@@ -477,6 +476,10 @@ specs: dict[str, ColSpec] = {
|
|
|
477
476
|
col_type=ColType.AGG,
|
|
478
477
|
expr=pl.col(ColName.DECK) + pl.col(ColName.SIDEBOARD),
|
|
479
478
|
),
|
|
479
|
+
ColName.NUM_IN_POOL_TOTAL: ColSpec(
|
|
480
|
+
col_type=ColType.AGG,
|
|
481
|
+
expr=pl.col(ColName.NUM_IN_POOL).sum(),
|
|
482
|
+
),
|
|
480
483
|
ColName.IN_POOL_WR: ColSpec(
|
|
481
484
|
col_type=ColType.AGG,
|
|
482
485
|
expr=(pl.col(ColName.WON_DECK) + pl.col(ColName.WON_SIDEBOARD))
|
|
@@ -555,4 +558,13 @@ specs: dict[str, ColSpec] = {
|
|
|
555
558
|
}
|
|
556
559
|
|
|
557
560
|
for item in ColName:
|
|
558
|
-
assert item in
|
|
561
|
+
assert item in _specs, f"column {item} enumerated but not specified"
|
|
562
|
+
|
|
563
|
+
class GetSpecs:
|
|
564
|
+
def __init__(self, spec_dict: dict[str, ColSpec]):
|
|
565
|
+
self._specs = spec_dict
|
|
566
|
+
def __call__(self):
|
|
567
|
+
return dict(self._specs)
|
|
568
|
+
|
|
569
|
+
get_specs = GetSpecs(_specs)
|
|
570
|
+
|
|
@@ -6,7 +6,6 @@ Aggregate dataframes containing raw counts are cached in the local file system
|
|
|
6
6
|
for performance.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
import datetime
|
|
10
9
|
import functools
|
|
11
10
|
import hashlib
|
|
12
11
|
import re
|
|
@@ -20,7 +19,7 @@ from spells.external import data_file_path
|
|
|
20
19
|
import spells.cache
|
|
21
20
|
import spells.filter
|
|
22
21
|
import spells.manifest
|
|
23
|
-
from spells.columns import ColDef, ColSpec
|
|
22
|
+
from spells.columns import ColDef, ColSpec, get_specs
|
|
24
23
|
from spells.enums import View, ColName, ColType
|
|
25
24
|
|
|
26
25
|
|
|
@@ -356,16 +355,19 @@ def summon(
|
|
|
356
355
|
columns: list[str] | None = None,
|
|
357
356
|
group_by: list[str] | None = None,
|
|
358
357
|
filter_spec: dict | None = None,
|
|
359
|
-
extensions: dict[str, ColSpec] | None = None,
|
|
358
|
+
extensions: dict[str, ColSpec] | list[dict[str, ColSpec]] | None = None,
|
|
360
359
|
use_streaming: bool = False,
|
|
361
360
|
read_cache: bool = True,
|
|
362
361
|
write_cache: bool = True,
|
|
363
362
|
card_context: pl.DataFrame | dict[str, dict] | None = None
|
|
364
363
|
) -> pl.DataFrame:
|
|
365
|
-
specs =
|
|
364
|
+
specs = get_specs()
|
|
366
365
|
|
|
367
366
|
if extensions is not None:
|
|
368
|
-
|
|
367
|
+
if not isinstance(extensions, list):
|
|
368
|
+
extensions = [extensions]
|
|
369
|
+
for ext in extensions:
|
|
370
|
+
specs.update(ext)
|
|
369
371
|
|
|
370
372
|
col_def_map = _hydrate_col_defs(set_code, specs, card_context)
|
|
371
373
|
m = spells.manifest.create(col_def_map, columns, group_by, filter_spec)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import polars as pl
|
|
4
|
+
|
|
5
|
+
from spells.enums import ColType, ColName
|
|
6
|
+
from spells.columns import ColSpec
|
|
7
|
+
from spells.cache import spells_print
|
|
8
|
+
|
|
9
|
+
def print_ext(ext: dict[str, ColSpec]) -> None:
|
|
10
|
+
spells_print("create", "Created extensions:")
|
|
11
|
+
for key in ext:
|
|
12
|
+
print("\t" + key)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def attr_cols(attr, silent=False) -> dict[str, ColSpec]:
|
|
16
|
+
ext = {
|
|
17
|
+
f"seen_{attr}": ColSpec(
|
|
18
|
+
col_type=ColType.NAME_SUM,
|
|
19
|
+
expr=(lambda name, card_context: pl.lit(None) if card_context[name][attr] is None or math.isnan(card_context[name][attr]) else pl.when(pl.col(f"pack_card_{name}") > 0)
|
|
20
|
+
.then(card_context[name][attr])
|
|
21
|
+
.otherwise(None)),
|
|
22
|
+
),
|
|
23
|
+
f"pick_{attr}": ColSpec(
|
|
24
|
+
col_type=ColType.PICK_SUM,
|
|
25
|
+
expr=lambda name, card_context: pl.lit(None) if card_context[name][attr] is None or math.isnan(card_context[name][attr]) else card_context[name][attr]
|
|
26
|
+
),
|
|
27
|
+
f"seen_{attr}_greater": ColSpec(
|
|
28
|
+
col_type=ColType.NAME_SUM,
|
|
29
|
+
expr=lambda name: pl.col(f"seen_{attr}_{name}") > pl.col(f"pick_{attr}"),
|
|
30
|
+
),
|
|
31
|
+
f"seen_{attr}_less": ColSpec(
|
|
32
|
+
col_type=ColType.NAME_SUM,
|
|
33
|
+
expr=lambda name: pl.col(f"seen_{attr}_{name}") < pl.col(f"pick_{attr}"),
|
|
34
|
+
),
|
|
35
|
+
f"greatest_{attr}_seen": ColSpec(
|
|
36
|
+
col_type=ColType.PICK_SUM,
|
|
37
|
+
expr=lambda names: pl.max_horizontal([pl.col(f"seen_{attr}_{name}") for name in names]),
|
|
38
|
+
),
|
|
39
|
+
f"least_{attr}_seen": ColSpec(
|
|
40
|
+
col_type=ColType.PICK_SUM,
|
|
41
|
+
expr=lambda names: pl.min_horizontal([pl.col(f"seen_{attr}_{name}") for name in names]),
|
|
42
|
+
),
|
|
43
|
+
f"pick_{attr}_rank_greatest": ColSpec(
|
|
44
|
+
col_type=ColType.GROUP_BY,
|
|
45
|
+
expr=lambda names: pl.sum_horizontal([pl.col(f"seen_{attr}_greater_{name}") for name in names]) + 1,
|
|
46
|
+
),
|
|
47
|
+
f"pick_{attr}_rank_least": ColSpec(
|
|
48
|
+
col_type=ColType.GROUP_BY,
|
|
49
|
+
expr=lambda names: pl.sum_horizontal([pl.col(f"seen_{attr}_less_{name}") for name in names]) + 1,
|
|
50
|
+
),
|
|
51
|
+
f"pick_{attr}_rank_greatest_sum": ColSpec(
|
|
52
|
+
col_type=ColType.PICK_SUM,
|
|
53
|
+
expr=pl.col(f"pick_{attr}_rank_greatest")
|
|
54
|
+
),
|
|
55
|
+
f"pick_{attr}_rank_least_sum": ColSpec(
|
|
56
|
+
col_type=ColType.PICK_SUM,
|
|
57
|
+
expr=pl.col(f"pick_{attr}_rank_least")
|
|
58
|
+
),
|
|
59
|
+
f"pick_{attr}_vs_least": ColSpec(
|
|
60
|
+
col_type=ColType.PICK_SUM,
|
|
61
|
+
expr=pl.col(f"pick_{attr}") - pl.col(f"least_{attr}_seen"),
|
|
62
|
+
),
|
|
63
|
+
f"pick_{attr}_vs_greatest": ColSpec(
|
|
64
|
+
col_type=ColType.PICK_SUM,
|
|
65
|
+
expr=pl.col(f"pick_{attr}") - pl.col(f"greatest_{attr}_seen"),
|
|
66
|
+
),
|
|
67
|
+
f"pick_{attr}_vs_least_mean": ColSpec(
|
|
68
|
+
col_type=ColType.AGG,
|
|
69
|
+
expr=pl.col(f"pick_{attr}_vs_least") / pl.col(ColName.NUM_TAKEN),
|
|
70
|
+
),
|
|
71
|
+
f"pick_{attr}_vs_greatest_mean": ColSpec(
|
|
72
|
+
col_type=ColType.AGG,
|
|
73
|
+
expr=pl.col(f"pick_{attr}_vs_greatest") / pl.col(ColName.NUM_TAKEN),
|
|
74
|
+
),
|
|
75
|
+
f"least_{attr}_taken": ColSpec(
|
|
76
|
+
col_type=ColType.PICK_SUM,
|
|
77
|
+
expr=pl.col(f'pick_{attr}') <= pl.col(f'least_{attr}_seen'),
|
|
78
|
+
),
|
|
79
|
+
f"least_{attr}_taken_rate": ColSpec(
|
|
80
|
+
col_type=ColType.AGG,
|
|
81
|
+
expr=pl.col(f"least_{attr}_taken") / pl.col(ColName.NUM_TAKEN),
|
|
82
|
+
),
|
|
83
|
+
f"greatest_{attr}_taken": ColSpec(
|
|
84
|
+
col_type=ColType.PICK_SUM,
|
|
85
|
+
expr=pl.col(f'pick_{attr}') >= pl.col(f"greatest_{attr}_seen")
|
|
86
|
+
),
|
|
87
|
+
f"greatest_{attr}_taken_rate": ColSpec(
|
|
88
|
+
col_type=ColType.AGG,
|
|
89
|
+
expr=pl.col(f"greatest_{attr}_taken") / pl.col(ColName.NUM_TAKEN),
|
|
90
|
+
),
|
|
91
|
+
f"pick_{attr}_mean": ColSpec(
|
|
92
|
+
col_type=ColType.AGG,
|
|
93
|
+
expr=pl.col(f"pick_{attr}") / pl.col(ColName.NUM_TAKEN)
|
|
94
|
+
),
|
|
95
|
+
f"{attr}_deck_weight_group": ColSpec(
|
|
96
|
+
col_type=ColType.AGG,
|
|
97
|
+
expr=pl.col(f"{attr}") * pl.col(ColName.DECK)
|
|
98
|
+
),
|
|
99
|
+
f"{attr}_deck_weight_total": ColSpec(
|
|
100
|
+
col_type=ColType.AGG,
|
|
101
|
+
expr=pl.col(f"{attr}_deck_weight_group").sum()
|
|
102
|
+
),
|
|
103
|
+
f"{attr}_dw_mean": ColSpec(
|
|
104
|
+
col_type=ColType.AGG,
|
|
105
|
+
expr=pl.col(f"{attr}_deck_weight_total") / pl.col(ColName.DECK_TOTAL),
|
|
106
|
+
),
|
|
107
|
+
f"{attr}_dw_excess": ColSpec(
|
|
108
|
+
col_type=ColType.AGG,
|
|
109
|
+
expr=pl.col(f"{attr}_dw_mean") - pl.col(f"{attr}"),
|
|
110
|
+
),
|
|
111
|
+
f"{attr}_dw_var": ColSpec(
|
|
112
|
+
col_type=ColType.AGG,
|
|
113
|
+
expr=(pl.col(f"{attr}_dw_excess").pow(2) * pl.col(ColName.DECK)) / pl.col(ColName.DECK_TOTAL),
|
|
114
|
+
),
|
|
115
|
+
f"{attr}_dw_stdev": ColSpec(
|
|
116
|
+
col_type=ColType.AGG,
|
|
117
|
+
expr=pl.col(f"{attr}_dw_var").sqrt(),
|
|
118
|
+
),
|
|
119
|
+
f"{attr}_dwz": ColSpec(
|
|
120
|
+
col_type=ColType.AGG,
|
|
121
|
+
expr=pl.col(f"{attr}_dw_excess") / pl.col(f"{attr}_dw_stdev"),
|
|
122
|
+
),
|
|
123
|
+
f"{attr}_pool_weight_group": ColSpec(
|
|
124
|
+
col_type=ColType.AGG,
|
|
125
|
+
expr=pl.col(f"{attr}") * pl.col(ColName.NUM_IN_POOL)
|
|
126
|
+
),
|
|
127
|
+
f"{attr}_pool_weight_total": ColSpec(
|
|
128
|
+
col_type=ColType.AGG,
|
|
129
|
+
expr=pl.col(f"{attr}_pool_weight_group").sum()
|
|
130
|
+
),
|
|
131
|
+
f"{attr}_pw_mean": ColSpec(
|
|
132
|
+
col_type=ColType.AGG,
|
|
133
|
+
expr=pl.col(f"{attr}_pool_weight_total") / pl.col(ColName.NUM_IN_POOL_TOTAL),
|
|
134
|
+
),
|
|
135
|
+
f"{attr}_pw_excess": ColSpec(
|
|
136
|
+
col_type=ColType.AGG,
|
|
137
|
+
expr=pl.col(f"{attr}_pw_mean") - pl.col(f"{attr}"),
|
|
138
|
+
),
|
|
139
|
+
f"{attr}_pw_var": ColSpec(
|
|
140
|
+
col_type=ColType.AGG,
|
|
141
|
+
expr=(pl.col(f"{attr}_pw_excess").pow(2) * pl.col(ColName.NUM_IN_POOL)) / pl.col(ColName.NUM_IN_POOL_TOTAL),
|
|
142
|
+
),
|
|
143
|
+
f"{attr}_pw_stdev": ColSpec(
|
|
144
|
+
col_type=ColType.AGG,
|
|
145
|
+
expr=pl.col(f"{attr}_pw_var").sqrt(),
|
|
146
|
+
),
|
|
147
|
+
f"{attr}_pwz": ColSpec(
|
|
148
|
+
col_type=ColType.AGG,
|
|
149
|
+
expr=pl.col(f"{attr}_pw_excess") / pl.col(f"{attr}_pw_stdev"),
|
|
150
|
+
),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if not silent:
|
|
154
|
+
print_ext(ext)
|
|
155
|
+
|
|
156
|
+
return ext
|
|
157
|
+
|
|
158
|
+
def more(silent=True):
|
|
159
|
+
wr_bucket = pl.col(ColName.USER_GAME_WIN_RATE_BUCKET)
|
|
160
|
+
gp_bucket = pl.col(ColName.USER_N_GAMES_BUCKET)
|
|
161
|
+
ext = {
|
|
162
|
+
'deq_base': ColSpec(
|
|
163
|
+
col_type=ColType.AGG,
|
|
164
|
+
expr=(pl.col("gp_wr_excess") + 0.03 * (1 - pl.col("ata") / 14).pow(2)) * pl.col("pct_gp")
|
|
165
|
+
),
|
|
166
|
+
'cohorts_plus': ColSpec(
|
|
167
|
+
col_type=ColType.GROUP_BY,
|
|
168
|
+
expr=pl.when((wr_bucket > 0.65) & (gp_bucket >= 500)).then(pl.lit('1 Best')).otherwise(
|
|
169
|
+
pl.when((wr_bucket > 0.61) & (gp_bucket >= 500) | (wr_bucket > 0.65) & (gp_bucket >= 100)).then(pl.lit('2 Elite')).otherwise(
|
|
170
|
+
pl.when((wr_bucket > 0.57) & (gp_bucket >= 100) | (wr_bucket > 0.61)).then(pl.lit('3 Competitive')).otherwise(
|
|
171
|
+
pl.when((wr_bucket > 0.53) & (gp_bucket >= 100) | (wr_bucket > 0.57)).then(pl.lit('4 Solid')).otherwise(pl.lit('5 None'))
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if not silent:
|
|
179
|
+
print_ext(ext)
|
|
180
|
+
|
|
181
|
+
return ext
|
|
182
|
+
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import polars as pl
|
|
2
|
-
|
|
3
|
-
from spells.enums import ColType
|
|
4
|
-
from spells.columns import ColSpec
|
|
5
|
-
|
|
6
|
-
def attr_metrics(attr):
|
|
7
|
-
return {
|
|
8
|
-
f"seen_{attr}": ColSpec(
|
|
9
|
-
col_type=ColType.NAME_SUM,
|
|
10
|
-
expr=(lambda name, card_context: pl.when(pl.col(f"pack_card_{name}") > 0)
|
|
11
|
-
.then(card_context[name][attr])
|
|
12
|
-
.otherwise(None)),
|
|
13
|
-
),
|
|
14
|
-
f"pick_{attr}": ColSpec(
|
|
15
|
-
col_type=ColType.PICK_SUM,
|
|
16
|
-
expr=lambda name, card_context: card_context[name][attr]
|
|
17
|
-
),
|
|
18
|
-
f"least_{attr}_taken": ColSpec(
|
|
19
|
-
col_type=ColType.PICK_SUM,
|
|
20
|
-
expr=(lambda names: pl.col(f'pick_{attr}')
|
|
21
|
-
<= pl.min_horizontal([pl.col(f"seen_{attr}_{name}") for name in names])),
|
|
22
|
-
),
|
|
23
|
-
f"least_{attr}_taken_rate": ColSpec(
|
|
24
|
-
col_type=ColType.AGG,
|
|
25
|
-
expr=pl.col(f"least_{attr}_taken") / pl.col("num_taken"),
|
|
26
|
-
),
|
|
27
|
-
f"greatest_{attr}_taken": ColSpec(
|
|
28
|
-
col_type=ColType.PICK_SUM,
|
|
29
|
-
expr=(lambda names: pl.col(f'pick_{attr}')
|
|
30
|
-
>= pl.max_horizontal([pl.col(f"seen_{attr}_{name}") for name in names])),
|
|
31
|
-
),
|
|
32
|
-
f"greatest_{attr}_taken_rate": ColSpec(
|
|
33
|
-
col_type=ColType.AGG,
|
|
34
|
-
expr=pl.col(f"greatest_{attr}_taken") / pl.col("num_taken"),
|
|
35
|
-
),
|
|
36
|
-
f"pick_{attr}_mean": ColSpec(
|
|
37
|
-
col_type=ColType.AGG,
|
|
38
|
-
expr=pl.col(f"pick_{attr}") / pl.col("num_taken")
|
|
39
|
-
)
|
|
40
|
-
}
|
|
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
|