{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "0", "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "# mypy: disable-error-code=\"no-untyped-def, no-untyped-call, assignment\"\n", "# pyright: reportUnusedExpression=false\n", "\n", "# set cache directory\n", "import os\n", "from pathlib import Path\n", "\n", "p = Path.cwd()\n", "for _ in range(100):\n", " if p.name == \"cmomy\":\n", " break\n", " p = p.parent\n", "\n", "os.environ[\"NUMBA_CACHE_DIR\"] = str(p / \".numba_cache\")" ] }, { "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "# Why `cmomy`?\n", "\n", "$$\\newcommand{\\ave}[1]{\\langle{#1}\\rangle}$$\n", "\n", "We wish to calculate moments of the form $\\ave{x}$ and $\\ave{(\\delta x)^k}$, $\\delta x = (x - \\ave{x})$, where, in general we define averages\n", "of the form.\n", "\n", "$$\n", " \\ave{x} = \\frac{\\sum_i w_i x_i}{\\sum_i w_i}\n", "$$\n", "$$\n", " \\ave{(\\delta x)^k} = \\frac{\\sum_i w_i (x_i - \\ave{x})^k}{\\sum_i w_i}\n", "$$\n", "\n", "where $w_i$ are weights associated with each sample $x_i$. In the simple case, $w_i = 1$. To calculate a central moment with $k > 1$, we have some choices. \n", "\n", "1. First calculate $\\ave{x}$, then use the above formula.\n", "* Downside: requires two passes through the data. \n", "* Upside: numerically stable.\n", " \n", "2. Expand out the central moment to raw moments. For example $\\ave{(x - \\ave{x})^2} = \\ave{x^n} - \\ave{x}^2$. These raw moments can be calculated directly in one pass. \n", "* Downside: numerically unstable ([see here for some info](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance)). \n", "* Upside: single pass for each of $\\ave{x^k}$.\n", "\n", "\n", "## An example\n", "\n", " \n", "\n", "In what follows, we'll arrange data in the from `output[moment]` where `output[0] = {total weight}`, `output[1] = {average value}`, `output[k > 1] = {kth order central moment}`. We can generate the central moments using the following functions" ] }, { "cell_type": "code", "execution_count": 2, "id": "2", "metadata": {}, "outputs": [], "source": [ "def cmom_1(x, axis=0, mom=3):\n", " \"\"\"Create central moments using stable method\"\"\"\n", " # output shape\n", " shape = x.shape[:axis] + x.shape[axis + 1 :] + (mom + 1,)\n", " output = np.zeros(shape, dtype=x.dtype)\n", "\n", " output[..., 0] = x.shape[axis]\n", " output[..., 1] = x.mean(axis=axis)\n", "\n", " # moments [2 -> mom]\n", " output[..., 2:] = (\n", " (x - x.mean(axis=axis, keepdims=True))[..., None] ** np.arange(2, mom + 1)\n", " ).mean(axis=axis)\n", " return output\n", "\n", "\n", "def cmom_2(x, axis=0, mom=3):\n", " if mom > 3:\n", " raise ValueError\n", "\n", " shape = x.shape[:axis] + x.shape[axis + 1 :] + (mom + 1,)\n", "\n", " output = np.zeros(shape, dtype=x.dtype)\n", "\n", " output[..., 0] = x.shape[axis]\n", "\n", " # higher order raw moments\n", " raws = (x[..., None] ** np.arange(0, mom + 1)).mean(axis=axis)\n", "\n", " output[..., 1] = raws[..., 1]\n", " if mom > 1:\n", " # <(x - )**2> = - **2\n", " output[..., 2] = raws[..., 2] - raws[..., 1] ** 2\n", "\n", " if mom > 2:\n", " # <(x - )**3> = - 3 + 2**3\n", " output[..., 3] = (\n", " raws[..., 3] - 3 * raws[..., 2] * raws[..., 1] + 2 * raws[..., 1] ** 3\n", " )\n", "\n", " return output" ] }, { "cell_type": "code", "execution_count": 3, "id": "3", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "rng = np.random.default_rng(seed=0)\n", "\n", "n = 1000\n", "x = rng.random(n)\n", "\n", "m1 = cmom_1(x)\n", "m2 = cmom_2(x)\n", "# same values\n", "np.testing.assert_allclose(m1, m2)" ] }, { "cell_type": "code", "execution_count": 4, "id": "4", "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "np.set_printoptions(precision=4)" ] }, { "cell_type": "markdown", "id": "5", "metadata": {}, "source": [ "OK, great. But what if we have unscaled data? For example, setting $y = a x + b$ gives $\\ave{y} = a \\ave{x} + b$, but for central moments, $\\ave{(y - \\ave{y})^n} = \\ave{(a x - b - \\ave{a x - b})^n} = a^n \\ave{(\\delta x)^n}$" ] }, { "cell_type": "code", "execution_count": 5, "id": "6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "abs error using central moments: [ 0.0000e+00 -1.8190e-12 -8.8373e-16 3.5155e-15]\n", "rel error using central moments: [ 0.0000e+00 -1.8190e-16 -1.0912e-12 -1.6856e-09]\n", "abs error using raw moments : [ 0.0000e+00 7.2760e-12 -7.2259e-08 9.7865e-04]\n", "rel error using raw moments : [ 0.0000e+00 7.2759e-16 -8.9221e-05 -4.6925e+02]\n", "\n" ] } ], "source": [ "# large value, small fluctuation\n", "a = 0.1\n", "b = 1e4\n", "y = a * x + b\n", "\n", "# expected value after shift\n", "expected = m1.copy()\n", "expected[..., 1] = a * expected[..., 1] + b\n", "expected[..., 2:] *= a ** np.arange(2, 4)\n", "\n", "\n", "m1_shift = cmom_1(y)\n", "m2_shift = cmom_2(y)\n", "\n", "m1_error = m1_shift - expected\n", "m2_error = m2_shift - expected\n", "\n", "print(\n", " f\"\"\"\n", "abs error using central moments: {m1_error}\n", "rel error using central moments: {m1_error / expected}\n", "abs error using raw moments : {m2_error}\n", "rel error using raw moments : {m2_error / expected}\n", "\"\"\"\n", ")" ] }, { "cell_type": "markdown", "id": "7", "metadata": {}, "source": [ "## So what?\n", "\n", "OK, so central moments have some advantages. But the two pass thing makes life difficult. For example, what if we are running a slow experiment or simulation? We could collect all the samples for `x`, then do the two pass algorithm at the end. But it would be nice to calculate averages on the fly. This is why we often turn to raw moments. There easy to accumulate as data comes in, while central moments, at least as formulated above, are not. \n", "\n", "Thankfully, smart people have figured out how to calculate central moments in a one-pass way. Moreover, these methods allow central moments to be combined. This makes resampling from central moments possible. We don't go into detail on these formulas, but point the interested reader to the this [article](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance), and citations within.\n", "\n", "The `cmomy` package has a variety of routines to work with central moments. This include\n", "\n", "* Create central moments accumulator object in a variety of ways.\n", "* add data to object\n", "* resample data\n", "* extract central and raw moments\n", "\n", "\n", "The primary object for doing all this is {class}`~cmomy.CentralMoments`." ] }, { "cell_type": "code", "execution_count": 6, "id": "8", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([ 1.0000e+03,  5.1691e-01,  8.0989e-02, -2.0856e-03])
" ], "text/plain": [ "\n", "array([ 1.0000e+03, 5.1691e-01, 8.0989e-02, -2.0856e-03])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import cmomy\n", "\n", "cx = cmomy.CentralMoments.from_vals(x, axis=0, mom=3)\n", "cy = cmomy.CentralMoments.from_vals(y, axis=0, mom=3)\n", "\n", "\n", "cx" ] }, { "cell_type": "markdown", "id": "9", "metadata": {}, "source": [ "You can access the underlying data using the {attr}`cmomy.CentralMoments.values` or {attr}`cmomy.CentralMoments.data` attributes." ] }, { "cell_type": "code", "execution_count": 7, "id": "10", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 1.0000e+03 5.1691e-01 8.0989e-02 -2.0856e-03]\n" ] } ], "source": [ "print(cx.values)" ] }, { "cell_type": "markdown", "id": "11", "metadata": {}, "source": [ "Basically, the {class}`~cmomy.CentralMoments` object is just a collection of routines around {attr}`~cmomy.CentralMoments.data`, which is an array of central moments (with the convention that `data[..., 0]` is the total `weight`, `data[..., 1]` is the average, and `data[..., k > 1]` is the `kth` central moment). It gives the same results as calculating central moments directly:" ] }, { "cell_type": "code", "execution_count": 8, "id": "12", "metadata": {}, "outputs": [], "source": [ "np.testing.assert_allclose(cx.values, m1)\n", "np.testing.assert_allclose(cy.values, m1_shift)" ] }, { "cell_type": "markdown", "id": "13", "metadata": {}, "source": [ "Nice! But what can that's not all that special. The real power comes in for multidimensional data.\n", "Suppose that we have separate samples of the data $\\{x_a, x_b, ... \\}$, and want to get there central moments. We can do the following." ] }, { "cell_type": "code", "execution_count": 9, "id": "14", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1.0000e+02, 4.7703e-01, 8.6779e-02, -2.0776e-03, 1.3134e-02],\n", " [ 1.0000e+02, 4.7149e-01, 8.9923e-02, 4.1844e-06, 1.3357e-02],\n", " [ 1.0000e+02, 4.9054e-01, 8.3374e-02, 6.0526e-03, 1.2658e-02],\n", " [ 1.0000e+02, 5.0095e-01, 9.1982e-02, -1.1610e-03, 1.4399e-02],\n", " [ 1.0000e+02, 5.1960e-01, 9.1251e-02, -2.4683e-03, 1.4763e-02]])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = rng.random((100, 5))\n", "m1 = cmom_1(x, axis=0, mom=4)\n", "m1" ] }, { "cell_type": "markdown", "id": "15", "metadata": {}, "source": [ "Wrapping the data in a central moments object gives" ] }, { "cell_type": "code", "execution_count": 10, "id": "16", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[5.0000e+02 4.9192e-01 8.8959e-02 1.3873e-04 1.3778e-02]\n", "[5.0000e+02 4.9192e-01 8.8959e-02 1.3873e-04 1.3778e-02]\n" ] } ], "source": [ "c = cmomy.CentralMoments(m1, mom_ndim=1)\n", "\n", "# reduce the data along a dimension to get\n", "\n", "print(c.reduce(axis=0).values)\n", "\n", "# verify that this is the same as just accumulating all the data\n", "print(cmom_1(x.reshape(-1), mom=4))" ] }, { "cell_type": "markdown", "id": "17", "metadata": {}, "source": [ "Excellent! We can use {class}`~cmomy.CentralMoments` to accumulate data on the go" ] }, { "cell_type": "code", "execution_count": 11, "id": "18", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])
" ], "text/plain": [ "\n", "array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cmomy.CentralMoments.zeros(mom=4)\n", "for i in range(5):\n", " # note: pushing multiple values\n", " c.push_vals(x[:, i], axis=0)\n", "c" ] }, { "cell_type": "markdown", "id": "19", "metadata": {}, "source": [ "Or, you can push all the values one at a time!" ] }, { "cell_type": "code", "execution_count": 12, "id": "20", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])
" ], "text/plain": [ "\n", "array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.zero()\n", "for xx in x.reshape(-1):\n", " # note: pushing single value\n", " c.push_val(xx)\n", "\n", "c" ] }, { "cell_type": "markdown", "id": "21", "metadata": {}, "source": [ "The values can even be differently weighted." ] }, { "cell_type": "code", "execution_count": 13, "id": "22", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])
" ], "text/plain": [ "\n", "array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xs = np.split(x.reshape(-1), [50, 150, 300])\n", "\n", "c.zero()\n", "for v in xs:\n", " c.push_vals(v, axis=0)\n", "c" ] }, { "cell_type": "markdown", "id": "23", "metadata": {}, "source": [ "Alternatively, you can add objects together." ] }, { "cell_type": "code", "execution_count": 14, "id": "24", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[\n", "array([5.0000e+01, 4.1743e-01, 7.3610e-02, 4.5490e-03, 1.0645e-02]), \n", "array([ 1.0000e+02, 5.1217e-01, 9.0418e-02, -3.0034e-03, 1.3257e-02]), \n", "array([ 1.5000e+02, 4.8912e-01, 8.3731e-02, -6.4426e-04, 1.2724e-02]), \n", "array([2.0000e+02, 5.0252e-01, 9.4279e-02, 1.8869e-04, 1.5262e-02])]\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])
" ], "text/plain": [ "\n", "array([5.0000e+02, 4.9192e-01, 8.8959e-02, 1.3873e-04, 1.3778e-02])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs = [cmomy.CentralMoments.from_vals(v, mom=4, axis=0) for v in xs]\n", "print(cs)\n", "\n", "c_tot = cs[0] + cs[1] + cs[2] + cs[3]\n", "c_tot" ] }, { "cell_type": "markdown", "id": "25", "metadata": {}, "source": [ "Or more simply:" ] }, { "cell_type": "code", "execution_count": 15, "id": "26", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[5.0000e+02 4.9192e-01 8.8959e-02 1.3873e-04 1.3778e-02]\n" ] } ], "source": [ "print(sum(cs, start=cs[0].zeros_like()).values)" ] }, { "cell_type": "markdown", "id": "27", "metadata": {}, "source": [ "Very cool!" ] }, { "cell_type": "markdown", "id": "28", "metadata": {}, "source": [ "## weighted averages\n", "\n", "cmomy is setup to work with arbitrary weights. We saw this work above when we considered unequal sample sizes. For example," ] }, { "cell_type": "code", "execution_count": 16, "id": "29", "metadata": {}, "outputs": [], "source": [ "def get_cmom_with_weights(x, w, axis=0, mom=3):\n", " \"\"\"Create central moments using stable method\"\"\"\n", " # output shape\n", " shape = x.shape[:axis] + x.shape[axis + 1 :] + (mom + 1,)\n", " output = np.zeros(shape, dtype=x.dtype)\n", "\n", " w_sum = w.sum(axis=axis)\n", " w_norm = 1.0 / w_sum\n", "\n", " output[..., 0] = w_sum\n", " output[..., 1] = ((w * x).sum(axis=axis)) * w_norm\n", "\n", " # moments [2 -> mom]\n", " output[..., 2:] = (\n", " w[..., None]\n", " * (x - (w * x).sum(axis=axis, keepdims=True) * w_norm)[..., None]\n", " ** np.arange(2, mom + 1)\n", " ).sum(axis=axis) * w_norm\n", "\n", " return output" ] }, { "cell_type": "code", "execution_count": 17, "id": "30", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([4.8363e+01, 5.0295e-01, 9.2209e-02, 6.3664e-04])
" ], "text/plain": [ "\n", "array([4.8363e+01, 5.0295e-01, 9.2209e-02, 6.3664e-04])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = rng.random(100)\n", "w = rng.random(100)\n", "\n", "moments = get_cmom_with_weights(x, w)\n", "moments\n", "\n", "cmomy.CentralMoments.from_vals(x, weight=w, mom=3, axis=0)" ] }, { "cell_type": "markdown", "id": "31", "metadata": {}, "source": [ "## comoments\n", "\n", "cmomy can also handle comoments (covariance, etc), like the $\\ave{(\\delta x)^i (\\delta y)^j}$ \n", "For example" ] }, { "cell_type": "code", "execution_count": 18, "id": "32", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
array([[ 4.8363e+01,  4.8516e-01,  7.5856e-02],\n",
       "       [ 5.0295e-01, -1.2237e-02,  3.2919e-04],\n",
       "       [ 9.2209e-02, -4.2304e-03,  6.5653e-03]])
" ], "text/plain": [ "\n", "array([[ 4.8363e+01, 4.8516e-01, 7.5856e-02],\n", " [ 5.0295e-01, -1.2237e-02, 3.2919e-04],\n", " [ 9.2209e-02, -4.2304e-03, 6.5653e-03]])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = rng.random(100)\n", "\n", "cmomy.CentralMoments.from_vals(x, y, weight=w, mom=(2, 2), axis=0)" ] }, { "cell_type": "markdown", "id": "33", "metadata": {}, "source": [ "All the special sauce works for central moments or comoments. " ] }, { "cell_type": "markdown", "id": "34", "metadata": {}, "source": [ "## xarray DataArray support\n", "\n", "cmomy also works with {class}`xarray.DataArray` objects. For example" ] }, { "cell_type": "code", "execution_count": 19, "id": "35", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.DataArray (rec: 3, a: 2, b: 3)> Size: 144B\n",
       "array([[[0.0625, 0.5585, 0.0184],\n",
       "        [0.4284, 0.4153, 0.0854]],\n",
       "\n",
       "       [[0.0821, 0.587 , 0.0041],\n",
       "        [0.7317, 0.3686, 0.2628]],\n",
       "\n",
       "       [[0.951 , 0.0224, 0.627 ],\n",
       "        [0.0179, 0.382 , 0.3126]]])\n",
       "Dimensions without coordinates: rec, a, b
" ], "text/plain": [ " Size: 144B\n", "array([[[0.0625, 0.5585, 0.0184],\n", " [0.4284, 0.4153, 0.0854]],\n", "\n", " [[0.0821, 0.587 , 0.0041],\n", " [0.7317, 0.3686, 0.2628]],\n", "\n", " [[0.951 , 0.0224, 0.627 ],\n", " [0.0179, 0.382 , 0.3126]]])\n", "Dimensions without coordinates: rec, a, b" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import xarray as xr\n", "\n", "x = xr.DataArray(rng.random((100, 2, 3)), dims=[\"rec\", \"a\", \"b\"])\n", "x.head(3) # type: ignore[attr-defined]" ] }, { "cell_type": "markdown", "id": "36", "metadata": {}, "source": [ "To create a cmomy object wrapping a {class}`xarray.DataArray`, use {class}`~cmomy.xCentralMoments`" ] }, { "cell_type": "code", "execution_count": 20, "id": "37", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.DataArray (a: 2, b: 3, mom_0: 4)> Size: 192B\n",
       "array([[[1.0000e+02, 4.0657e-01, 9.0470e-02, 1.3814e-02],\n",
       "        [1.0000e+02, 4.9516e-01, 7.3811e-02, 1.1677e-03],\n",
       "        [1.0000e+02, 4.6592e-01, 8.1210e-02, 3.3827e-03]],\n",
       "\n",
       "       [[1.0000e+02, 4.8831e-01, 8.2432e-02, 1.6465e-04],\n",
       "        [1.0000e+02, 4.6920e-01, 9.2950e-02, 5.5999e-03],\n",
       "        [1.0000e+02, 4.8891e-01, 7.6961e-02, 2.3232e-03]]])\n",
       "Dimensions without coordinates: a, b, mom_0
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.DataArray (a: 2, b: 3, mom_0: 4)> Size: 192B\n",
       "array([[[1.0000e+02, 4.0657e-01, 9.0470e-02, 1.3814e-02],\n",
       "        [1.0000e+02, 4.9516e-01, 7.3811e-02, 1.1677e-03],\n",
       "        [1.0000e+02, 4.6592e-01, 8.1210e-02, 3.3827e-03]],\n",
       "\n",
       "       [[1.0000e+02, 4.8831e-01, 8.2432e-02, 1.6465e-04],\n",
       "        [1.0000e+02, 4.6920e-01, 9.2950e-02, 5.5999e-03],\n",
       "        [1.0000e+02, 4.8891e-01, 7.6961e-02, 2.3232e-03]]])\n",
       "Dimensions without coordinates: a, b, mom_0
" ], "text/plain": [ "\n", " Size: 192B\n", "array([[[1.0000e+02, 4.0657e-01, 9.0470e-02, 1.3814e-02],\n", " [1.0000e+02, 4.9516e-01, 7.3811e-02, 1.1677e-03],\n", " [1.0000e+02, 4.6592e-01, 8.1210e-02, 3.3827e-03]],\n", "\n", " [[1.0000e+02, 4.8831e-01, 8.2432e-02, 1.6465e-04],\n", " [1.0000e+02, 4.6920e-01, 9.2950e-02, 5.5999e-03],\n", " [1.0000e+02, 4.8891e-01, 7.6961e-02, 2.3232e-03]]])\n", "Dimensions without coordinates: a, b, mom_0" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cmomy.xCentralMoments.from_vals(x, dim=\"rec\", mom=3)\n", "c" ] }, { "cell_type": "markdown", "id": "38", "metadata": {}, "source": [ "Everything that {class}`~cmomy.CentralMoments` can do, {class}`~cmomy.xCentralMoments` can do." ] }, { "cell_type": "code", "execution_count": null, "id": "39", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Tags", "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.9" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }