{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## numpy broadcasting is like \"sharing\" a smaller array for the bigger array\n", "- An array sharing a number\n", "- Regression paramters/weights sharing 1 intercept\n", "- Image data classification 2-D array of weights sharing 1-D array of intercept weights\n", "\n", "\n", "### Remember: \n", "\n", "\n", "1. shape (3,) is treated as (1,3)\n", "\n", "2. shape column sizes must match in order to broadcast\n", "\n", "3. any ufunc can be broadcasted, not just +-" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## [Broadcasting 1 number](#Broadcasting1Number)\n", "\n", "## [Broadcasting 1D array](#Broadcasting1D)\n", "\n", "## [Broadcast 2 ways](#two-way)\n", "\n", "## [Examples](#examples)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*** \n", "\n", "## Broadcasting 1 number" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(10)\n", "a" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a +10" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "a = np.arange(15).reshape(3,5)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1000, 1001, 1002, 1003, 1004],\n", " [1005, 1006, 1007, 1008, 1009],\n", " [1010, 1011, 1012, 1013, 1014]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + 1000" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Broadcasting 1D array" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(3)\n", "a" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.eye(3)\n", "b" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 1., 2.],\n", " [0., 2., 2.],\n", " [0., 1., 3.]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "b = np.ones((2,3), int)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [1, 2, 3]])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Won't work: when column sizes don't match unless one of them has only 1 column! Column sizes must match! (3,) is treated as (1,3) when broadcasting. (6,) is treated as (1,6)\n", "
" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.arange(10)\n", "b" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "operands could not be broadcast together with shapes (3,) (10,) ", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ma\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mb\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mValueError\u001b[0m: operands could not be broadcast together with shapes (3,) (10,) " ] } ], "source": [ "a + b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# even though 6 is divisable by 3, a refuses to be shared :(\n", "b = np.arange(6)\n", "a + b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# as soon as we reshape b to have the same column size as a, it works. \n", "a + b.reshape(2,3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Broadcast two ways" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = np.arange(3)\n", "a.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = np.arange(3)[:, np.newaxis]\n", "b.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# it is working because b has 1 column\n", "a + b" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "\n", "## Examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ex. 1 long - wide\n", "- long duplicates itself horizontally to match wide's width\n", "- wide duplicates itself vertically to match long's width" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X = np.ones((2,1), dtype=int)\n", "X" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y = np.ones((1,2), dtype=int)\n", "Y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X - Y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ex. 2 long - wide\n", "- long duplicates itself horizontally to match wide's width\n", "- wide duplicates itself vertically to match long's width" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X = np.full((2,1),2)\n", "X" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y = np.full((1,2),1)\n", "Y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X - Y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ex. 3 long - wide\n", "- long duplicates itself horizontally to match wide's width\n", "- wide duplicates itself vertically to match long's width" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X = np. array([[1],[2]])\n", "X" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y = np.array([[2, 1]])\n", "Y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X -Y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tricking it into doing something with evey row\n", "If we think of each row is a point on 2-D space (like a sheet of paper), if we want to get its distance from all other points, including itself,which we called X here,\n", "\n", "then we reshape a copy of it into 3-D space, which we call Y. So when we take the difference between them, X will be duplicated along the 3rd dimension.\n", "\n", "The trick is that we do not reshape Y in (2,2,1). Rather, we reshape Y in (2,1,2). \n", "\n", "In the first 2D space, X is (2,2) whereas Y is (2,1). So Y has to duplicate itself to become (2,2). \n", "\n", "In the last dimension, X has to duplicate itself for Y. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X = np.array([[1,0],\n", " [2,1]])\n", "X" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Y = X.reshape(2,1,2)\n", "Y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#[[0,0] ,[-1,-1]] = [[1, 0]] - [[1, 0],[2, 1]]\n", "#[[ 1, 1],[ 0, 0]]] = [[2, 1]] - [[1, 0],[2, 1]]\n", "Y-X" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Let's check to see if we can replicate what numpy did" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.array([[1, 0]]) - np.array([[1, 0],[2, 1]])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.array([[2, 1]]) - np.array([[1, 0],[2, 1]])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.hstack((np.array([[1, 0]]) - np.array([[1, 0],[2, 1]]), np.array([[2, 1]])) - np.array([[1, 0],[2, 1]]) )" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }