{"id":2484,"date":"2026-02-02T07:51:43","date_gmt":"2026-02-02T07:51:43","guid":{"rendered":"https:\/\/demo.materiamedica.net\/demo6\/?p=2484"},"modified":"2026-02-02T07:51:43","modified_gmt":"2026-02-02T07:51:43","slug":"chapter-13-numpy-joining-array","status":"publish","type":"post","link":"https:\/\/demo.materiamedica.net\/demo6\/chapter-13-numpy-joining-array\/","title":{"rendered":"Chapter 13: NumPy Joining Array"},"content":{"rendered":"<p dir=\"auto\"><strong>NumPy Joining Arrays<\/strong> \u2014 written as if I\u2019m your patient teacher sitting next to you, showing examples on the screen, explaining exactly what\u2019s happening, when to use each method, common beginner mistakes, and realistic patterns you will actually use.<\/p>\n<p dir=\"auto\">Let\u2019s go step by step.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>import numpy as np<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">What does \u201cjoining arrays\u201d really mean?<\/h3>\n<p dir=\"auto\">Joining = <strong>combining multiple arrays<\/strong> into a <strong>single larger array<\/strong>.<\/p>\n<p dir=\"auto\">NumPy provides several functions to do this, and each one has a slightly different purpose:<\/p>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"xs\">Function<\/th>\n<th data-col-size=\"xl\">What it does<\/th>\n<th data-col-size=\"lg\">Most common dimension (axis)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"xs\">np.concatenate()<\/td>\n<td data-col-size=\"xl\">General-purpose joining along <strong>any axis<\/strong><\/td>\n<td data-col-size=\"lg\">axis=0 or axis=1<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.vstack()<\/td>\n<td data-col-size=\"xl\">Vertical stack (like stacking rows)<\/td>\n<td data-col-size=\"lg\">always along axis=0<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.hstack()<\/td>\n<td data-col-size=\"xl\">Horizontal stack (like putting columns side by side)<\/td>\n<td data-col-size=\"lg\">always along axis=1<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.dstack()<\/td>\n<td data-col-size=\"xl\">Depth stack (adds a new 3rd dimension)<\/td>\n<td data-col-size=\"lg\">along axis=2<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.column_stack()<\/td>\n<td data-col-size=\"xl\">Special case: turns 1D arrays into columns<\/td>\n<td data-col-size=\"lg\">treats 1D as columns<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.row_stack()<\/td>\n<td data-col-size=\"xl\">Alias for vstack<\/td>\n<td data-col-size=\"lg\">along axis=0<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xs\">np.append()<\/td>\n<td data-col-size=\"xl\">Convenient but <strong>often slower<\/strong><\/td>\n<td data-col-size=\"lg\">usually along axis=0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">1. The most important function: np.concatenate()<\/h3>\n<p dir=\"auto\">This is the <strong>general-purpose<\/strong> and most flexible method.<\/p>\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])\r\nb = np.array([4, 5, 6])\r\n\r\n# Join along axis=0 (default) \u2192 vertical \/ rows\r\nc = np.concatenate([a, b])\r\nprint(c)\r\n# [1 2 3 4 5 6]\r\n\r\n# Same as:\r\nc = np.concatenate((a, b), axis=0)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>2D example \u2013 most common real use<\/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>A = np.array([[1, 2],\r\n              [3, 4]])\r\n\r\nB = np.array([[5, 6],\r\n              [7, 8]])\r\n\r\n# Stack vertically (add rows) \u2192 axis=0\r\nvert = np.concatenate([A, B], axis=0)\r\nprint(vert)\r\n# [[1 2]\r\n#  [3 4]\r\n#  [5 6]\r\n#  [7 8]]\r\n\r\n# Stack horizontally (add columns) \u2192 axis=1\r\nhoriz = np.concatenate([A, B], axis=1)\r\nprint(horiz)\r\n# [[1 2 5 6]\r\n#  [3 4 7 8]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Very important rule<\/strong>:<\/p>\n<blockquote dir=\"auto\">\n<p dir=\"auto\">All arrays must have <strong>the same shape in all dimensions except the one you are joining along<\/strong>.<\/p>\n<\/blockquote>\n<p dir=\"auto\">Wrong example:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>x = np.array([[1,2,3]])\r\ny = np.array([[4,5]])          # \u2190 different number of columns\r\n\r\nnp.concatenate([x, y], axis=0)   # ValueError: all the input array dimensions except for the concatenation axis must match exactly<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">2. Convenience functions: vstack, hstack, dstack<\/h3>\n<p dir=\"auto\">These are just <strong>special cases<\/strong> of concatenate \u2014 easier to remember.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code># vstack = vertical stack = concatenate along axis=0\r\nprint(np.vstack([A, B]))\r\n# same as concatenate(..., axis=0)\r\n\r\n# hstack = horizontal stack = concatenate along axis=1 (for 2D)\r\nprint(np.hstack([A, B]))\r\n# same as concatenate(..., axis=1)\r\n\r\n# For 1D arrays \u2192 hstack behaves differently\r\np = np.array([10, 20, 30])\r\nq = np.array([40, 50, 60])\r\n\r\nprint(np.hstack([p, q]))\r\n# [10 20 30 40 50 60]   \u2190 just like concatenate\r\n\r\nprint(np.vstack([p, q]))\r\n# [[10 20 30]\r\n#  [40 50 60]]         \u2190 turns 1D into rows<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>dstack<\/strong> \u2014 depth \/ third dimension (less common but useful)<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>x = np.array([[1,2],[3,4]])\r\ny = np.array([[5,6],[7,8]])\r\n\r\nz = np.dstack([x, y])\r\nprint(z.shape)          # (2, 2, 2)\r\nprint(z)\r\n# [[[1 5]\r\n#   [2 6]]\r\n\r\n#  [[3 7]\r\n#   [4 8]]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">Think of it as: <strong>adding a new color channel<\/strong> or <strong>adding a new feature layer<\/strong>.<\/p>\n<h3 dir=\"auto\">3. Very useful special case: np.column_stack()<\/h3>\n<p dir=\"auto\">This is <strong>extremely common<\/strong> when you have several 1D arrays and want to make them columns.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>time = np.array([0, 1, 2, 3])\r\ntemp = np.array([22.5, 23.1, 24.0, 23.8])\r\npressure = np.array([1013, 1012, 1010, 1009])\r\n\r\ndata = np.column_stack((time, temp, pressure))\r\nprint(data)\r\n# [[   0.    22.5 1013. ]\r\n#  [   1.    23.1 1012. ]\r\n#  [   2.    24.   1010. ]\r\n#  [   3.    23.8 1009. ]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">\u2192 This is very similar to np.c_[&#8230;] (another short syntax)<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>data2 = np.c_[time, temp, pressure]     # exactly the same result<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">4. Realistic patterns you will use very often<\/h3>\n<p dir=\"auto\"><strong>Pattern 1: Building a dataset row by row (simulation \/ logging)<\/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># Start empty\r\nresults = np.empty((0, 4))   # 0 rows, 4 columns\r\n\r\nfor i in range(100):\r\n    new_row = np.array([i, i**2, np.sin(i), np.random.randn()])\r\n    results = np.vstack([results, new_row])      # \u2190 common but slow!<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Better &amp; faster way<\/strong> (recommended):<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code># Collect in list first (much faster)\r\nrows = []\r\nfor i in range(100):\r\n    rows.append([i, i**2, np.sin(i), np.random.randn()])\r\n\r\nresults = np.array(rows)           # convert once at the end\r\n# or\r\nresults = np.vstack(rows)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Pattern 2: Combining features \/ channels<\/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>red   = np.random.randint(0, 256, (100, 100))\r\ngreen = np.random.randint(0, 256, (100, 100))\r\nblue  = np.random.randint(0, 256, (100, 100))\r\n\r\nrgb = np.dstack([red, green, blue])\r\nprint(rgb.shape)          # (100, 100, 3)  \u2190 perfect image shape<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Pattern 3: Merging train\/test or old\/new data<\/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>X_old = np.random.randn(800, 20)\r\nX_new = np.random.randn(200, 20)\r\n\r\nX_all = np.concatenate([X_old, X_new], axis=0)\r\nprint(X_all.shape)        # (1000, 20)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Summary \u2013 Quick Decision Table<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"md\">You want to&#8230;<\/th>\n<th data-col-size=\"lg\">Best function(s)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"md\">Add rows \/ stack vertically<\/td>\n<td data-col-size=\"lg\">vstack() or concatenate(&#8230;, axis=0)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Add columns \/ stack horizontally<\/td>\n<td data-col-size=\"lg\">hstack() or concatenate(&#8230;, axis=1)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Turn 1D arrays into columns<\/td>\n<td data-col-size=\"lg\">column_stack() or np.c_[&#8230;]<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Add a new depth \/ channel dimension<\/td>\n<td data-col-size=\"lg\">dstack() or concatenate(&#8230;, axis=2)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">General case \/ more than 2 arrays<\/td>\n<td data-col-size=\"lg\">np.concatenate()<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">You are building an array incrementally<\/td>\n<td data-col-size=\"lg\">collect in list \u2192 np.array(list) or vstack at end<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Common Mistakes to Avoid<\/h3>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code># Mistake 1: different shapes in non-join dimension\r\na = np.ones((3,4))\r\nb = np.ones((3,5))\r\nnp.hstack([a,b])           # ValueError\r\n\r\n# Mistake 2: forgetting list\/tuple\r\nnp.concatenate(a, b)       # TypeError \u2013 must be sequence of arrays\r\n\r\n# Mistake 3: using append in a loop (very slow)\r\nfor i in range(10000):\r\n    arr = np.append(arr, i)   # \u2190 extremely inefficient \u2013 avoid!<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">Would you like to go deeper into any of these topics next?<\/p>\n<ul dir=\"auto\">\n<li>Performance comparison: concatenate vs vstack vs list collecting<\/li>\n<li>Joining arrays with different dtypes (what happens?)<\/li>\n<li>Joining &gt;2 arrays or joining along axis=2, axis=3\u2026<\/li>\n<li>Real mini-project: combining measurement files \/ images \/ time series<\/li>\n<li>Difference between concatenate and append in detail<\/li>\n<\/ul>\n<p dir=\"auto\">Just tell me what you want to focus on now! \ud83d\ude0a<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NumPy Joining Arrays \u2014 written as if I\u2019m your patient teacher sitting next to you, showing examples on the screen, explaining exactly what\u2019s happening, when to use each method, common beginner mistakes, and realistic&#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-2484","post","type-post","status-publish","format-standard","hentry","category-numpy"],"_links":{"self":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2484","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=2484"}],"version-history":[{"count":1,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2484\/revisions"}],"predecessor-version":[{"id":2485,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2484\/revisions\/2485"}],"wp:attachment":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/media?parent=2484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/categories?post=2484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/tags?post=2484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}