Skip to content

Commit c4da51a

Browse files
committed
Merge branch 'develop' of https://github.com/stan-dev/cmdstanpy into develop
2 parents 8e9e68b + 26374f8 commit c4da51a

File tree

8 files changed

+134
-33
lines changed

8 files changed

+134
-33
lines changed

cmdstanpy/stanfit/gq.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ def draws_pd(
268268
vars_list = [vars]
269269
else:
270270
vars_list = vars
271+
vars_list = list(dict.fromkeys(vars_list))
271272
if (
272273
inc_warmup
273274
and not self.mcmc_sample.metadata.cmdstan_config['save_warmup']
@@ -282,7 +283,7 @@ def draws_pd(
282283
gq_cols = []
283284
mcmc_vars = []
284285
if vars is not None:
285-
for var in set(vars_list):
286+
for var in vars_list:
286287
if var in self.metadata.stan_vars_cols:
287288
for idx in self.metadata.stan_vars_cols[var]:
288289
gq_cols.append(self.column_names[idx])
@@ -295,6 +296,7 @@ def draws_pd(
295296
raise ValueError('Unknown variable: {}'.format(var))
296297
else:
297298
gq_cols = list(self.column_names)
299+
vars_list = gq_cols
298300

299301
if inc_sample and mcmc_vars:
300302
if gq_cols:
@@ -311,7 +313,7 @@ def draws_pd(
311313
)[gq_cols],
312314
],
313315
axis='columns',
314-
)
316+
)[vars_list]
315317
else:
316318
return self.mcmc_sample.draws_pd(
317319
vars=mcmc_vars, inc_warmup=inc_warmup

cmdstanpy/stanfit/mcmc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ def draws_pd(
589589
self._assemble_draws()
590590
cols = []
591591
if vars is not None:
592-
for var in set(vars_list):
592+
for var in dict.fromkeys(vars_list):
593593
if (
594594
var not in self.metadata.method_vars_cols
595595
and var not in self.metadata.stan_vars_cols

docsrc/community.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ when you start a new project.
1313
<https://github.com/teddygroves/cookiecutter-cmdstanpy-analysis>`_ A
1414
cookiecutter template for cmdstanpy-based statistical analysis projects.
1515

16+
- `cookiecutter-cmdstanpy-wrapper
17+
<https://github.com/WardBrian/cookiecutter-cmdstanpy-wrapper>`_ A
18+
cookiecutter template using Stan models in Python packages, including
19+
the ability to pre-compile the model as part of the package distribution.
20+
1621
Software
1722
--------
1823

docsrc/users-guide.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ usage of CmdStanPy.
1010
users-guide/overview
1111
users-guide/hello_world
1212
users-guide/workflow
13+
users-guide/outputs
1314
users-guide/examples

docsrc/users-guide/hello_world.rst

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,6 @@ By default, the `sample` method runs 4 sampler chains.
104104
# fit the model
105105
fit = model.sample(data=data_file)
106106
107-
Underlyingly, the CmdStan outputs are a set of per-chain
108-
`Stan CSV files <https://mc-stan.org/docs/cmdstan-guide/stan-csv.html#mcmc-sampler-csv-output>`__.
109-
The filenames follow the template '<model_name>-<YYYYMMDDHHMMSS>-<chain_id>'
110-
plus the file suffix '.csv'.
111-
CmdStanPy also captures the per-chain console and error messages.
112-
The ``output_dir`` argument is an optional argument which specifies
113-
the path to the output directory used by CmdStan.
114-
If this argument is omitted, the output files are written
115-
to a temporary directory which is deleted when the current Python session is terminated.
116-
117-
.. ipython:: python
118-
119-
# printing the object reports sampler commands, output files
120-
print(fit)
121-
122107
123108
Accessing the results
124109
^^^^^^^^^^^^^^^^^^^^^
@@ -230,18 +215,3 @@ The :meth:`~CmdStanMCMC.diagnose` method runs this utility and prints the output
230215
.. ipython:: python
231216
232217
print(fit.diagnose())
233-
234-
235-
236-
Managing Stan CSV files
237-
^^^^^^^^^^^^^^^^^^^^^^^
238-
239-
The :class:`CmdStanMCMC` object keeps track of all output files produced
240-
by the sampler run.
241-
The :meth:`~CmdStanMCMC.save_csvfiles` function moves the CSV files
242-
to a specified directory.
243-
244-
.. ipython:: python
245-
:verbatim:
246-
247-
fit.save_csvfiles(dir='some/path')

docsrc/users-guide/outputs.rst

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
.. py:currentmodule:: cmdstanpy
2+
3+
Controlling Outputs
4+
===================
5+
6+
CSV File Outputs
7+
----------------
8+
9+
Underlyingly, the CmdStan outputs are a set of per-chain
10+
`Stan CSV files <https://mc-stan.org/docs/cmdstan-guide/stan-csv.html#mcmc-sampler-csv-output>`__.
11+
The filenames follow the template '<model_name>-<YYYYMMDDHHMMSS>-<chain_id>'
12+
plus the file suffix '.csv'.
13+
CmdStanPy also captures the per-chain console and error messages.
14+
15+
.. ipython:: python
16+
17+
import os
18+
from cmdstanpy import CmdStanModel
19+
stan_file = os.path.join('users-guide', 'examples', 'bernoulli.stan')
20+
model = CmdStanModel(stan_file=stan_file)
21+
22+
data_file = os.path.join('users-guide', 'examples', 'bernoulli.data.json')
23+
fit = model.sample(data=data_file)
24+
25+
# printing the object reports sampler commands, output files
26+
print(fit)
27+
28+
The ``output_dir`` argument is an optional argument which specifies
29+
the path to the output directory used by CmdStan.
30+
If this argument is omitted, the output files are written
31+
to a temporary directory which is deleted when the current Python session is terminated.
32+
33+
.. ipython:: python
34+
35+
fit = model.sample(data=data_file, output_dir="./outputs/")
36+
37+
!ls outputs/
38+
39+
Alternatively, the :meth:`~CmdStanMCMC.save_csvfiles` function moves the CSV files
40+
to a specified directory.
41+
42+
.. ipython:: python
43+
44+
fit = model.sample(data=data_file)
45+
fit.save_csvfiles(dir='some/path')
46+
47+
!ls some/path
48+
49+
.. ipython:: python
50+
:suppress:
51+
52+
!rm -rf outputs/ some/path/
53+
54+
Logging
55+
-------
56+
57+
You may notice CmdStanPy can produce a lot of output when it is running:
58+
59+
.. ipython:: python
60+
61+
fit = model.sample(data=data_file, show_progress=False)
62+
63+
This output is managed through the built-in :mod:`logging` module. For example, it can be disabled entirely:
64+
65+
.. ipython:: python
66+
67+
import logging
68+
cmdstanpy_logger = logging.getLogger("cmdstanpy")
69+
cmdstanpy_logger.disabled = True
70+
# look, no output!
71+
fit = model.sample(data=data_file, show_progress=False)
72+
73+
Or one can remove the logging handler that CmdStanPy installs by default and install their own for more
74+
fine-grained control. For example, the following code sends all logs (including the ``DEBUG`` logs, which are hidden by default),
75+
to a file.
76+
77+
DEBUG logging is useful primarily to developers or when trying to hunt down an issue.
78+
79+
.. ipython:: python
80+
81+
cmdstanpy_logger.disabled = False
82+
# remove all existing handlers
83+
cmdstanpy_logger.handlers = []
84+
85+
cmdstanpy_logger.setLevel(logging.DEBUG)
86+
handler = logging.FileHandler('all.log')
87+
handler.setLevel(logging.DEBUG)
88+
handler.setFormatter(
89+
logging.Formatter(
90+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
91+
"%H:%M:%S",
92+
)
93+
)
94+
cmdstanpy_logger.addHandler(handler)
95+
96+
Now, if we run the model and check the contents of the file, we will see all the possible logging.
97+
98+
.. ipython:: python
99+
100+
fit = model.sample(data=data_file, show_progress=False)
101+
102+
with open('all.log','r') as logs:
103+
for line in logs.readlines():
104+
print(line.strip())
105+
106+
.. ipython:: python
107+
:suppress:
108+
109+
!rm all.log

test/test_generate_quantities.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ def test_from_csv_files(self):
8484
+ bern_gqs.draws_pd().shape[1],
8585
)
8686

87+
self.assertEqual(
88+
list(bern_gqs.draws_pd(vars=['y_rep']).columns),
89+
column_names,
90+
)
91+
8792
def test_from_csv_files_bad(self):
8893
# gq model
8994
stan = os.path.join(DATAFILES_PATH, 'bernoulli_ppc.stan')

test/test_sample.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,15 @@ def test_validate_good_run(self):
741741
self.assertEqual(fit.draws_pd(vars=['theta', 'lp__']).shape, (400, 2))
742742
self.assertEqual(fit.draws_pd(vars='theta').shape, (400, 1))
743743

744+
self.assertEqual(
745+
list(fit.draws_pd(vars=['theta', 'lp__']).columns),
746+
['theta', 'lp__']
747+
)
748+
self.assertEqual(
749+
list(fit.draws_pd(vars=['lp__', 'theta']).columns),
750+
['lp__', 'theta']
751+
)
752+
744753
summary = fit.summary()
745754
self.assertIn('5%', list(summary.columns))
746755
self.assertIn('50%', list(summary.columns))

0 commit comments

Comments
 (0)