{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Flux sampling" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic usage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The easiest way to get started with flux sampling is using the `sample` function in the `flux_analysis` submodule. `sample` takes at least two arguments: a cobra model and the number of samples you want to generate." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scaling...\n", " A: min|aij| = 1.000e+00 max|aij| = 1.000e+00 ratio = 1.000e+00\n", "Problem data seem to be well scaled\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ACALDACALDtACKrACONTaACONTbACt2rADK1AKGDHAKGt2rALCD2x...RPISUCCt2_2SUCCt3SUCDiSUCOASTALATHD2TKT1TKT2TPI
0-0.771296-0.431093-2.2842466.7353026.735302-2.2842462.2739303.942050-1.589360-0.340203...-2.3144166.9970028.082133335.977726-3.9420502.15298312.8503482.1529832.0880657.542984
1-2.089680-1.099843-0.38645310.47779010.477790-0.3864533.3967703.163168-1.592767-0.989837...-1.7563593.0930513.415053540.804734-3.1631681.65747956.6493681.6574791.6177158.029587
2-1.108346-0.126460-1.1986395.0578195.057819-1.1986397.1540430.313155-0.227554-0.981886...-4.4913557.8734668.606818558.331088-0.3131554.29554012.1412834.2955404.2167955.181243
3-1.239111-0.334024-1.28402312.03549912.035499-1.28402319.7902321.359155-0.007846-0.905088...-2.0638279.00280010.772472647.037371-1.3591552.01649526.6093812.0164951.9974617.712080
4-1.943290-1.571257-0.84207211.03590011.035900-0.84207215.9631630.288986-0.861444-0.372033...-1.4682567.1889978.085781368.039875-0.2889861.4656635.7308861.4656631.4646208.298285
\n", "

5 rows × 95 columns

\n", "
" ], "text/plain": [ " ACALD ACALDt ACKr ACONTa ACONTb ACt2r ADK1 \\\n", "0 -0.771296 -0.431093 -2.284246 6.735302 6.735302 -2.284246 2.273930 \n", "1 -2.089680 -1.099843 -0.386453 10.477790 10.477790 -0.386453 3.396770 \n", "2 -1.108346 -0.126460 -1.198639 5.057819 5.057819 -1.198639 7.154043 \n", "3 -1.239111 -0.334024 -1.284023 12.035499 12.035499 -1.284023 19.790232 \n", "4 -1.943290 -1.571257 -0.842072 11.035900 11.035900 -0.842072 15.963163 \n", "\n", " AKGDH AKGt2r ALCD2x ... RPI SUCCt2_2 SUCCt3 \\\n", "0 3.942050 -1.589360 -0.340203 ... -2.314416 6.997002 8.082133 \n", "1 3.163168 -1.592767 -0.989837 ... -1.756359 3.093051 3.415053 \n", "2 0.313155 -0.227554 -0.981886 ... -4.491355 7.873466 8.606818 \n", "3 1.359155 -0.007846 -0.905088 ... -2.063827 9.002800 10.772472 \n", "4 0.288986 -0.861444 -0.372033 ... -1.468256 7.188997 8.085781 \n", "\n", " SUCDi SUCOAS TALA THD2 TKT1 TKT2 TPI \n", "0 335.977726 -3.942050 2.152983 12.850348 2.152983 2.088065 7.542984 \n", "1 540.804734 -3.163168 1.657479 56.649368 1.657479 1.617715 8.029587 \n", "2 558.331088 -0.313155 4.295540 12.141283 4.295540 4.216795 5.181243 \n", "3 647.037371 -1.359155 2.016495 26.609381 2.016495 1.997461 7.712080 \n", "4 368.039875 -0.288986 1.465663 5.730886 1.465663 1.464620 8.298285 \n", "\n", "[5 rows x 95 columns]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from cobra.io import load_model\n", "from cobra.sampling import sample\n", "\n", "model = load_model(\"textbook\")\n", "s = sample(model, 100)\n", "s.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default sample uses the `optgp` method based on the [method presented here](http://dx.doi.org/10.1371/journal.pone.0086587) as it is suited for larger models and can run in parallel. By default the sampler uses a single process. This can be changed by using the `processes` argument." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "One process:\n", "CPU times: user 9.8 s, sys: 333 ms, total: 10.1 s\n", "Wall time: 9.21 s\n", "Two processes:\n", "CPU times: user 186 ms, sys: 41.2 ms, total: 227 ms\n", "Wall time: 5.26 s\n" ] } ], "source": [ "print(\"One process:\")\n", "%time s = sample(model, 1000)\n", "print(\"Two processes:\")\n", "%time s = sample(model, 1000, processes=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively you can also user Artificial Centering Hit-and-Run for sampling by setting the method to `achr`. `achr` does not support parallel execution but has good convergence and is almost Markovian." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "s = sample(model, 100, method=\"achr\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In general setting up the sampler is expensive since initial search directions are generated by solving many linear programming problems. Thus, we recommend to generate as many samples as possible in one go. However, this might require finer control over the sampling procedure as described in the following section." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced usage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sampler objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The sampling process can be controlled on a lower level by using the sampler classes directly." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from cobra.sampling import OptGPSampler, ACHRSampler" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both sampler classes have standardized interfaces and take some additional argument. For instance the `thinning` factor. \"Thinning\" means only recording samples every n iterations. A higher thinning factors mean less correlated samples but also larger computation times. By default the samplers use a thinning factor of 100 which creates roughly uncorrelated samples. If you want less samples but better mixing feel free to increase this parameter. If you want to study convergence for your own model you might want to set it to 1 to obtain all iterates." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "achr = ACHRSampler(model, thinning=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`OptGPSampler` has an additional `processes` argument specifying how many processes are used to create parallel sampling chains. This should be in the order of your CPU cores for maximum efficiency. As noted before class initialization can take up to a few minutes due to generation of initial search directions. Sampling on the other hand is quick." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "optgp = OptGPSampler(model, processes=4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sampling and validation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both samplers have a sample function that generates samples from the initialized object and act like the `sample` function described above, only that this time it will only accept a single argument, the number of samples. For `OptGPSampler` the number of samples should be a multiple of the number of processes, otherwise it will be increased to the nearest multiple automatically." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "s1 = achr.sample(100)\n", "\n", "s2 = optgp.sample(100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can call `sample` repeatedly and both samplers are optimized to generate large amount of samples without falling into \"numerical traps\". All sampler objects have a `validate` function in order to check if a set of points are feasible and give detailed information about feasibility violations in a form of a short code denoting feasibility. Here the short code is a combination of any of the following letters:\n", "\n", "- \"v\" - valid point\n", "- \"l\" - lower bound violation\n", "- \"u\" - upper bound violation\n", "- \"e\" - equality violation (meaning the point is not a steady state)\n", "\n", "For instance for a random flux distribution (should not be feasible):" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['le'], dtype=' 0.1) for s in optgp.batch(100, 10)]\n", "print(\"Usually {:.2f}% +- {:.2f}% grow...\".format(\n", " np.mean(counts) * 100.0, np.std(counts) * 100.0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding constraints" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Flux sampling will respect additional contraints defined in the model. For instance we can add a constraint enforcing growth in asimilar manner as the section before." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "co = model.problem.Constraint(model.reactions.Biomass_Ecoli_core.flux_expression, lb=0.1)\n", "model.add_cons_vars([co])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Note that this is only for demonstration purposes. usually you could set the lower bound of the reaction directly instead of creating a new constraint.*" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 0.106248\n", "1 0.116061\n", "2 0.113978\n", "3 0.179056\n", "4 0.117057\n", "5 0.111005\n", "6 0.182250\n", "7 0.114853\n", "8 0.128597\n", "9 0.160970\n", "Name: Biomass_Ecoli_core, dtype: float64\n" ] } ], "source": [ "s = sample(model, 10)\n", "print(s.Biomass_Ecoli_core)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see our new constraint was respected." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.1" } }, "nbformat": 4, "nbformat_minor": 4 }