{"id":5451,"date":"2022-03-01T06:29:01","date_gmt":"2022-03-01T06:29:01","guid":{"rendered":"https:\/\/www.aiproblog.com\/index.php\/2022\/03\/01\/command-line-arguments-for-your-python-script\/"},"modified":"2022-03-01T06:29:01","modified_gmt":"2022-03-01T06:29:01","slug":"command-line-arguments-for-your-python-script","status":"publish","type":"post","link":"https:\/\/www.aiproblog.com\/index.php\/2022\/03\/01\/command-line-arguments-for-your-python-script\/","title":{"rendered":"Command line arguments for your Python script"},"content":{"rendered":"<p>Author: Adrian Tam<\/p>\n<div>\n<p>Working on a machine learning project means we need to experiment. Having a way to configure your script easily will help you move faster. In Python, we have a way to adapt the code from command line. In this tutorial, we are going to see how we can leverage the command line arguments to a Python script to help you work better in your machine learning project.<\/p>\n<p>After finishing this tutorial, you will learn<\/p>\n<ul>\n<li>Why we would like to control a Python script in command line<\/li>\n<li>How we can work in a command line efficiently<\/li>\n<\/ul>\n<p>Let\u2019s get started.<\/p>\n<div id=\"attachment_13220\" style=\"width: 810px\" class=\"wp-caption aligncenter\">\n<img decoding=\"async\" aria-describedby=\"caption-attachment-13220\" class=\"size-full wp-image-13220\" src=\"https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/insung-yoon-Uaf6XwW4n10-unsplash-scaled.jpg\" alt=\"\" width=\"800\"><\/p>\n<p id=\"caption-attachment-13220\" class=\"wp-caption-text\">Command line arguments for your Python script. Photo by <a href=\"https:\/\/unsplash.com\/photos\/Uaf6XwW4n10\">insung yoon<\/a>. Some rights reserved<\/p>\n<\/div>\n<h2 id=\"Overview\">Overview<\/h2>\n<p>This tutorial is in three parts, they are<\/p>\n<ul>\n<li>Running a Python script in command line<\/li>\n<li>Working on the command line<\/li>\n<li>Alternative to command line arguments<\/li>\n<\/ul>\n<h2 id=\"Running-a-Python-script-in-command-line\">Running a Python script in command line<\/h2>\n<p>There are many ways to run a Python script. Someone may run it as part of a Jupyter notebook. Someone may run it in an IDE. But in all platforms, it is always possible to run a Python script in command line. In Windows, you have the command prompt or PowerShell (or even better, the\u00a0<a href=\"https:\/\/aka.ms\/terminal\">Windows Terminal<\/a>). In macOS or Linux, you have the Terminal or xterm. Running a Python script in command line is powerful because you can pass in additional parameter to the script.<\/p>\n<p>The following script allows us to pass in values from the command line into Python:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import sys\r\n\r\nn = int(sys.argv[1])\r\nprint(n+1)<\/pre>\n<p>When we save these few lines into a file, and run it in command line with an argument:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ python commandline.py 15\r\n16<\/pre>\n<p>you will see it takes our argument, convert it into integer, add one into it and print. The list\u00a0<code>sys.argv<\/code>\u00a0contains the name of our script and all the arguments (all strings), which in the above case, it is\u00a0<code>[\"commandline.py\", \"15\"]<\/code>.<\/p>\n<p>When you run a command line with more complicated set of arguments, it takes some effort to process the list\u00a0<code>sys.argv<\/code>. Therefore Python provided the library\u00a0<code>argparse<\/code> to help. This is to assume GNU-style, which can be explained using the following example:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">rsync -a -v --exclude=\"*.pyc\" -B 1024 --ignore-existing 192.168.0.3:\/tmp\/ .\/<\/pre>\n<p>The optional arguments are introduced by \u201c<code>-<\/code>\u201d or \u201c<code>--<\/code>\u201c, which a single hyphen is to carry a single character \u201cshort option\u201d (such as <code>-a<\/code>,\u00a0<code>-B<\/code>\u00a0and\u00a0<code>-v<\/code>\u00a0above), and two hyphens are for multiple characters \u201clong options\u201d (such as\u00a0<code>--exclude<\/code>\u00a0and\u00a0<code>--ignore-existing<\/code>\u00a0above). The optional arguments may have additional parameters, such as in\u00a0<code>-B 1024<\/code>\u00a0or\u00a0<code>--exclude=\"*.pyc\"<\/code>, the\u00a0<code>1024<\/code>\u00a0and\u00a0<code>\"*.pyc\"<\/code>\u00a0are parameters to\u00a0<code>-B<\/code>\u00a0and\u00a0<code>--exclude<\/code>\u00a0respectively. Additionally, we may also have compulsory arguments, which we just put them into the command line. The part\u00a0<code>192.168.0.3:\/tmp\/<\/code>\u00a0and\u00a0<code>.\/<\/code>\u00a0above are examples. The order of compulsory arguments are important. For example, the\u00a0<code>rsync<\/code>\u00a0command above will copy files from\u00a0<code>192.168.0.3:\/tmp\/<\/code>\u00a0to\u00a0<code>.\/<\/code>\u00a0instead of the other way round.<\/p>\n<p>The following is to replicate the above example in Python using argparse:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import argparse\r\n\r\nparser = argparse.ArgumentParser(description=\"Just an example\",\r\n                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)\r\nparser.add_argument(\"-a\", \"--archive\", action=\"store_true\", help=\"archive mode\")\r\nparser.add_argument(\"-v\", \"--verbose\", action=\"store_true\", help=\"increase verbosity\")\r\nparser.add_argument(\"-B\", \"--block-size\", help=\"checksum blocksize\")\r\nparser.add_argument(\"--ignore-existing\", action=\"store_true\", help=\"skip files that exist\")\r\nparser.add_argument(\"--exclude\", help=\"files to exclude\")\r\nparser.add_argument(\"src\", help=\"Source location\")\r\nparser.add_argument(\"dest\", help=\"Destination location\")\r\nargs = parser.parse_args()\r\nconfig = vars(args)\r\nprint(config)<\/pre>\n<p>If you run the above script, you will see:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ python argparse_example.py\r\nusage: argparse_example.py [-h] [-a] [-v] [-B BLOCK_SIZE] [--ignore-existing] [--exclude EXCLUDE] src dest\r\nargparse_example.py: error: the following arguments are required: src, dest<\/pre>\n<p>This is to mean you didn\u2019t provide the compulsory arguments for\u00a0<code>src<\/code>\u00a0and\u00a0<code>dest<\/code>. Perhaps the best reason to use argparse is to get a help screen for free if you provded\u00a0<code>-h<\/code>\u00a0or\u00a0<code>--help<\/code>\u00a0as the argument, like the following:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ python argparse_example.py --help\r\nusage: argparse_example.py [-h] [-a] [-v] [-B BLOCK_SIZE] [--ignore-existing] [--exclude EXCLUDE] src dest\r\n\r\nJust an example\r\n\r\npositional arguments:\r\n  src                   Source location\r\n  dest                  Destination location\r\n\r\noptional arguments:\r\n  -h, --help            show this help message and exit\r\n  -a, --archive         archive mode (default: False)\r\n  -v, --verbose         increase verbosity (default: False)\r\n  -B BLOCK_SIZE, --block-size BLOCK_SIZE\r\n                        checksum blocksize (default: None)\r\n  --ignore-existing     skip files that exist (default: False)\r\n  --exclude EXCLUDE     files to exclude (default: None)<\/pre>\n<p>While the script did nothing real, if you provided the arguments as required, you will see this:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ python argparse_example.py -a --ignore-existing 192.168.0.1:\/tmp\/ \/home\r\n{'archive': True, 'verbose': False, 'block_size': None, 'ignore_existing': True, 'exclude': None, 'src': '192.168.0.1:\/tmp\/', 'dest': '\/home'}<\/pre>\n<p>The parser object created by\u00a0<code>ArgumentParser()<\/code>\u00a0has a\u00a0<code>parse_args()<\/code>\u00a0method that reads\u00a0<code>sys.argv<\/code>\u00a0and returns a\u00a0<strong>namespace<\/strong>\u00a0object. This is an object that carries attributes and we can read using\u00a0<code>args.ignore_existing<\/code>\u00a0for example. But usually it is easier to handle if it is a Python dictionary. Hence we can convert it into one using\u00a0<code>vars(args)<\/code>.<\/p>\n<p>Usually for all optional arguments, we provide the long option and sometimes also the short option. Then we can access the value provided from the command line using the long option as the key (with hyphen replaced with underscore, or the single-character short option as the key if we don\u2019t have a long version). The \u201cpositional arguments\u201d are not optional and their names are provided in the\u00a0<code>add_argument()<\/code>\u00a0function.<\/p>\n<p>There are multiple types of arguments. For the optional arguments, sometimes we use them as a boolean flags but sometimes we expect them to bring in some data. In the above, we use\u00a0<code>action=\"store_true\"<\/code>\u00a0to make that option set to\u00a0<code>False<\/code>\u00a0by default and toggle to\u00a0<code>True<\/code>\u00a0if it is specified. For the other option such as\u00a0<code>-B<\/code>\u00a0above, by default it expects additional data to go following it.<\/p>\n<p>We can further require an argument to be a specific type. For example the\u00a0<code>-B<\/code>\u00a0option above, we can make it to expect integer data by adding\u00a0<code>type<\/code>\u00a0like the following<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">parser.add_argument(\"-B\", \"--block-size\", type=int, help=\"checksum blocksize\")<\/pre>\n<p>and if we provided the wrong type, argparse will help terminate our program with an informative error message:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">python argparse_example.py -a -B hello --ignore-existing 192.168.0.1:\/tmp\/ \/home\r\nusage: argparse_example.py [-h] [-a] [-v] [-B BLOCK_SIZE] [--ignore-existing] [--exclude EXCLUDE] src dest\r\nargparse_example.py: error: argument -B\/--block-size: invalid int value: 'hello'<\/pre>\n<\/p>\n<h2 id=\"Working-on-the-command-line\">Working on the command line<\/h2>\n<p>Empowering your Python script with command line arguments can bring it to a new level of reusability. First, let\u2019s look at a simple example on fitting an ARIMA model to GDP time series. World Bank collected historical GDP data of many countries. We can make use of the\u00a0<code>pandas_datareader<\/code>\u00a0package to read the data. If you haven\u2019t installed it yet, you can use\u00a0<code>pip<\/code>\u00a0(or\u00a0<code>conda<\/code>\u00a0if you installed Anacronda) to install the package:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">pip install pandas_datareader<\/pre>\n<p>The code for the GDP data that we use is\u00a0<code>NY.GDP.MKTP.CN<\/code>, we can get the data of a country in the form of a pandas DataFrame by<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">from pandas_datareader.wb import WorldBankReader\r\n\r\ngdp = WorldBankReader(\"NY.GDP.MKTP.CN\", \"SE\", start=1960, end=2020).read()<\/pre>\n<p>and then we can tidy up the DataFrame a bit using the tools provided by pandas:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import pandas as pd\r\n\r\n# Drop country name from index\r\ngdp = gdp.droplevel(level=0, axis=0)\r\n# Sort data in choronological order and set data point at year-end\r\ngdp.index = pd.to_datetime(gdp.index)\r\ngdp = gdp.sort_index().resample(\"y\").last()\r\n# Convert pandas DataFrame into pandas Series\r\ngdp = gdp[\"NY.GDP.MKTP.CN\"]<\/pre>\n<p>then fitting an ARIMA model and use the model for prediction is not difficult. In the following, we fit using the first 40 data points and forecast for next 3. Then compare the forecast with the actual in terms of relative error:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import statsmodels.api as sm\r\n\r\nmodel = sm.tsa.ARIMA(endog=gdp[:40], order=(1,1,1)).fit()\r\nforecast = model.forecast(steps=3)\r\ncompare = pd.DataFrame({\"actual\":gdp, \"forecast\":forecast}).dropna()\r\ncompare[\"rel error\"] = (compare[\"forecast\"] - compare[\"actual\"])\/compare[\"actual\"]\r\nprint(compare)<\/pre>\n<p>Putting it all together, and a little polishing, the following is the complete code:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import warnings\r\nwarnings.simplefilter(\"ignore\")\r\n\r\nfrom pandas_datareader.wb import WorldBankReader\r\nimport statsmodels.api as sm\r\nimport pandas as pd\r\n\r\nseries = \"NY.GDP.MKTP.CN\"\r\ncountry = \"SE\" # Sweden\r\nlength = 40\r\nstart = 0\r\nsteps = 3\r\norder = (1,1,1)\r\n\r\n# Read the GDP data from WorldBank database\r\ngdp = WorldBankReader(series, country, start=1960, end=2020).read()\r\n# Drop country name from index\r\ngdp = gdp.droplevel(level=0, axis=0)\r\n# Sort data in choronological order and set data point at year-end\r\ngdp.index = pd.to_datetime(gdp.index)\r\ngdp = gdp.sort_index().resample(\"y\").last()\r\n# Convert pandas dataframe into pandas series\r\ngdp = gdp[series]\r\n# Fit arima model\r\nresult = sm.tsa.ARIMA(endog=gdp[start:start+length], order=order).fit()\r\n# Forecast, and calculate the relative error\r\nforecast = result.forecast(steps=steps)\r\ndf = pd.DataFrame({\"Actual\":gdp, \"Forecast\":forecast}).dropna()\r\ndf[\"Rel Error\"] = (df[\"Forecast\"] - df[\"Actual\"]) \/ df[\"Actual\"]\r\n# Print result\r\nwith pd.option_context('display.max_rows', None, 'display.max_columns', 3):\r\n    print(df)<\/pre>\n<p>This script prints the following output<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">Actual      Forecast  Rel Error\r\n2000-12-31  2408151000000  2.367152e+12  -0.017025\r\n2001-12-31  2503731000000  2.449716e+12  -0.021574\r\n2002-12-31  2598336000000  2.516118e+12  -0.031643<\/pre>\n<p>The above code is short but we made it flexible enough by holding some parameters in variables. We can change the above code to use argparse so we can change some parameters from the command line, as follows:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter\r\nimport warnings\r\nwarnings.simplefilter(\"ignore\")\r\n\r\nfrom pandas_datareader.wb import WorldBankReader\r\nimport statsmodels.api as sm\r\nimport pandas as pd\r\n\r\n# Parse command line arguments\r\nparser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)\r\nparser.add_argument(\"-c\", \"--country\", default=\"SE\", help=\"Two-letter country code\")\r\nparser.add_argument(\"-l\", \"--length\", default=40, type=int, help=\"Length of time series to fit the ARIMA model\")\r\nparser.add_argument(\"-s\", \"--start\", default=0, type=int, help=\"Starting offset to fit the ARIMA model\")\r\nargs = vars(parser.parse_args())\r\n\r\n# Set up parameters\r\nseries = \"NY.GDP.MKTP.CN\"\r\ncountry = args[\"country\"]\r\nlength = args[\"length\"]\r\nstart = args[\"start\"]\r\nsteps = 3\r\norder = (1,1,1)\r\n\r\n# Read the GDP data from WorldBank database\r\ngdp = WorldBankReader(series, country, start=1960, end=2020).read()\r\n# Drop country name from index\r\ngdp = gdp.droplevel(level=0, axis=0)\r\n# Sort data in choronological order and set data point at year-end\r\ngdp.index = pd.to_datetime(gdp.index)\r\ngdp = gdp.sort_index().resample(\"y\").last()\r\n# Convert pandas dataframe into pandas series\r\ngdp = gdp[series]\r\n# Fit arima model\r\nresult = sm.tsa.ARIMA(endog=gdp[start:start+length], order=order).fit()\r\n# Forecast, and calculate the relative error\r\nforecast = result.forecast(steps=steps)\r\ndf = pd.DataFrame({\"Actual\":gdp, \"Forecast\":forecast}).dropna()\r\ndf[\"Rel Error\"] = (df[\"Forecast\"] - df[\"Actual\"]) \/ df[\"Actual\"]\r\n# Print result\r\nwith pd.option_context('display.max_rows', None, 'display.max_columns', 3):\r\n    print(df)<\/pre>\n<p>If we run the code above in a command line, we can see it can now accept arguments:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ python gdp_arima.py --help\r\nusage: gdp_arima.py [-h] [-c COUNTRY] [-l LENGTH] [-s START]\r\n\r\noptional arguments:\r\n  -h, --help            show this help message and exit\r\n  -c COUNTRY, --country COUNTRY\r\n                        Two-letter country code (default: SE)\r\n  -l LENGTH, --length LENGTH\r\n                        Length of time series to fit the ARIMA model (default: 40)\r\n  -s START, --start START\r\n                        Starting offset to fit the ARIMA model (default: 0)\r\n$ python gdp_arima.py\r\n                   Actual      Forecast  Rel Error\r\n2000-12-31  2408151000000  2.367152e+12  -0.017025\r\n2001-12-31  2503731000000  2.449716e+12  -0.021574\r\n2002-12-31  2598336000000  2.516118e+12  -0.031643\r\n$ python gdp_arima.py -c NO\r\n                   Actual      Forecast  Rel Error\r\n2000-12-31  1507283000000  1.337229e+12  -0.112821\r\n2001-12-31  1564306000000  1.408769e+12  -0.099429\r\n2002-12-31  1561026000000  1.480307e+12  -0.051709<\/pre>\n<p>In the last command above, we pass in\u00a0<code>-c NO<\/code>\u00a0to apply the same model to the GDP data of Norway (NO) instead of Sweden (SE). Hence, without the risk of messing up the code, we reused our code to a different dataset.<\/p>\n<p>The power of introducing command line argument is that we can test out our code with varying parameters easily. For example, we want to see if ARIMA(1,1,1) model is a good model for predicting GDP and we want to verify with different time window of the nordic countries:<\/p>\n<ul>\n<li>Denmark (DK)<\/li>\n<li>Finland (FI)<\/li>\n<li>Iceland (IS)<\/li>\n<li>Norway (NO)<\/li>\n<li>Sweden (SE)<\/li>\n<\/ul>\n<p>We want to check for the window of 40 years but with different starting points (since 1960, 1965, 1970, 1975). Depends on the OS, you can build a for loop in Linux and mac using the bash shell syntax:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">for C in DK FI IS NO SE; do\r\n    for S in 0 5 10 15; do\r\n        python gdp_arima.py -c $C -s $S\r\n    done\r\ndone<\/pre>\n<p>or, as the shell syntax permits, we can put everything in one line:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">for C in DK FI IS NO SE; do for S in 0 5 10 15; do python gdp_arima.py -c $C -s $S ; done ; done<\/pre>\n<p>or even better, give some information at each iteration of the loop, and we get our script run multiple times:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ for C in DK FI IS NO SE; do for S in 0 5 10 15; do echo $C $S; python gdp_arima.py -c $C -s $S ; done; done\r\nDK 0\r\n                  Actual      Forecast  Rel Error\r\n2000-12-31  1.326912e+12  1.290489e+12  -0.027449\r\n2001-12-31  1.371526e+12  1.338878e+12  -0.023804\r\n2002-12-31  1.410271e+12  1.386694e+12  -0.016718\r\nDK 5\r\n                  Actual      Forecast  Rel Error\r\n2005-12-31  1.585984e+12  1.555961e+12  -0.018931\r\n2006-12-31  1.682260e+12  1.605475e+12  -0.045644\r\n2007-12-31  1.738845e+12  1.654548e+12  -0.048479\r\nDK 10\r\n                  Actual      Forecast  Rel Error\r\n2010-12-31  1.810926e+12  1.762747e+12  -0.026605\r\n2011-12-31  1.846854e+12  1.803335e+12  -0.023564\r\n2012-12-31  1.895002e+12  1.843907e+12  -0.026963\r\n\r\n...\r\n\r\n\r\nSE 5\r\n                   Actual      Forecast  Rel Error\r\n2005-12-31  2931085000000  2.947563e+12   0.005622\r\n2006-12-31  3121668000000  3.043831e+12  -0.024934\r\n2007-12-31  3320278000000  3.122791e+12  -0.059479\r\nSE 10\r\n                   Actual      Forecast  Rel Error\r\n2010-12-31  3573581000000  3.237310e+12  -0.094099\r\n2011-12-31  3727905000000  3.163924e+12  -0.151286\r\n2012-12-31  3743086000000  3.112069e+12  -0.168582\r\nSE 15\r\n                   Actual      Forecast  Rel Error\r\n2015-12-31  4260470000000  4.086529e+12  -0.040827\r\n2016-12-31  4415031000000  4.180213e+12  -0.053186\r\n2017-12-31  4625094000000  4.273781e+12  -0.075958<\/pre>\n<p>If you\u2019re using Windows, you can use the following syntax in command prompt:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">for %C in (DK FI IS NO SE) do for %S in (0 5 10 15) do python gdp_arima.py -c $C -s $S<\/pre>\n<p>or the following in PowerShell:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">foreach ($C in \"DK\",\"FI\",\"IS\",\"NO\",\"SE\") { foreach ($S in 0,5,10,15) { python gdp_arima.py -c $C -s $S } }<\/pre>\n<p>both should produce the same result.<\/p>\n<p>While we can put similar loop inside our Python script, sometimes it is easier if we can do it at the command line. It could be more convenient when we are exploring different options. Moreover, by taking the loop outside of the Python code, we can be assured that every time we run the script is independent because we will not share any variables between iterations.<\/p>\n<h1 id=\"Alternative-to-command-line-arguments\">Alternative to command line arguments<\/h1>\n<p>Using command line arguments is not the only way to pass in data to your Python script. At least, there are several other ways too:<\/p>\n<ul>\n<li>using environment variables<\/li>\n<li>using config files<\/li>\n<\/ul>\n<p>Environment variables are features from your OS to keep small amount of data in memory. We can read environment variables in Python using the following syntax:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import os\r\nprint(os.environ[\"MYVALUE\"])<\/pre>\n<p>For example, in Linux, the above two-line script will work with the shell as follows<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">$ export MYVALUE=\"hello\"\r\n$ python show_env.py\r\nhello<\/pre>\n<p>and in Windows, the syntax inside command prompt is similar:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">C:MLM&gt; set MYVALUE=hello\r\n\r\nC:MLM&gt; python show_env.py\r\nhello<\/pre>\n<p>You may also add or edit environment variables in Windows using the dialog in Control Panel:<\/p>\n<p><a href=\"https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/Env-Variable.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"size-medium wp-image-13276 aligncenter\" src=\"https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/Env-Variable-300x237.jpg\" alt=\"\" width=\"300\" height=\"237\" srcset=\"https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/Env-Variable-300x237.jpg 300w, https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/Env-Variable-768x607.jpg 768w, https:\/\/machinelearningmastery.com\/wp-content\/uploads\/2022\/02\/Env-Variable.jpg 782w\" sizes=\"(max-width: 300px) 100vw, 300px\"><\/a><\/p>\n<p>So we may keep the parameters to the script in some environment variables and let the script adapt its behavior like setting up command line arguments.<\/p>\n<p>In case we have a lot of options to set, it is better to save the options to a file rather than overwhelming the command line. Depends on the format we chose, we can use the <code>configparser<\/code>\u00a0or\u00a0<code>json<\/code>\u00a0module from Python for reading Windows INI format or JSON format respectively. We may also use the third party library PyYAML to read YAML format.<\/p>\n<p>For the above example on running ARIMA model on GDP data, we can modify the code to use YAML config file:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import warnings\r\nwarnings.simplefilter(\"ignore\")\r\n\r\nfrom pandas_datareader.wb import WorldBankReader\r\nimport statsmodels.api as sm\r\nimport pandas as pd\r\nimport yaml\r\n\r\n# Load config from YAML file\r\nwith open(\"config.yaml\", \"r\") as fp:\r\n    args = yaml.safe_load(fp)\r\n\r\n# Set up parameters\r\nseries = \"NY.GDP.MKTP.CN\"\r\ncountry = args[\"country\"]\r\nlength = args[\"length\"]\r\nstart = args[\"start\"]\r\nsteps = 3\r\norder = (1,1,1)\r\n\r\n# Read the GDP data from WorldBank database\r\ngdp = WorldBankReader(series, country, start=1960, end=2020).read()\r\n# Drop country name from index\r\ngdp = gdp.droplevel(level=0, axis=0)\r\n# Sort data in choronological order and set data point at year-end\r\ngdp.index = pd.to_datetime(gdp.index)\r\ngdp = gdp.sort_index().resample(\"y\").last()\r\n# Convert pandas dataframe into pandas series\r\ngdp = gdp[series]\r\n# Fit arima model\r\nresult = sm.tsa.ARIMA(endog=gdp[start:start+length], order=order).fit()\r\n# Forecast, and calculate the relative error\r\nforecast = result.forecast(steps=steps)\r\ndf = pd.DataFrame({\"Actual\":gdp, \"Forecast\":forecast}).dropna()\r\ndf[\"Rel Error\"] = (df[\"Forecast\"] - df[\"Actual\"]) \/ df[\"Actual\"]\r\n# Print result\r\nwith pd.option_context('display.max_rows', None, 'display.max_columns', 3):\r\n    print(df)<\/pre>\n<p>and the YAML config file is named as\u00a0<code>config.yaml<\/code>, which its content is as follows:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">country: SE\r\nlength: 40\r\nstart: 0<\/pre>\n<p>Then we can run the above code and obtaining the same result as before. The JSON counterpart is very similar, which we use the\u00a0<code>load()<\/code>\u00a0function from\u00a0<code>json<\/code>\u00a0module:<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">import json\r\nimport warnings\r\nwarnings.simplefilter(\"ignore\")\r\n\r\nfrom pandas_datareader.wb import WorldBankReader\r\nimport statsmodels.api as sm\r\nimport pandas as pd\r\n\r\n# Load config from JSON file\r\nwith open(\"config.json\", \"r\") as fp:\r\n    args = json.load(fp)\r\n\r\n# Set up parameters\r\nseries = \"NY.GDP.MKTP.CN\"\r\ncountry = args[\"country\"]\r\nlength = args[\"length\"]\r\nstart = args[\"start\"]\r\nsteps = 3\r\norder = (1,1,1)\r\n\r\n# Read the GDP data from WorldBank database\r\ngdp = WorldBankReader(series, country, start=1960, end=2020).read()\r\n# Drop country name from index\r\ngdp = gdp.droplevel(level=0, axis=0)\r\n# Sort data in choronological order and set data point at year-end\r\ngdp.index = pd.to_datetime(gdp.index)\r\ngdp = gdp.sort_index().resample(\"y\").last()\r\n# Convert pandas dataframe into pandas series\r\ngdp = gdp[series]\r\n# Fit arima model\r\nresult = sm.tsa.ARIMA(endog=gdp[start:start+length], order=order).fit()\r\n# Forecast, and calculate the relative error\r\nforecast = result.forecast(steps=steps)\r\ndf = pd.DataFrame({\"Actual\":gdp, \"Forecast\":forecast}).dropna()\r\ndf[\"Rel Error\"] = (df[\"Forecast\"] - df[\"Actual\"]) \/ df[\"Actual\"]\r\n# Print result\r\nwith pd.option_context('display.max_rows', None, 'display.max_columns', 3):\r\n    print(df)<\/pre>\n<p>and the JSON config file,\u00a0<code>config.json<\/code>\u00a0would be<\/p>\n<pre class=\"urvanov-syntax-highlighter-plain-tag\">{\r\n    \"country\": \"SE\",\r\n    \"length\": 40,\r\n    \"start\": 0\r\n}<\/pre>\n<p>You may learn more about the syntax of\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/JavaScript\/Objects\/JSON\">JSON<\/a>\u00a0and\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/YAML\">YAML<\/a>\u00a0for your project. But the idea here is that we can separate the data and algorithm for better reusability of our code.<\/p>\n<h2 id=\"Further-reading\">Further reading<\/h2>\n<p>This section provides more resources on the topic if you are looking to go deeper.<\/p>\n<h4 id=\"Libraries\">Libraries<\/h4>\n<ul>\n<li>argparse module,\u00a0<a href=\"https:\/\/docs.python.org\/3\/library\/argparse.html\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.python.org\/3\/library\/argparse.html<\/a>\n<\/li>\n<li>Pandas Data Reader,\u00a0<a href=\"https:\/\/pandas-datareader.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"noopener\">https:\/\/pandas-datareader.readthedocs.io\/en\/latest\/<\/a>\n<\/li>\n<li>ARIMA in statsmodels,\u00a0<a href=\"https:\/\/www.statsmodels.org\/devel\/generated\/statsmodels.tsa.arima.model.ARIMA.html\" target=\"_blank\" rel=\"noopener\">https:\/\/www.statsmodels.org\/devel\/generated\/statsmodels.tsa.arima.model.ARIMA.html<\/a>\n<\/li>\n<li>configparser module,\u00a0<a href=\"https:\/\/docs.python.org\/3\/library\/configparser.html\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.python.org\/3\/library\/configparser.html<\/a>\n<\/li>\n<li>json module,\u00a0<a href=\"https:\/\/docs.python.org\/3\/library\/json.html\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.python.org\/3\/library\/json.html<\/a>\n<\/li>\n<li>PyYAML,\u00a0<a href=\"https:\/\/pyyaml.org\/wiki\/PyYAMLDocumentation\" target=\"_blank\" rel=\"noopener\">https:\/\/pyyaml.org\/wiki\/PyYAMLDocumentation<\/a>\n<\/li>\n<\/ul>\n<h4 id=\"Articles\">Articles<\/h4>\n<ul>\n<li>Working with JSON,\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/JavaScript\/Objects\/JSON\" target=\"_blank\" rel=\"noopener\">https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/JavaScript\/Objects\/JSON<\/a>\n<\/li>\n<li>YAML on Wikipedia,\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/YAML\" target=\"_blank\" rel=\"noopener\">https:\/\/en.wikipedia.org\/wiki\/YAML<\/a>\n<\/li>\n<\/ul>\n<h4 id=\"Books\">Books<\/h4>\n<ul>\n<li>Python Cookbook, third edition, by David Beazley and Brian K. Jones,\u00a0<a href=\"https:\/\/www.amazon.com\/dp\/1449340377\/\" target=\"_blank\" rel=\"noopener\">https:\/\/www.amazon.com\/dp\/1449340377\/<\/a>\n<\/li>\n<\/ul>\n<h2 id=\"Summary\">Summary<\/h2>\n<p>In this tutorial, you\u2019ve see how we can make use of the command line for more efficient control of our Python script. Specifically, you learned<\/p>\n<ul>\n<li>How we can pass in parameters to your Python script using the argparse module<\/li>\n<li>How we can efficiently control the argparse-enabled Python script in a terminal under different OS<\/li>\n<li>We can also use environment variables, or config files to pass in parameters to a Python script<\/li>\n<\/ul>\n<p>The post <a rel=\"nofollow\" href=\"https:\/\/machinelearningmastery.com\/command-line-arguments-for-your-python-script\/\">Command line arguments for your Python script<\/a> appeared first on <a rel=\"nofollow\" href=\"https:\/\/machinelearningmastery.com\/\">Machine Learning Mastery<\/a>.<\/p>\n<\/div>\n<p><a href=\"https:\/\/machinelearningmastery.com\/command-line-arguments-for-your-python-script\/\">Go to Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Author: Adrian Tam Working on a machine learning project means we need to experiment. Having a way to configure your script easily will help you [&hellip;] <span class=\"read-more-link\"><a class=\"read-more\" href=\"https:\/\/www.aiproblog.com\/index.php\/2022\/03\/01\/command-line-arguments-for-your-python-script\/\">Read More<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":5452,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"categories":[24],"tags":[],"_links":{"self":[{"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/posts\/5451"}],"collection":[{"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/comments?post=5451"}],"version-history":[{"count":0,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/posts\/5451\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/media\/5452"}],"wp:attachment":[{"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/media?parent=5451"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/categories?post=5451"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aiproblog.com\/index.php\/wp-json\/wp\/v2\/tags?post=5451"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}