{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# General Applied Math" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "Working with math is perhaps the most common task in any kind of geoscience workflow in Python. This notebook will cover:\n", "\n", "- Python `math` vs. `numpy`\n", "- Mathematical Constants\n", "- Trigonmetric and Hyperbolic Functions\n", "- Algebraic Functions\n", "- Degrees and Radians\n", "- Rounding\n", "- Exponents and Logarithms\n", "- Sorting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `math` vs. `numpy`\n", "\n", "`math` is a built-in part of the standard Python library. This is a useful module for common and simple computations when working with single input values. To work with arrays or large datasets, `numpy` is a good alternative to the `math` module. `numpy` is a powerful external Python package for working with arrays and mathematical functions. `numpy` is package developed to work with scientific computing and math functions and is tailored to run much faster with large datasets and arrays." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "

Important Note

\n", " The math library cannot be used with complex numbers. Instead, equivalent functions can be found within the standard Python cmath library\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mathematical Constants\n", "\n", "Fixed mathematical constants are built into the standard Python libraries as well as external packages like `numpy`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `pi`\n", "\n", "`pi` represents the ratio of a cicle's circumferences to its diameter" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "print(f\"(numpy) pi = {np.pi}\")\n", "print(f\"(standard library) pi = {math.pi}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `e`\n", "`e` is the base of the natural logarithm" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "print(f\"(numpy) e = {np.e}\")\n", "print(f\"(standard library) e = {math.e}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Trigonmetric and Hyperbolic Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `sin`, `cos`, and `tan`\n", "\n", "The functions `sin`, `cos`, and `tan` are part of the standard Python `math` library when working with single value inputs. When working with lists and arrays, these functions can be evaluated with the external package `numpy`. By default, the input and output values are in radians." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 3.14\n", "print(\"Single Value input\")\n", "print(f\"\\tsin (math) = {math.sin(input)}\")\n", "print(f\"\\tsin (numpy) = {np.sin(input)}\")\n", "print(f\"\\tcos (math) = {math.cos(input)}\")\n", "print(f\"\\tcos (numpy) = {np.cos(input)}\")\n", "print(f\"\\ttan (math) = {math.tan(input)}\")\n", "print(f\"\\ttan (numpy) = {np.tan(input)}\")\n", "\n", "inputs = [1.2, 2.3, 3.14]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\tsin (numpy) = {np.sin(inputs)}\")\n", "print(f\"\\tcos (numpy) = {np.cos(inputs)}\")\n", "print(f\"\\ttan (numpy) = {np.tan(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `cosecant`, `secant`, and `cotangent`\n", "The functions `csc`, `sec`, and `cot` are **not** part of the standard Python `math` library or `numpy`. Instead, these values can be found as the reciprocal of the values `sin`, `cos`, and `tan`\n", "\n", "```\n", "csc = 1 / sin\n", "\n", "sec = 1 / cos\n", "\n", "cot = 1 / tan\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 3.14\n", "print(\"Single Value input\")\n", "print(f\"\\tcsc (math) = {1 / math.sin(input)}\")\n", "print(f\"\\tcsc (numpy) = {1 / np.sin(input)}\")\n", "print(f\"\\tsec (math) = {1 / math.cos(input)}\")\n", "print(f\"\\tsec (numpy) = {1 / np.cos(input)}\")\n", "print(f\"\\tcot (math) = {1 / math.tan(input)}\")\n", "print(f\"\\tcot (numpy) = {1 / np.tan(input)}\")\n", "\n", "inputs = [1.2, 2.3, 3.14]\n", "print(\"\\Multiple Value Input (array/list)\")\n", "print(f\"\\tcsc (numpy) = {1 / np.sin(inputs)}\")\n", "print(f\"\\tsec (numpy) = {1 / np.cos(inputs)}\")\n", "print(f\"\\tcot (numpy) = {1 / np.tan(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `asin`, `acos`, `atan`, and `atan2`\n", "\n", "The inverse trigonometric functions `asin`, `acos`, `atan`, and `atan2` are part of the standard Python `math` library when working with single value inputs. When working with lists and arrays, these functions can be evaluated with the external package `numpy`. By default, the input and output values are in radians." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 0.5\n", "print(\"Single Value input\")\n", "print(f\"\\tasin (math) = {math.asin(input)}\")\n", "print(f\"\\tasin (numpy) = {np.arcsin(input)}\")\n", "print(f\"\\tacos (math) = {math.acos(input)}\")\n", "print(f\"\\tacos (numpy) = {np.arccos(input)}\")\n", "print(f\"\\tatan (math) = {math.atan(input)}\")\n", "print(f\"\\tatan (numpy) = {np.arctan(input)}\")\n", "\n", "inputs = [0.5, 0.75, 0.14]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\tasin (numpy) = {np.arcsin(inputs)}\")\n", "print(f\"\\tacos (numpy) = {np.arccos(inputs)}\")\n", "print(f\"\\tatan (numpy) = {np.arctan(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `sinh`, `cosh`, and `tanh`\n", "\n", "The hyperbolic trigonometric functions are analogous functions that make use of the hyperbola instead of the circle. The trigonometric functions `sinh`, `cosh`, and `tanh` are part of the standard Python `math` library when working with single value inputs. When working with lists and arrays, these functions can be evaluated with the external package `numpy`. By default, the input and output values are in radians." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 3.14\n", "print(\"Single Value input\")\n", "print(f\"\\tsinh (math) = {math.sinh(input)}\")\n", "print(f\"\\tsinh (numpy) = {np.sinh(input)}\")\n", "print(f\"\\tcosh (math) = {math.cosh(input)}\")\n", "print(f\"\\tcosh (numpy) = {np.cosh(input)}\")\n", "print(f\"\\ttanh (math) = {math.tanh(input)}\")\n", "print(f\"\\ttanh (numpy) = {np.tanh(input)}\")\n", "\n", "inputs = [1.2, 2.3, 3.14]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\tsinh (numpy) = {np.sinh(inputs)}\")\n", "print(f\"\\tcosh (numpy) = {np.cosh(inputs)}\")\n", "print(f\"\\ttanh (numpy) = {np.tanh(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `asinh`, `acosh`, and `atanh`\n", "\n", "The inverse hyperbolic trigonmetric functions `asinh`, `acosh`, and `atanh` are part of the standard Python `math` library when working with single value inputs. When working with lists and arrays, these functions can be evaluated with the external package `numpy`. By default, the input and output values are in radians." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 3.14\n", "print(\"Single Value input\")\n", "print(f\"\\tasinh (math) = {math.asinh(input)}\")\n", "print(f\"\\tasinh (numpy) = {np.arcsinh(input)}\")\n", "print(f\"\\tacosh (math) = {math.acosh(input)}\")\n", "print(f\"\\tacosh (numpy) = {np.arccosh(input)}\")\n", "input = 0.5\n", "print(f\"\\tatanh (math) = {math.atanh(input)}\")\n", "print(f\"\\tatanh (numpy) = {np.arctanh(input)}\")\n", "\n", "inputs = [1.5, 1.75, 3.14]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\tasinh (numpy) = {np.arcsinh(inputs)}\")\n", "print(f\"\\tacosh (numpy) = {np.arccosh(inputs)}\")\n", "inputs = [0.5, 0.75, 0.14]\n", "print(f\"\\tatanh (numpy) = {np.arctanh(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Algebraic Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `sum` and `prod`\n", "\n", "To find the sum or product of a list of values, Python include `sum` and `prod` as part of the standard Python library and are also available as well as part of the `numpy` library" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = [1.2, 2.3, 3.4, 4.5]\n", "print(\"sum of input\")\n", "print(f\"\\tsum (standard library) = {sum(input)}\")\n", "print(f\"\\tsum (numpy) = {np.sum(input)}\")\n", "\n", "print(\"\\nproduct of input\")\n", "print(f\"\\tprod (math) = {math.prod(input)}\")\n", "print(f\"\\tprod (numpy) = {np.prod(input)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `cumsum` and `cumprod`\n", "\n", "The `numpy` package can be used to find the cumulative sum or product of a list of values." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "input = [[1, 2, 3], [4, 5, 6]]\n", "print(\"cumulative sum\")\n", "print(f\"\\tcumsum (numpy) = {np.cumsum(input)}\")\n", "\n", "print(\"\\ncumulative product\")\n", "print(f\"\\tcumprod (numpy) = {np.cumprod(input)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `abs`\n", "\n", "The standard Python `math` module includes the function to find the absolute value of a single value. When working with lists and arrays, the values can be evaluated with the external package `numpy`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "input = -3.14\n", "print(\"Single Value input\")\n", "print(f\"\\t(numpy) {input} = {np.abs(input)}\")\n", "print(f\"\\t(standard library) {input} = {abs(input)}\")\n", "\n", "inputs = [-1.5, -1.75, -3.14]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\t(numpy) {inputs} = {np.abs(inputs)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `avg`\n", "\n", "When working with multiple values, the external `numpy` package can be used to evaluated the average value across the list of values." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "input_value = [1, 2, 3]\n", "print(\"Single List\")\n", "print(f\"\\t{input_value} = {np.average(input_value)}\")\n", "\n", "print(\"List of Lists - Flattened to a Single List\")\n", "input_values = [[1, 2, 3], [4, 5, 6]]\n", "print(f\"\\t{input_values} = {np.mean(input_values)}\")\n", "\n", "print(\"List of Lists\")\n", "input_values = [[1, 2, 3], [4, 5, 6]]\n", "print(f\"\\t{input_values} = {np.mean(input_values, axis=1)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `mod`\n", "\n", "The modulo operator (`%`) can be used to return the remainder from dividing values.\n", "\n", "```\n", "x1 mod x2 = x1 % x2\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "x1 = 17\n", "x2 = 3\n", "print(\"Single Value input\")\n", "print(f\"\\t(standard library) {x1} % {x2} = {x1 % x2}\")\n", "print(f\"\\t(numpy) {x1} mod {x2} = {np.mod(x1, x2)}\")\n", "\n", "x1_values = [17, 4]\n", "x2_values = [3, 2]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\t(numpy) {x1_values} mod {x2_values} = {np.mod(x1_values, x2_values)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Degrees and Radians\n", "\n", "The input and output values of trigonometric functions like `sin` and `cos` expect radians. Python allows for various functions to convert between radian and degree values, both has part of the standard Python `math` library and the external `numpy` package when working with arrays." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 32 # degrees\n", "print(\"Convert from Degrees to Radians\")\n", "print(f\"\\t(math) {input} degrees = {math.radians(input)} radians\")\n", "print(f\"\\t(numpy) {input} degrees = {np.deg2rad(input)} radians\")\n", "print(f\"\\t(numpy) {input} degrees = {np.radians(input)} raidans\")\n", "\n", "input = 0.5585 # radians\n", "print(\"\\nConvert from Radians to Degrees\")\n", "print(f\"\\t(math) {input} radians = {math.degrees(input)} degrees\")\n", "print(f\"\\t(numpy) {input} radians = {np.rad2deg(input)} degrees\")\n", "print(f\"\\t(numpy) {input} radians = {np.degrees(input)} degrees\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Rounding\n", "\n", "Python includes functions to round off a decimal point value to a desired accuracy, either by rounding up, rounding down, or by manually truncating the decimal value." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `round`, `around`, `floor`, `ceil`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "input = 3.1415926535\n", "\n", "print(\"Rounding Up\")\n", "print(f\"\\t(math) {input} to next nearest integer = {math.ceil(input)}\")\n", "print(f\"\\t(numpy) {input} to 3 decimal points = {np.around(input, 3)}\")\n", "\n", "print(\"\\nRounding Down\")\n", "print(f\"\\t(math) {input} to nearest integer = {math.floor(input)}\")\n", "\n", "print(\"\\nRound to Closest Integer\")\n", "print(f\"\\t(standard library) {input} to closest integer = {round(input)}\")\n", "print(f\"\\t(standard library) {input} to closest integer = {int(input)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `truncate`\n", "\n", "Truncate will cut off the decimal points after a certain value, without rounding up or down" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "input = 3.1415926535\n", "\n", "# Truncate decimal points after 3 points\n", "decimal_values = str(input).split(\".\")\n", "truncate_decimal = decimal_values[1][:3]\n", "truncate_output = float(decimal_values[0] + \".\" + truncate_decimal)\n", "print(truncate_output)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exponents and Logarithms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `exp`\n", "\n", "Raise e (e approximately = 2.71828) to a given power x\n", "\n", "```\n", "exp(x) = e^x\n", "```\n", "\n", "The exponential is both part of the standard Python `math` library for single values and can be calculated for multiple values in a list with `numpy`" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Single Value input\n", "\t(math) e^3.2 = 24.532530197109352\n", "\t(numpy) e^3.2 = 24.532530197109352\n", "\n", "Multiple Value Input (array/list)\n", "\t(numpy) e^[1.2, 2.2, 3.2] = [ 3.32011692 9.0250135 24.5325302 ]\n" ] } ], "source": [ "import math\n", "import numpy as np\n", "\n", "power = 3.2\n", "print(\"Single Value input\")\n", "print(f\"\\t(math) e^{power} = {math.exp(power)}\")\n", "print(f\"\\t(numpy) e^{power} = {np.exp(power)}\")\n", "\n", "power_list = [1.2, 2.2, 3.2]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(f\"\\t(numpy) e^{power_list} = {np.exp(power_list)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `log`, `log10`, and `log2`\n", "\n", "Python includes many different functions to calculate the logarithm with various bases of a given value, with the standard Python `math` library for single values and the arrays/lists with `numpy`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "import numpy as np\n", "\n", "print(\"Single Value input (Base 10)\")\n", "input = 3.2\n", "base = 10\n", "print(f\"\\tlog base 10 of {input} (math.log10) = {math.log10(input)}\")\n", "print(f\"\\tlog base {base} of {input} (math.log) = {math.log(input, base)}\")\n", "print(f\"\\tlog base 10 of {input} (np.log10) = {np.log10(input)}\")\n", "\n", "print(\"\\nSingle Value input (Base 2)\")\n", "input = 3.2\n", "base = 2\n", "print(f\"\\tlog base 2 of {input} (math.log2) = {math.log2(input)}\")\n", "print(f\"\\tlog base {base} of {input} (math.log) = {math.log(input, base)}\")\n", "print(f\"\\tlog base 2 of {input} (np.log2) = {np.log2(input)}\")\n", "\n", "print(\"\\nSingle Value input (Base e)\")\n", "input = 3.2\n", "base = math.e\n", "print(f\"\\tlog base e of {input} (math.log) = {math.log(input)}\")\n", "print(f\"\\tlog base e of {input} (math.log) = {math.log(input, base)}\")\n", "print(f\"\\tlog base e of {input} (np.log) = {np.log(input)}\")\n", "\n", "input_list = [1.2, 2.2, 3.2]\n", "print(\"\\nMultiple Value Input (array/list)\")\n", "print(\"\\tBase 10\")\n", "print(f\"\\t\\tlog10 (np.log10) = {np.log10(input_list)}\")\n", "print(\"\\tBase 2\")\n", "print(f\"\\t\\tlog2 (np.log2) = {np.log2(input_list)}\")\n", "print(\"\\tBase e\")\n", "print(f\"\\t\\tlog (np.log) = {np.log(input_list)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sorting\n", "\n", "Python includes functions to organize and sort lists of numbers or strings\n", "\n", "Functions to sort lists and arrays are part of the standard Python library as well as `numpy`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sorting in Python and Numpy\n", "Python has two similar sorting functions: [`list.sort()` and `sorted()`](https://docs.python.org/3/howto/sorting.html)\n", "\n", "`list.sort()` reorganizes a numerical or string list in-place, but returns `None`, while `sorted()` creates a new copy of the list with the sorted elements.\n", "\n", "```\n", "lst = [2, 1, 3]\n", "lst.sort()\n", "print(lst)\n", ">> [1, 2, 3]\n", "print(lst.sort())\n", ">> None\n", "\n", "lst = [2, 1, 3]\n", "new_sorted_list = sorted(lst)\n", "print(lst)\n", ">> [2, 1, 3]\n", "print(new_sorted_list)\n", ">> [1, 2, 3]\n", "```\n", "\n", "The `numpy.sort()` function works like the `sorted` function, which creates and returns a sorted array of the original list\n", "\n", "```\n", "import numpy as np\n", "lst = [2, 1, 3]\n", "new_sorted_list = np.sort(lst)\n", "print(lst)\n", ">> [2, 1, 3]\n", "print(new_sorted_list)\n", ">> [1 2 3]\n", "```" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "List of Strings\n", "\t(standard library) = ['cheese', 'egg', 'mango', 'milkshake', 'taco', 'tea']\n", "\t(numpy) = ['cheese' 'egg' 'mango' 'milkshake' 'taco' 'tea']\n", "\n", "List of Numbers\n", "\t(standard library) = [-1.2, 0.2, 3.14, 10, 49, 100]\n", "\t(numpy) = [ -1.2 0.2 3.14 10. 49. 100. ]\n" ] } ], "source": [ "import numpy as np\n", "\n", "input_values = [\"mango\", \"egg\", \"taco\", \"tea\", \"milkshake\", \"cheese\"]\n", "print(\"List of Strings\")\n", "print(f\"\\t(standard library) = {sorted(input_values)}\")\n", "print(f\"\\t(numpy) = {np.sort(input_values)}\")\n", "\n", "print(\"\\nList of Numbers\")\n", "input_values = [3.14, -1.2, 0.2, 10, 100, 49]\n", "print(f\"\\t(standard library) = {sorted(input_values)}\")\n", "print(f\"\\t(numpy) = {np.sort(input_values)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Curated Resources\n", "\n", "To learn more about working with math in Python, we suggest:\n", "\n", "- [Built-in Python Functions](https://docs.python.org/3/library/functions.html)\n", "- [Standard Built-In Python `math` module](https://docs.python.org/3/library/math.html)\n", "- [Python `cmath` when working with complex mathematics](https://docs.python.org/3/library/cmath.html)\n", "- [Additional mathematical `numpy` functions](https://numpy.org/doc/stable/reference/routines.math.html)\n", "- [Python Sorting Techniques](https://docs.python.org/3/howto/sorting.html)" ] } ], "metadata": { "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.11.8" } }, "nbformat": 4, "nbformat_minor": 4 }