{"id":2545,"date":"2026-02-02T10:32:36","date_gmt":"2026-02-02T10:32:36","guid":{"rendered":"https:\/\/demo.materiamedica.net\/demo6\/?p=2545"},"modified":"2026-02-02T10:33:14","modified_gmt":"2026-02-02T10:33:14","slug":"chapter-7-numpy-products","status":"publish","type":"post","link":"https:\/\/demo.materiamedica.net\/demo6\/chapter-7-numpy-products\/","title":{"rendered":"Chapter 7: NumPy Products"},"content":{"rendered":"<h3 dir=\"auto\">1. What do we mean by \u201cproducts\u201d in NumPy?<\/h3>\n<p dir=\"auto\">In NumPy, \u201cproducts\u201d usually refer to <strong>multiplication operations<\/strong> and <strong>product reductions<\/strong> (like summing, but multiplying).<\/p>\n<p dir=\"auto\">There are two main families:<\/p>\n<ol dir=\"auto\">\n<li><strong>Element-wise multiplication<\/strong> \u2192 happens between arrays of the same shape (or broadcastable shapes) \u2192 this is the most common operation you do every day<\/li>\n<li><strong>Product reduction<\/strong> (like sum, but multiply all elements together) \u2192 collapses an axis (or the whole array) into a single product \u2192 very useful in probability, logarithms, factorial-like calculations, cumulative products, etc.<\/li>\n<\/ol>\n<h3 dir=\"auto\">2. The three most important product-related ufuncs<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"md\">Function<\/th>\n<th data-col-size=\"lg\">What it does<\/th>\n<th data-col-size=\"lg\">Returns<\/th>\n<th data-col-size=\"xl\">Common use case<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"md\">np.multiply \/ *<\/td>\n<td data-col-size=\"lg\">element-wise multiplication<\/td>\n<td data-col-size=\"lg\">new array<\/td>\n<td data-col-size=\"xl\">almost everything<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">np.prod()<\/td>\n<td data-col-size=\"lg\">product of all elements (or along axis)<\/td>\n<td data-col-size=\"lg\">scalar or reduced array<\/td>\n<td data-col-size=\"xl\">total product, probability chains<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">np.cumprod()<\/td>\n<td data-col-size=\"lg\">cumulative product along axis<\/td>\n<td data-col-size=\"lg\">array of same shape<\/td>\n<td data-col-size=\"xl\">running product, growth factors<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">3. Element-wise multiplication \u2013 the most common operation<\/h3>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>a = np.array([2, 3, 4, 5])\r\nb = np.array([10, 20, 30, 40])\r\n\r\nprint(\"a * b       =\", a * b)              # [ 20  60 120 200]\r\nprint(\"np.multiply(a, b) =\", np.multiply(a, b))  # same\r\n\r\n# With scalar\r\nprint(\"a * 100     =\", a * 100)            # [200 300 400 500]\r\n\r\n# With broadcasting\r\nprint(\"a * [1, 2, 3, 4] =\", a * np.array([1, 2, 3, 4]))<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>2D example \u2013 very frequent in real work<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>matrix = np.arange(1, 13).reshape(3, 4)\r\nprint(\"matrix =\\n\", matrix)\r\n\r\nweights = np.array([1.5, 2.0, 0.5, 3.0])\r\n\r\nprint(\"\\nmatrix * weights (broadcasts row-wise):\")\r\nprint(matrix * weights)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Output<\/strong>:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>text<\/div>\n<div>\n<pre tabindex=\"0\"><code>matrix =\r\n [[ 1  2  3  4]\r\n  [ 5  6  7  8]\r\n  [ 9 10 11 12]]\r\n\r\nmatrix * weights:\r\n [[ 1.5  4.   1.5 12. ]\r\n  [ 7.5 12.   3.5 24. ]\r\n  [13.5 20.   5.5 36. ]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">4. np.prod() \u2013 the \u201csum, but multiply\u201d function<\/h3>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>a = np.array([1, 2, 3, 4, 5])\r\n\r\nprint(\"np.prod(a)      =\", np.prod(a))          # 120\r\nprint(\"a.prod()        =\", a.prod())            # 120\r\n\r\n# With axis\r\nm = np.arange(1, 13).reshape(3, 4)\r\nprint(\"\\nm =\\n\", m)\r\n\r\nprint(\"\\nProduct of each column:\", m.prod(axis=0))\r\n# [ 45 240 693 1344]\r\n\r\nprint(\"Product of each row:\", m.prod(axis=1))\r\n# [   24  1680 11880]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Important trap<\/strong>: <strong>Product can become huge very quickly<\/strong> \u2192 overflow is common with integers.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>big = np.arange(1, 25)\r\nprint(np.prod(big))           # \u2192 huge number or overflow if int32\/int64<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Safe habit<\/strong> \u2014 use dtype=float or dtype=object when product might overflow:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>print(np.prod(big, dtype=float))        # safe, but loses precision at very large values<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">5. np.cumprod() \u2013 cumulative \/ running product<\/h3>\n<p dir=\"auto\">Very useful in:<\/p>\n<ul dir=\"auto\">\n<li>growth factors<\/li>\n<li>probability chains<\/li>\n<li>compound interest<\/li>\n<li>sequential multiplication<\/li>\n<\/ul>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>returns = np.array([1.02, 0.98, 1.05, 1.03, 0.99])   # daily multipliers\r\n\r\ncumulative_growth = np.cumprod(returns)\r\n\r\nprint(\"Daily multipliers:\", returns)\r\nprint(\"Cumulative product:\", cumulative_growth.round(3))\r\n# [1.    0.98  1.029 1.06  1.049]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Plot example<\/strong> \u2013 very common in finance \/ growth simulation<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>days = np.arange(len(cumulative_growth))\r\n\r\nplt.plot(days, cumulative_growth, marker='o', ms=6, lw=1.8, color='teal')\r\nplt.axhline(1, color='gray', ls='--', lw=0.8)\r\nplt.title(\"Cumulative growth from daily returns\")\r\nplt.xlabel(\"Day\")\r\nplt.ylabel(\"Growth factor\")\r\nplt.show()<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">6. Realistic patterns you will write again and again<\/h3>\n<p dir=\"auto\"><strong>Pattern 1 \u2013 Normalize probabilities \/ softmax style<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>scores = np.random.randn(1000, 5) * 2\r\n\r\n# Very common mistake: product of probabilities \u2192 underflow\r\n# Better: work in log space\r\nlog_probs = scores - np.log(np.sum(np.exp(scores), axis=1, keepdims=True))\r\nprobs = np.exp(log_probs)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Pattern 2 \u2013 Cumulative product for investment returns<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>monthly_returns = 1 + np.random.normal(0.008, 0.04, 60)  # ~10% annual\r\n\r\nwealth_path = 100000 * np.cumprod(monthly_returns)\r\n\r\nplt.plot(wealth_path, lw=1.5, color='darkblue')\r\nplt.title(\"Simulated portfolio growth (60 months)\")\r\nplt.ylabel(\"Portfolio value ($)\")\r\nplt.xlabel(\"Month\")\r\nplt.show()<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Pattern 3 \u2013 Product along axis for ratios \/ factors<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>ratios = np.random.uniform(0.8, 1.2, size=(100, 12))  # monthly growth factors\r\n\r\nyearly_product = ratios.prod(axis=1)         # annual growth factor per row\r\nprint(\"Average annual growth factor:\", yearly_product.mean().round(3))<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Pattern 4 \u2013 Safe product with very small numbers<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>small_probs = np.random.uniform(0.001, 0.1, 100)\r\n\r\n# Direct product \u2192 underflow \u2192 0.0\r\nprint(\"Direct product:\", small_probs.prod())\r\n\r\n# Safe way: sum of logs\r\nlog_prod = np.sum(np.log(small_probs))\r\nsafe_product = np.exp(log_prod)\r\nprint(\"Safe product via log:\", safe_product.round(8))<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">7. Summary \u2013 NumPy Product Operations Quick Reference<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"md\">Operation \/ Function<\/th>\n<th data-col-size=\"lg\">Syntax example<\/th>\n<th data-col-size=\"lg\">Typical use case<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"md\">Element-wise multiply<\/td>\n<td data-col-size=\"lg\">a * b, np.multiply(a, b)<\/td>\n<td data-col-size=\"lg\">scaling, weighting, masking<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Total product<\/td>\n<td data-col-size=\"lg\">arr.prod() or np.prod(arr)<\/td>\n<td data-col-size=\"lg\">total multiplication<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Product along axis<\/td>\n<td data-col-size=\"lg\">arr.prod(axis=0)<\/td>\n<td data-col-size=\"lg\">row\/column products<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Cumulative product<\/td>\n<td data-col-size=\"lg\">np.cumprod(arr)<\/td>\n<td data-col-size=\"lg\">running product, growth<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Safe product (no underflow)<\/td>\n<td data-col-size=\"lg\">np.exp(np.sum(np.log(arr)))<\/td>\n<td data-col-size=\"lg\">very small probabilities<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Final teacher advice (very important)<\/h3>\n<p dir=\"auto\"><strong>Golden rule #1<\/strong> Use * for element-wise multiplication \u2014 it is clean, fast, and idiomatic.<\/p>\n<p dir=\"auto\"><strong>Golden rule #2<\/strong> When you need the <strong>product of many numbers<\/strong> (especially small ones), <strong>work in log space<\/strong>:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>log_result = np.sum(np.log(values))\r\nresult = np.exp(log_result)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">This avoids underflow (product \u2192 0) and overflow.<\/p>\n<p dir=\"auto\"><strong>Golden rule #3<\/strong> When you see loops like this:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>product = 1\r\nfor x in arr:\r\n    product *= x<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">\u2192 replace it immediately with arr.prod() or np.prod(arr).<\/p>\n<p dir=\"auto\">Would you like to continue with any of these topics?<\/p>\n<ul dir=\"auto\">\n<li>Handling underflow\/overflow in products<\/li>\n<li>Cumulative product vs cumulative sum in time series<\/li>\n<li>Products along multiple axes (3D, 4D arrays)<\/li>\n<li>Realistic mini-project: simulate investment growth or probability chains<\/li>\n<li>Difference between prod vs multiply vs dot<\/li>\n<\/ul>\n<p dir=\"auto\">Just tell me what you want to focus on next! \ud83d\ude0a<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. What do we mean by \u201cproducts\u201d in NumPy? In NumPy, \u201cproducts\u201d usually refer to multiplication operations and product reductions (like summing, but multiplying). There are two main families: Element-wise multiplication \u2192 happens between&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[75],"tags":[],"class_list":["post-2545","post","type-post","status-publish","format-standard","hentry","category-numpy"],"_links":{"self":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2545","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/comments?post=2545"}],"version-history":[{"count":1,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2545\/revisions"}],"predecessor-version":[{"id":2546,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2545\/revisions\/2546"}],"wp:attachment":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/media?parent=2545"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/categories?post=2545"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/tags?post=2545"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}