{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Summarizing Arrays"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Arrays of numbers are very useful tools for storing and organizing large collections of data. Often, however, we want to summarize these collections of information to provide a sense of the data as a whole. We often do this instinctively in our daily lives. For example - want to know if we're getting a good price on buying a car? Look at the average price of that care in the area and compare the asking price. Want to know if your home is at risk of being flooded? Look at the maximum flood height in the area over the past 200 years and compare that to your home. We use data summaries every day for decision-making: these are all data-driven approaches to decision-making. In other words, rudimentary data science.\n",
"\n",
"We touched on summarizing array information earlier when we discussed vectors. We now want to be able to summarize a collection of numerical data by calculating sums, minima, maxima, averages, standard deviations, or even counts of the number of elements in a collection. Here we'll be diving deeper into summarization techniques and will explore how they can be applied to multidimensional arrays as well. For each of these summarization techniques, `numpy` has methods that are ready to help!\n",
"\n",
"Your core summarization functions are as follows:\n",
"1. Sum: `sum`\n",
"2. Minimum: `min`\n",
"3. Maximum: `max`\n",
"4. Average: `mean`\n",
"5. Median: `median`\n",
"6. Size/Length/cardinality/number of elements: `size`\n",
"7. Number of nonzero elements: `count_nonzero`\n",
"8. Standard deviation: `std`\n",
"\n",
"Let's create a simple array to demonstrate these features. (As a best practice, it's always good to start with a simple example that you can verify or compute by hand, if possible, to make sure your code is working as expected - think test-driven development as was discussed in the last course)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"x = np.array([0, 1, 0, -2, 12])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This simple array shows that each of the summarization methods shrinks the data down to a single number. A data science term for this is dimensionality reduction - we can represent the array `x` with any one of these summary quantities."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sum = 11\n",
"Mean = 2.2\n",
"Min = -2\n",
"Max = 12\n",
"Median = 0.0\n",
"Size = 5\n",
"Count nonzero = 3\n",
"Standard Deviation = 4.995998398718719\n"
]
}
],
"source": [
"print(f\"Sum = {np.sum(x)}\")\n",
"print(f\"Mean = {np.mean(x)}\")\n",
"print(f\"Min = {np.min(x)}\")\n",
"print(f\"Max = {np.max(x)}\")\n",
"print(f\"Median = {np.median(x)}\")\n",
"print(f\"Size = {np.size(x)}\")\n",
"print(f\"Count nonzero = {np.count_nonzero(x)}\")\n",
"print(f\"Standard Deviation = {np.std(x)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Summarizing 1-dimensional arrays is pretty straightforward. This same concept can be used on arrays of far higher dimensionality. In those cases, we just have to be careful to adjust the parameters accordingly. Let's define a new array `y` that is a 2-dimensional matrix. Remember, this is an array of arrays."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1],\n",
" [2, 3]])"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = np.array([[0, 1], [2, 3]])\n",
"y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case, we have an array of two entries; each entry is an array: the first array has the values 0 and 1, and the second array has the values 2 and 3. We typically describe this array as having two rows (where the first row is `[0 1]` and the second row is `[2 3]`) and two columns (the first column is `[0 2]` and the second column is `[1 3]`)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's run each of the summary functions again and see what happens:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sum = 6\n",
"Mean = 1.5\n",
"Min = 0\n",
"Max = 3\n",
"Median = 1.5\n",
"Size = 4\n",
"Count nonzero = 3\n",
"Standard Deviation = 1.118033988749895\n"
]
}
],
"source": [
"print(\"Sum =\", np.sum(y))\n",
"print(\"Mean =\", np.mean(y))\n",
"print(\"Min =\", np.min(y))\n",
"print(\"Max =\", np.max(y))\n",
"print(\"Median =\", np.median(y))\n",
"print(\"Size =\", np.size(y))\n",
"print(\"Count nonzero =\", np.count_nonzero(y))\n",
"print(\"Standard Deviation =\", np.std(y))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see that these functions operate across **all** elements in the array, regardless of which row or column they are a part of. We could do this on any size matrix we wish.\n",
"\n",
"Sometimes, however, we want to perform these summarization operations just down each column or just across each row. This is often the case when we are working with tabular data. Imagine each row represents a patient and each column represents a different characteristic of that patient (weight, height, temperature). We may want the average weight, height, and temperature of the patients. We can do that, we just need to specify which axis along which to perform the summarization along. For a matrix of data axis 0 is down the columns and axis 1 is across the rows (see the figure below).\n",
"\n",
"Let's take an example using our matrix `y` above:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.sum(y) # Sum of all elements"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 4])"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.sum(y, axis=0) # Sum of each column"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 5])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.sum(y, axis=1) # Sum of each row"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How these summarization functions are computed is described in this figure:\n",
"\n",
"![Sum Along Axis](img/sum_along_axes.png)\n",
"\n",
"These same techniques can be used with other `numpy` functions that compute various statistics. These techniques can also be applied to higher dimensional arrays (3, 4, or more dimensions) using the same basic principles and functions.\n",
"\n",
"**Aside**. All of the functions we described above have the functional form `np.()`. However, you may also see some of these functions accessed as a method of the `ndarray` object class (the standard object type that `numpy` uses for representing arrays. Just as we discussed earlier around object-oriented programming, a method is a function associated with an object. For those methods of `ndarray` objects in `numpy`, they can be accessed by using the alternative syntax of: `.()`. Here's an example with the `max` function:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.max(y)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y.max() # Here we access the \"max\" method of the \"array\" object"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 3])"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y.max(axis=1) # You can specify the axis to compute along as well as was done with np.max(y, axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Which should you choose? For summary functions, either will yield the same result so pick the one that keeps your code easier to read. There are other `ndarray` methods such as `x.sort()` that will operate on your array in-place, meaning that it replaces the content of the original array while the function `np.sort(x)` returns a sorted copy, leaving `x` unchanged."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Recap\n",
"- Many common data science applications of gathering insights or making decisions based on data rely on summarizing those data\n",
"- Summaries such as calculating minima, maxima, and sums can be applied readily to matrices of two or more dimensions.\n",
"\n",
"In the next lesson, we will walk through an example of how these techniques can be used in practice."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.2 64-bit",
"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.8.2"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
},
"vscode": {
"interpreter": {
"hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}