pySEQTarget 0.10.0__tar.gz → 0.10.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.
Files changed (59) hide show
  1. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/PKG-INFO +6 -5
  2. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/README.md +5 -4
  3. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/SEQuential.py +6 -6
  4. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/__init__.py +1 -0
  5. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/_survival_pred.py +8 -0
  6. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/error/__init__.py +1 -1
  7. pyseqtarget-0.10.0/pySEQTarget/error/_datachecker.py → pyseqtarget-0.10.1/pySEQTarget/error/_data_checker.py +1 -1
  8. pyseqtarget-0.10.1/pySEQTarget/expansion/_selection.py +44 -0
  9. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_bootstrap.py +2 -1
  10. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/_weight_fit.py +2 -2
  11. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/_weight_pred.py +4 -4
  12. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget.egg-info/PKG-INFO +6 -5
  13. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget.egg-info/SOURCES.txt +1 -1
  14. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pyproject.toml +1 -1
  15. pyseqtarget-0.10.0/pySEQTarget/expansion/_selection.py +0 -31
  16. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/LICENSE +0 -0
  17. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/SEQopts.py +0 -0
  18. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/SEQoutput.py +0 -0
  19. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/__init__.py +0 -0
  20. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/_hazard.py +0 -0
  21. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/_outcome_fit.py +0 -0
  22. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/_risk_estimates.py +0 -0
  23. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/analysis/_subgroup_fit.py +0 -0
  24. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/data/__init__.py +0 -0
  25. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/error/_param_checker.py +0 -0
  26. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/expansion/__init__.py +0 -0
  27. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/expansion/_binder.py +0 -0
  28. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/expansion/_diagnostics.py +0 -0
  29. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/expansion/_dynamic.py +0 -0
  30. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/expansion/_mapper.py +0 -0
  31. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/__init__.py +0 -0
  32. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_col_string.py +0 -0
  33. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_format_time.py +0 -0
  34. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_output_files.py +0 -0
  35. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_pad.py +0 -0
  36. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_predict_model.py +0 -0
  37. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/helpers/_prepare_data.py +0 -0
  38. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/initialization/__init__.py +0 -0
  39. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/initialization/_censoring.py +0 -0
  40. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/initialization/_denominator.py +0 -0
  41. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/initialization/_numerator.py +0 -0
  42. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/initialization/_outcome.py +0 -0
  43. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/plot/__init__.py +0 -0
  44. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/plot/_survival_plot.py +0 -0
  45. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/__init__.py +0 -0
  46. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/_weight_bind.py +0 -0
  47. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/_weight_data.py +0 -0
  48. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget/weighting/_weight_stats.py +0 -0
  49. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget.egg-info/dependency_links.txt +0 -0
  50. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget.egg-info/requires.txt +0 -0
  51. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/pySEQTarget.egg-info/top_level.txt +0 -0
  52. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/setup.cfg +0 -0
  53. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_accessor.py +0 -0
  54. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_coefficients.py +0 -0
  55. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_covariates.py +0 -0
  56. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_followup_options.py +0 -0
  57. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_hazard.py +0 -0
  58. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_parallel.py +0 -0
  59. {pyseqtarget-0.10.0 → pyseqtarget-0.10.1}/tests/test_survival.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pySEQTarget
3
- Version: 0.10.0
3
+ Version: 0.10.1
4
4
  Summary: Sequentially Nested Target Trial Emulation
5
5
  Author-email: Ryan O'Dea <ryan.odea@psi.ch>, Alejandro Szmulewicz <aszmulewicz@hsph.harvard.edu>, Tom Palmer <tom.palmer@bristol.ac.uk>, Miguel Hernan <mhernan@hsph.harvard.edu>
6
6
  Maintainer-email: Ryan O'Dea <ryan.odea@psi.ch>
@@ -68,8 +68,9 @@ From the user side, this amounts to creating a dataclass, `SEQopts`, and then fe
68
68
  ```python
69
69
  import polars as pl
70
70
  from pySEQTarget import SEQuential, SEQopts
71
+ from pySEQTarget.data import load_data
71
72
 
72
- data = pl.from_pandas(SEQdata)
73
+ data = load_data("SEQdata")
73
74
  options = SEQopts(km_curves = True)
74
75
 
75
76
  # Initiate the class
@@ -77,17 +78,18 @@ model = SEQuential(data,
77
78
  id_col = "ID",
78
79
  time_col = "time",
79
80
  eligible_col = "eligible",
81
+ treatment_col = "tx_init",
82
+ outcome_col = "outcome",
80
83
  time_varying_cols = ["N", "L", "P"],
81
84
  fixed_cols = ["sex"],
82
85
  method = "ITT",
83
- options = options)
86
+ parameters = options)
84
87
  model.expand() # Construct the nested structure
85
88
  model.bootstrap(bootstrap_nboot = 20) # Run 20 bootstrap samples
86
89
  model.fit() # Fit the model
87
90
  model.survival() # Create survival curves
88
91
  model.plot() # Create and show a plot of the survival curves
89
92
  model.collect() # Collection of important information
90
-
91
93
  ```
92
94
 
93
95
  ## Assumptions
@@ -95,4 +97,3 @@ There are several key assumptions in this package -
95
97
  1. User provided `time_col` begins at 0 per unique `id_col`, we also assume this column contains only integers and continues by 1 for every time step, e.g. (0, 1, 2, 3, 4, ...) is allowed and (0, 1, 2, 2.5, ...) or (0, 1, 4, 5) are not
96
98
  1. Provided `time_col` entries may be out of order at intake as a sort is enforced at expansion.
97
99
  2. `eligible_col` and elements of `excused_colnames` are once 1, only 1 (with respect to `time_col`) flag variables.
98
-
@@ -31,8 +31,9 @@ From the user side, this amounts to creating a dataclass, `SEQopts`, and then fe
31
31
  ```python
32
32
  import polars as pl
33
33
  from pySEQTarget import SEQuential, SEQopts
34
+ from pySEQTarget.data import load_data
34
35
 
35
- data = pl.from_pandas(SEQdata)
36
+ data = load_data("SEQdata")
36
37
  options = SEQopts(km_curves = True)
37
38
 
38
39
  # Initiate the class
@@ -40,17 +41,18 @@ model = SEQuential(data,
40
41
  id_col = "ID",
41
42
  time_col = "time",
42
43
  eligible_col = "eligible",
44
+ treatment_col = "tx_init",
45
+ outcome_col = "outcome",
43
46
  time_varying_cols = ["N", "L", "P"],
44
47
  fixed_cols = ["sex"],
45
48
  method = "ITT",
46
- options = options)
49
+ parameters = options)
47
50
  model.expand() # Construct the nested structure
48
51
  model.bootstrap(bootstrap_nboot = 20) # Run 20 bootstrap samples
49
52
  model.fit() # Fit the model
50
53
  model.survival() # Create survival curves
51
54
  model.plot() # Create and show a plot of the survival curves
52
55
  model.collect() # Collection of important information
53
-
54
56
  ```
55
57
 
56
58
  ## Assumptions
@@ -58,4 +60,3 @@ There are several key assumptions in this package -
58
60
  1. User provided `time_col` begins at 0 per unique `id_col`, we also assume this column contains only integers and continues by 1 for every time step, e.g. (0, 1, 2, 3, 4, ...) is allowed and (0, 1, 2, 2.5, ...) or (0, 1, 4, 5) are not
59
61
  1. Provided `time_col` entries may be out of order at intake as a sort is enforced at expansion.
60
62
  2. `eligible_col` and elements of `excused_colnames` are once 1, only 1 (with respect to `time_col`) flag variables.
61
-
@@ -7,9 +7,10 @@ from typing import List, Literal, Optional
7
7
  import numpy as np
8
8
  import polars as pl
9
9
 
10
- from .analysis import (_calculate_hazard, _calculate_survival, _outcome_fit,
11
- _pred_risk, _risk_estimates, _subgroup_fit)
12
- from .error import _datachecker, _param_checker
10
+ from .analysis import (_calculate_hazard, _calculate_survival, _clamp,
11
+ _outcome_fit, _pred_risk, _risk_estimates,
12
+ _subgroup_fit)
13
+ from .error import _data_checker, _param_checker
13
14
  from .expansion import _binder, _diagnostics, _dynamic, _random_selection
14
15
  from .helpers import _col_string, _format_time, bootstrap_loop
15
16
  from .initialization import (_cense_denominator, _cense_numerator,
@@ -101,7 +102,7 @@ class SEQuential:
101
102
  self.cense_denominator = _cense_denominator(self)
102
103
 
103
104
  _param_checker(self)
104
- _datachecker(self)
105
+ _data_checker(self)
105
106
 
106
107
  def expand(self) -> None:
107
108
  """
@@ -190,7 +191,6 @@ class SEQuential:
190
191
  )
191
192
  id_counts = Counter(sampled_IDs)
192
193
  self._boot_samples.append(id_counts)
193
- return self
194
194
 
195
195
  @bootstrap_loop
196
196
  def fit(self) -> None:
@@ -266,7 +266,7 @@ class SEQuential:
266
266
 
267
267
  risk_data = _pred_risk(self)
268
268
  surv_data = _calculate_survival(self, risk_data)
269
- self.km_data = pl.concat([risk_data, surv_data])
269
+ self.km_data = _clamp(pl.concat([risk_data, surv_data]))
270
270
  self.risk_estimates = _risk_estimates(self)
271
271
 
272
272
  end = time.perf_counter()
@@ -3,6 +3,7 @@ from ._outcome_fit import _outcome_fit as _outcome_fit
3
3
  from ._risk_estimates import _risk_estimates as _risk_estimates
4
4
  from ._subgroup_fit import _subgroup_fit as _subgroup_fit
5
5
  from ._survival_pred import _calculate_survival as _calculate_survival
6
+ from ._survival_pred import _clamp as _clamp
6
7
  from ._survival_pred import \
7
8
  _get_outcome_predictions as _get_outcome_predictions
8
9
  from ._survival_pred import _pred_risk as _pred_risk
@@ -370,3 +370,11 @@ def _calculate_survival(self, risk_data):
370
370
  [(1 - pl.col("pred")).alias("pred"), pl.lit("survival").alias("estimate")]
371
371
  )
372
372
  return surv
373
+
374
+
375
+ def _clamp(data):
376
+ """Clamp prediction and CI columns to [0, 1] bounds."""
377
+ cols = ["pred", "LCI", "UCI"]
378
+ exists = [c for c in cols if c in data.columns]
379
+
380
+ return data.with_columns([pl.col(col).clip(0.0, 1.0) for col in exists])
@@ -1,2 +1,2 @@
1
- from ._datachecker import _datachecker as _datachecker
1
+ from ._data_checker import _data_checker as _data_checker
2
2
  from ._param_checker import _param_checker as _param_checker
@@ -1,7 +1,7 @@
1
1
  import polars as pl
2
2
 
3
3
 
4
- def _datachecker(self):
4
+ def _data_checker(self):
5
5
  check = self.data.group_by(self.id_col).agg(
6
6
  [pl.len().alias("row_count"), pl.col(self.time_col).max().alias("max_time")]
7
7
  )
@@ -0,0 +1,44 @@
1
+ import polars as pl
2
+
3
+
4
+ def _random_selection(self):
5
+ """
6
+ Handles the case where random selection is applied for data from
7
+ the __mapper -> __binder -> optionally __dynamic pipeline
8
+ """
9
+ UIDs = (
10
+ self.DT.select(
11
+ [self.id_col, "trial", f"{self.treatment_col}{self.indicator_baseline}"]
12
+ )
13
+ .with_columns(
14
+ (
15
+ pl.col(self.id_col).cast(pl.Utf8) + "_" + pl.col("trial").cast(pl.Utf8)
16
+ ).alias("trialID")
17
+ )
18
+ .filter(
19
+ pl.col(f"{self.treatment_col}{self.indicator_baseline}")
20
+ == self.treatment_level[0]
21
+ )
22
+ .unique("trialID")
23
+ .get_column("trialID")
24
+ .to_list()
25
+ )
26
+
27
+ NIDs = len(UIDs)
28
+ sample = self._rng.choice(
29
+ UIDs, size=int(self.selection_sample * NIDs), replace=False
30
+ )
31
+
32
+ self.DT = (
33
+ self.DT.with_columns(
34
+ (
35
+ pl.col(self.id_col).cast(pl.Utf8) + "_" + pl.col("trial").cast(pl.Utf8)
36
+ ).alias("trialID")
37
+ )
38
+ .filter(
39
+ pl.col("trialID").is_in(sample)
40
+ | pl.col(f"{self.treatment_col}{self.indicator_baseline}")
41
+ != self.treatment_level[0]
42
+ )
43
+ .drop("trialID")
44
+ )
@@ -58,13 +58,14 @@ def bootstrap_loop(method):
58
58
  start = time.perf_counter()
59
59
 
60
60
  results = []
61
+ original_DT = self.DT
62
+
61
63
  full = method(self, *args, **kwargs)
62
64
  results.append(full)
63
65
 
64
66
  if getattr(self, "bootstrap_nboot") > 0 and getattr(
65
67
  self, "_boot_samples", None
66
68
  ):
67
- original_DT = self.DT
68
69
  nboot = self.bootstrap_nboot
69
70
  ncores = self.ncores
70
71
  seed = getattr(self, "seed", None)
@@ -26,7 +26,7 @@ def _fit_LTFU(self, WDT):
26
26
  WDT,
27
27
  "cense_colname",
28
28
  [self.cense_numerator, self.cense_denominator],
29
- ["cense_numerator", "cense_denominator"],
29
+ ["cense_numerator_model", "cense_denominator_model"],
30
30
  "cense_eligible_colname",
31
31
  )
32
32
 
@@ -39,7 +39,7 @@ def _fit_visit(self, WDT):
39
39
  WDT,
40
40
  "visit_colname",
41
41
  [self.cense_numerator, self.cense_denominator],
42
- ["visit_numerator", "visit_denominator"],
42
+ ["visit_numerator_model", "visit_denominator_model"],
43
43
  )
44
44
 
45
45
 
@@ -150,8 +150,8 @@ def _weight_predict(self, WDT):
150
150
  .alias("numerator")
151
151
  )
152
152
  if self.cense_colname is not None:
153
- p_num = _predict_model(self, self.cense_numerator, WDT).flatten()
154
- p_denom = _predict_model(self, self.cense_denominator, WDT).flatten()
153
+ p_num = _predict_model(self, self.cense_numerator_model, WDT).flatten()
154
+ p_denom = _predict_model(self, self.cense_denominator_model, WDT).flatten()
155
155
  WDT = WDT.with_columns(
156
156
  [
157
157
  pl.Series("cense_numerator", p_num),
@@ -164,8 +164,8 @@ def _weight_predict(self, WDT):
164
164
  WDT = WDT.with_columns(pl.lit(1.0).alias("_cense"))
165
165
 
166
166
  if self.visit_colname is not None:
167
- p_num = _predict_model(self, self.visit_numerator, WDT).flatten()
168
- p_denom = _predict_model(self, self.visit_denominator, WDT).flatten()
167
+ p_num = _predict_model(self, self.visit_numerator_model, WDT).flatten()
168
+ p_denom = _predict_model(self, self.visit_denominator_model, WDT).flatten()
169
169
 
170
170
  WDT = WDT.with_columns(
171
171
  [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pySEQTarget
3
- Version: 0.10.0
3
+ Version: 0.10.1
4
4
  Summary: Sequentially Nested Target Trial Emulation
5
5
  Author-email: Ryan O'Dea <ryan.odea@psi.ch>, Alejandro Szmulewicz <aszmulewicz@hsph.harvard.edu>, Tom Palmer <tom.palmer@bristol.ac.uk>, Miguel Hernan <mhernan@hsph.harvard.edu>
6
6
  Maintainer-email: Ryan O'Dea <ryan.odea@psi.ch>
@@ -68,8 +68,9 @@ From the user side, this amounts to creating a dataclass, `SEQopts`, and then fe
68
68
  ```python
69
69
  import polars as pl
70
70
  from pySEQTarget import SEQuential, SEQopts
71
+ from pySEQTarget.data import load_data
71
72
 
72
- data = pl.from_pandas(SEQdata)
73
+ data = load_data("SEQdata")
73
74
  options = SEQopts(km_curves = True)
74
75
 
75
76
  # Initiate the class
@@ -77,17 +78,18 @@ model = SEQuential(data,
77
78
  id_col = "ID",
78
79
  time_col = "time",
79
80
  eligible_col = "eligible",
81
+ treatment_col = "tx_init",
82
+ outcome_col = "outcome",
80
83
  time_varying_cols = ["N", "L", "P"],
81
84
  fixed_cols = ["sex"],
82
85
  method = "ITT",
83
- options = options)
86
+ parameters = options)
84
87
  model.expand() # Construct the nested structure
85
88
  model.bootstrap(bootstrap_nboot = 20) # Run 20 bootstrap samples
86
89
  model.fit() # Fit the model
87
90
  model.survival() # Create survival curves
88
91
  model.plot() # Create and show a plot of the survival curves
89
92
  model.collect() # Collection of important information
90
-
91
93
  ```
92
94
 
93
95
  ## Assumptions
@@ -95,4 +97,3 @@ There are several key assumptions in this package -
95
97
  1. User provided `time_col` begins at 0 per unique `id_col`, we also assume this column contains only integers and continues by 1 for every time step, e.g. (0, 1, 2, 3, 4, ...) is allowed and (0, 1, 2, 2.5, ...) or (0, 1, 4, 5) are not
96
98
  1. Provided `time_col` entries may be out of order at intake as a sort is enforced at expansion.
97
99
  2. `eligible_col` and elements of `excused_colnames` are once 1, only 1 (with respect to `time_col`) flag variables.
98
-
@@ -18,7 +18,7 @@ pySEQTarget/analysis/_subgroup_fit.py
18
18
  pySEQTarget/analysis/_survival_pred.py
19
19
  pySEQTarget/data/__init__.py
20
20
  pySEQTarget/error/__init__.py
21
- pySEQTarget/error/_datachecker.py
21
+ pySEQTarget/error/_data_checker.py
22
22
  pySEQTarget/error/_param_checker.py
23
23
  pySEQTarget/expansion/__init__.py
24
24
  pySEQTarget/expansion/_binder.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pySEQTarget"
7
- version = "0.10.0"
7
+ version = "0.10.1"
8
8
  description = "Sequentially Nested Target Trial Emulation"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,31 +0,0 @@
1
- import polars as pl
2
-
3
-
4
- def _random_selection(self):
5
- """
6
- Handles the case where random selection is applied for data from
7
- the __mapper -> __binder -> optionally __dynamic pipeline
8
- """
9
- UIDs = (
10
- self.DT.select(
11
- [self.id_col, "trial", f"{self.treatment_col}{self.indicator_baseline}"]
12
- )
13
- .with_columns((pl.col(self.id_col) + "_" + pl.col("trial")).alias("trialID"))
14
- .filter(pl.col(f"{self.treatment_col}{self.indicator_baseline}") == 0)
15
- .unique("trialID")
16
- .to_series()
17
- .to_list()
18
- )
19
-
20
- NIDs = len(UIDs)
21
- sample = self._rng.choice(
22
- UIDs, size=int(self.selection_sample * NIDs), replace=False
23
- )
24
-
25
- self.DT = (
26
- self.DT.with_columns(
27
- (pl.col(self.id_col) + "_" + pl.col("trial")).alias("trialID")
28
- )
29
- .filter(pl.col("trialID").is_in(sample))
30
- .drop("trialID")
31
- )
File without changes
File without changes