NumPy Arrays and Vectorized Computing

Learn to work with numbers the way data analysts do in Python: as NumPy arrays. Create arrays and choose their data types, select values by position or by condition, reshape and join arrays, and replace slow loops with vectorized arithmetic, universal functions and broadcasting. Summarize data along rows or columns, deal with missing values, and use a seeded random number generator to run reproducible simulations.

IntermediateLesson 1 of 8 in Data Analysis with Python Course

What you will learn

  1. Build NumPy arrays from Python data and with NumPy's creation functions, describe an array by its shape and data type, and choose and convert data types without losing information by accident.
    • Explain what a NumPy array is and how it differs from a list
      Describe an array by its dimensions, shape, size and data type, and explain why arrays behave and perform differently from Python lists.
    • Create arrays from lists and with NumPy's creation functions
      Turn lists into arrays and generate filled arrays, number ranges and evenly spaced grids with the shape and type you need.
    • Choose, inspect and convert data types
      Read and set an array's dtype, predict the type NumPy chooses, and convert between types while avoiding truncation, overflow and lost missing values.
  2. Pick out single values, rows, columns and blocks; select by lists of positions or by conditions; and know when a selection shares its data with the original array.
    • Index and slice one- and two-dimensional arrays
      Use positions and slices, one per axis, to read and change elements, rows, columns and blocks.
    • Select by lists of positions and tell views from copies
      Select any elements, rows or columns with integer arrays, and predict whether a result shares memory with the original array.
    • Filter with conditions using boolean masks and np.where
      Build true/false masks from comparisons, combine them, and use them to filter, count, replace and choose values.
  3. Rearrange the same values into a new shape, swap rows and columns, add or remove axes of length 1, and join or split arrays along an axis.
    • Change an array's shape and swap its axes
      Reshape, flatten and transpose arrays, and add or remove axes of length 1, while predicting the order of the values.
    • Join and split arrays
      Combine arrays along an existing or a new axis, and cut an array into pieces, checking that shapes fit.
  4. Write calculations on whole arrays instead of element-by-element loops, apply NumPy's universal functions, and combine arrays of different shapes with the broadcasting rules.
    • Compute element by element instead of looping
      Use arithmetic and comparison operators on whole arrays, and know how they handle shapes, division by zero and in-place updates.
    • Apply universal functions to whole arrays
      Use NumPy's element-wise math functions, including rounding and two-array functions, and handle values outside a function's domain.
    • Combine arrays of different shapes with broadcasting
      Apply the broadcasting rules to predict whether two shapes combine and what shape results, and fix shape errors by adding an axis.
  5. Reduce arrays to totals, means, extremes, spreads, medians and counts, for the whole array or along a chosen axis, and handle missing values and subsets correctly.
    • Aggregate a whole array or along one axis
      Compute sums, means, extremes, positions, running totals and spreads for the whole array or per row or column, and predict the shape of the result.
    • Use medians, percentiles, sorting and unique values
      Describe the center and spread of data with order-based statistics, sort values and related arrays, and count distinct values.
    • Summarize data with missing values and conditions
      Find, count, drop and fill missing values, use NaN-aware aggregations, and summarize only the values that meet a condition or belong to a group.
  6. Create a seeded random number generator, draw reproducible samples from common distributions, shuffle and sample data, and estimate results with vectorized simulations.
    • Draw reproducible random samples with a Generator
      Create a Generator with a seed, draw integers, decimals, normal values and samples from a list, shuffle data, and keep results reproducible.
    • Run vectorized simulations
      Estimate probabilities and long-run behavior by drawing all random values at once and summarizing them with array operations.

NumPy Arrays study guide

6 chapters

1

Create arrays and control their data types

Numerical data becomes easier to work with when its structure and storage type are clear. Build arrays from existing values or from a planned shape, then read their dimensions, element count, and dtype. Choose creation functions that match your input, and see how conversion, rounding, overflow, and missing values affect what the array actually stores. These choices determine whether later calculations retain the information you need.

1.1 Explain what a NumPy array is and how it differs from a list

NumPy stores numerical data in arrays so that one expression can work on many values. Import it with import numpy as np; the short name np is the usual way to call its functions.

Read an array's structure

An ndarray is a rectangular grid whose elements share one data type. A dimension is also called an axis. Start with a small table:

import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])

Its attributes answer four different questions:

AttributeMeaningValue for a
ndimNumber of axes2
shapeLength of each axis(2, 3)
sizeTotal elements6
dtypeType of each elementUsually int64 on a 64-bit computer

Axis 0 indexes rows; axis 1 indexes columns. A data table with one row per person and columns for height, mass, and age would have shape (100, 3) for 100 people. The product of the shape entries gives the size.

A vector has no row or column axis

np.array([2, 4, 6, 8]) has shape (4,) and one axis. The comma makes this a one-entry tuple. Shape (1, 4) has two axes: one row and four columns. Shape (4, 1) also has two axes, but four rows and one column. These arrays contain four values, yet behave differently when combined with other arrays. np.array(7) is a zero-dimensional array: its shape is () and its ndim is 0.

Arrays change the meaning of operators

A list is a general Python container. An array is designed for calculations on matching positions.

ExpressionResult
[1, 2, 3] * 2[1, 2, 3, 1, 2, 3]
np.array([1, 2, 3]) * 2array([2, 4, 6])
[1, 2] + [3, 4][1, 2, 3, 4]
np.array([1, 2]) + np.array([3, 4])array([4, 6])

In the array addition, 1 pairs with 3 and 2 pairs with 4. The array stays the same size.

Why numerical arrays are efficient

A newly created numerical array stores same-typed values together in memory. NumPy runs the loop through these values in compiled code, avoiding a separate Python-level operation for every number. A million float64 values occupy 8,000,000 bytes of element storage, available as a.nbytes on an array of that size. A Python list also stores references to Python objects, so it needs substantially more space. Performance gains depend on the calculation and computer.

Array size does not grow through an in-place append method. np.append(a, value) allocates a new array. For data collected one value at a time, build a Python list and convert once. Nested input must be rectangular: np.array([[1, 2], [3]]) raises ValueError because its row lengths differ.

Recognize displayed results

print(np.array([1, 2, 3])) shows [1 2 3]. An interactive display uses array([1, 2, 3]). For np.array([5, 6])[0] on a 64-bit computer, NumPy 2 displays np.int64(5); it participates in arithmetic as the number 5.

Key Takeaways

  • Shape gives the length of each axis; size counts all elements.
  • A 1-D shape such as (4,) differs from a 2-D row or column.
  • Array arithmetic acts on values at matching positions.
  • Numerical arrays store one dtype and support efficient compiled calculations.
  • Nested input must have equal-length rows.

1.2 Create arrays from lists and with NumPy's creation functions

Choose a creation function by asking what you know: the actual values, a shape and fill value, a step size, or a required number of points. That choice makes the code express how the data should be built.

Start from values or a shape

np.array([3, 1, 4]) creates a vector. A list of equal-length lists creates a table. Pass the values as one sequence; np.array(1, 2, 3) does not supply three elements correctly.

FunctionExampleWhat it creates
np.zerosnp.zeros((3, 4))Three rows of four zeros
np.onesnp.ones((2, 3))Two rows of three ones
np.fullnp.full((2, 2), 7)A 2-by-2 array filled with 7
np.emptynp.empty((3, 4))Reserved, uninitialized storage

For a multidimensional shape, the parentheses matter. np.zeros((2, 3)) passes one tuple. In np.zeros(2, 3), Python sends 3 as the dtype argument, which causes a type error. Zeros and ones use float64 by default; full infers its dtype from the fill value. Add dtype=int when you need whole-number storage.

empty does not promise zeros or meaningful starting values. Read from it only after assigning every element you will use. zeros is a simpler choice when an initial zero has meaning.

Choose a step or choose a point count

np.arange(start, stop, step) follows the stepping idea of Python's range. np.arange(2, 11, 3) gives [2 5 8]: start at 2 and add 3 while staying below 11. With one argument, np.arange(5) starts at 0 and gives [0 1 2 3 4].

Floating-point steps can give surprising endpoints. For example, np.arange(1, 1.3, 0.1) includes the displayed value 1.3 because binary rounding affects the calculation of the sequence. For a decimal grid with a fixed point count, use linspace:

grid = np.linspace(0, 1, 5)
# array([0.  , 0.25, 0.5 , 0.75, 1.  ])

Both endpoints are included by default. Five points make four gaps. Ten points between 0 and 1 make nine gaps, so their spacing is about 0.111; steps of 0.1 need 11 points.

Reuse an existing structure

np.zeros_like(a), np.ones_like(a), and np.full_like(a, value) create new arrays with a's shape and dtype. The inherited dtype matters: filling an integer template with a decimal can lose the decimal part unless you request a floating dtype. np.eye(3) creates a square identity array with ones on the diagonal and zeros elsewhere.

Allocate a data table once

For rainfall in millimeters at three stations over four weeks:

rain = np.zeros((3, 4))
rain[0] = [12.0, 0.0, 5.5, 8.0]

The first assignment fills one row and preserves shape (3, 4). If the number of readings is known, reserving the full table avoids repeatedly allocating larger arrays. If the amount of input is unknown, accumulate values in a list and call np.array when collection is finished.

Key Takeaways

  • Pass a multidimensional shape as a tuple.
  • arange specifies a step; linspace specifies a point count.
  • linspace includes both endpoints by default.
  • empty must be filled before its values are used.
  • The like-functions inherit both shape and dtype.
  • Allocate a known final shape once.

1.3 Choose, inspect and convert data types

An array's dtype controls what it can store and how much memory each value needs. Choosing the right type also prevents calculations from quietly losing information.

Inspect the storage type

int64 holds 64-bit whole numbers, float64 holds binary floating-point numbers, and bool holds true/false values. Unicode dtypes such as <U5 store text with a maximum character length. a.itemsize is the bytes per element; a.nbytes is a.size * a.itemsize. A float64 uses 8 bytes and has about 15 significant decimal digits of precision.

On typical 64-bit computers, whole-number input uses 64-bit integers. NumPy 2 also uses that default on 64-bit Windows. Decimal input normally gives float64.

Inference chooses one shared type

np.array([1, 2.5]) becomes [1. 2.5]: the integer is represented as a float. np.array([True, 2]) becomes [1 2]. Mixing numbers and text can turn the entire array into text, so a label such as 'n/a' can make later arithmetic fail. Inspect dtype when apparently numerical data will not add or multiply.

Convert deliberately

astype returns a converted copy:

x = np.array([1.7, -1.7, 2.5])
whole = x.astype(int)
# array([ 1, -1,  2])

This conversion cuts toward zero; it does not round. np.round(x).astype(int) gives [2 -2 2] because exact halves round to the nearest even value. Text such as '1.5' converts with astype(float), but 'n/a' raises ValueError. Clean placeholders before conversion.

Assignments use the destination's dtype. After a = np.array([1, 2, 3]), assigning a[0] = 9.9 stores 9 without warning. Converting the entire array to float first lets later assignments retain decimals.

Fixed-width integers can overflow

An int8 holds values from −128 to 127; a uint8 holds 0 to 255. Adding two uint8 arrays containing 250 and 10 produces 4 through wraparound. Multiplying an int8 array containing 100 by 2 produces −56. A Python integer that cannot fit the array type, such as 300 added to an int8 array in NumPy 2, raises OverflowError instead. Widen small integer types before calculations that can exceed their range.

Division and approximate decimals
OperationExampleResult
True divisionnp.array([7, 8]) / 2[3.5 4.]
Floor divisionnp.array([7, -7]) // 2[3 -4]
Remaindernp.array([7, -7]) % 2[1 1]

Floor division rounds down toward negative infinity, which differs from truncation for negative results. True division returns floating-point results for integer inputs.

Many decimal fractions are approximations in binary. 0.1 + 0.2 == 0.3 is false; np.isclose compares corresponding values with a tolerance, and np.allclose gives one whole-array answer.

The missing marker np.nan is floating-point. Integer arrays cannot store it. np.array([1, 2, np.nan]) therefore becomes floating-point; converting missing values to integers does not repair them and can yield meaningless results.

Key Takeaways

  • One dtype governs every element, including values assigned later.
  • astype(int) truncates toward zero; rounding is a separate step.
  • Small fixed-width integers can overflow during arithmetic.
  • Use tolerance-based comparisons for approximate decimals.
  • NaN needs a floating-point dtype.
2

Select and filter data in arrays

An analysis rarely needs every value in exactly its original order. Select individual positions, regular slices, arbitrary records, or entries that satisfy a condition. Track whether a result shares memory with its source before editing it. Boolean masks then let the same selection rule support filtering, replacement, counts, and proportions, while preserving complete records when that is what your question needs.

2.1 Index and slice one- and two-dimensional arrays

Indexing locates values by position. Slicing selects a regular run of positions. In a table, write one selector for each axis so the code says both which rows and which columns you need.

Read a vector

For a = np.array([10, 20, 30, 40, 50]), position 0 contains 10 and position −1 contains 50. A slice has the form start:stop:step, with the stop excluded:

SelectionResult
a[1:4][20 30 40]
a[::2][10 30 50]
a[::-1][50 40 30 20 10]
a[3:10][40 50]

Leaving out start or stop extends to the relevant end. A slice can run beyond the array and be shortened automatically. A single invalid position, such as a[5], raises IndexError.

Give each table axis its own selector
m = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

m[1, 2] reads row 1, column 2, giving 6. The comma separates axes. A colon alone selects the full axis: m[0, :] gives the first row [1 2 3], and m[:, 1] gives the second column [2 5 8]. For a block, m[:2, 1:] selects rows 0 and 1 and columns 1 and 2, giving [[2 3] [5 6]].

Avoid treating repeated square-bracket indexing as interchangeable with comma indexing. m[1][2] happens to locate the same scalar as m[1, 2]. But m[:][0] first takes all rows and then selects the first row. It does not select the first column, which is m[:, 0].

Predict which axes remain

A single integer selector removes its axis. A slice retains its axis even when only one position is selected. Thus m[:, 1] has shape (3,), while m[:, 1:2] has shape (3, 1). Both select 2, 5, and 8, but only the second keeps a column axis. This difference becomes important when subtracting or multiplying arrays with other shapes.

The same rule extends beyond tables. If t.shape is (2, 3, 4), t[0] has shape (3, 4), t[0, 1] has shape (4,), and t[:, :, 0] has shape (2, 3). Any trailing axes omitted from the index are selected in full.

Change the selected positions

Assignment through an index writes into the existing array. a[1:3] = 0 replaces both selected values with zero; the scalar is applied throughout the selection. m[0] = [0, 0, 0] replaces a complete row. The assigned values must fit the selection's shape and are converted to its dtype.

For four students and three tests:

scores = np.array([[78, 85, 92], [64, 70, 58],
                   [88, 91, 95], [72, 68, 80]])

scores[2] is the third student's [88 91 95]. scores[:, -1] gives the final-test results [92 58 95 80]. scores[1:3, :2] gives [[64 70] [88 91]]: two students, each retaining two test columns.

Key Takeaways

  • Indexes start at 0; negative indexes count from the end.
  • Slices exclude the stop and can be shortened at an array boundary.
  • Use comma-separated selectors for separate axes.
  • An integer removes an axis; a slice retains it.
  • Assignment through an index changes the selected values.

2.2 Select by lists of positions and tell views from copies

A selection can share its data with the original array or own independent data. Knowing which one you have prevents edits to a small selection from unexpectedly changing a larger table.

Distinguish an alias, a view, and a copy
CodeRelationshipEffect of changing b
b = aTwo names for one objectChanges a
b = a[2:5]A slice view sharing dataChanges the corresponding part of a
b = a[2:5].copy()Independent dataLeaves a unchanged

For a = np.arange(6) and b = a[2:5], assigning b[0] = 99 makes a equal to [0 1 99 3 4 5]. The first position of the view refers to position 2 in the original. This differs from slicing a Python list, which makes a new list.

Copy before editing when the original must remain intact. A small retained view can also keep a large original data buffer alive; copying that small piece lets it stand independently.

Select arbitrary positions

Fancy indexing uses an integer list or array. It allows reordered and repeated positions:

a = np.array([10, 20, 30, 40, 50])
a[[4, 0, 0]]
# array([50, 10, 10])

For m = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), m[[0, 2]] selects the first and third rows. m[:, [2, 0]] selects the last and first columns in that order, giving [[3 1] [6 4] [9 7]].

Two integer lists in one index select paired coordinates. m[[0, 2], [1, 2]] pairs row 0 with column 1 and row 2 with column 2, producing [2 9]. It does not take all combinations. To get the block formed by both rows and both columns, use:

m[np.ix_([0, 2], [1, 2])]
# array([[2, 3], [8, 9]])

Selecting the rows first and then the columns, m[[0, 2]][:, [1, 2]], gives the same block.

Reading and assigning behave differently

Fancy indexing and boolean filtering return copies. If c = a[[0, 1]], changing c[0] leaves a unchanged. But a[[0, 1]] = -1 writes directly into those original positions. A saved selection and an assignment through an index are different operations.

This also explains why chained edits can fail to reach the source. In a[[0, 1]][0] = -1, the first selection is already a temporary copy. The final write changes that temporary array, not a.

Check sharing directly

np.shares_memory(x, y) checks whether two arrays overlap in memory. It returns true for an ordinary nonempty slice and false for a fancy-indexed copy. The base attribute can identify a backing owner, but it need not identify the array you most recently sliced. If a = np.arange(6), b = a[2:5], and c = b[0:2], then c.base is a is true and c.base is b is false. Use shares_memory when the question is specifically whether two arrays share data.

Key Takeaways

  • Assignment aliases an array; a basic slice shares its data.
  • Use .copy() for an independent selection.
  • Fancy indexing preserves the requested order and allows repeats.
  • Two integer index lists pair coordinates; np.ix_ selects all combinations.
  • Fancy-indexed reads copy, but direct indexed assignments update the source.
  • Use np.shares_memory to test sharing between arrays.

2.3 Filter with conditions using boolean masks and np.where

A boolean mask records which values satisfy a condition. Once a mask exists, the same true/false decisions can select values, count events, or choose replacements.

Build and apply a mask
t = np.array([18.5, 22.0, 15.2, 25.8, 21.1])
warm = t > 20
t[warm]
# array([22. , 25.8, 21.1])

The comparison produces [False True False True True]. Boolean indexing keeps the true positions and returns a copy. A 1-D mask used on an axis must have the same length as that axis.

To combine conditions, use & for and, | for or, and ~ for not. Put parentheses around each comparison:

comfortable = (t > 18) & (t < 23)
t[comfortable]
# array([18.5, 22. , 21.1])

Python's and and or try to get one truth value from an entire array and fail for multi-element arrays. Omitting the parentheses also changes how Python groups the expression because bitwise operators bind before comparisons.

Count, measure, or test conditions

True contributes 1 and False contributes 0. warm.sum() is 3 and warm.mean() is 0.6, the fraction of days above 20 °C. np.count_nonzero(warm) also counts true entries. warm.any() asks whether at least one day is warm; warm.all() asks whether every day is warm.

These operations answer different questions from t[warm].mean(), which calculates the average temperature among warm days. The mean of a mask measures a share; the mean of selected measurements retains the measurement's unit.

Replace values or choose between branches

Assignment through a mask updates the selected positions. With t2 = t.copy(), the line t2[t2 < 16] = 16 raises low readings to 16. np.clip(t, 16, 25) returns a new array bounded at both ends, [18.5 22. 16. 25. 21.1].

np.where(condition, x, y) builds a new result taking x at true positions and y at false positions. np.where(t > 20, 'warm', 'cool') supplies a label at every original position. In contrast, filtering shortens the result. With a condition alone, np.where(t > 20) returns a tuple of index arrays, here (array([1, 3, 4]),).

Keep values or keep complete records

A same-shape mask on a 2-D array extracts matching elements into one flat vector. In m[m > 5], the row structure is lost. To retain whole records, derive one boolean per row from a column:

scores = np.array([[78, 85, 92], [64, 70, 58],
                   [88, 91, 95], [72, 68, 80]])
scores[scores[:, 2] >= 90]
# array([[78, 85, 92], [88, 91, 95]])
Find missing values explicitly

NaN does not compare equal even to itself. Equality and ordering comparisons with NaN are false; inequality is true. Thus neither x == np.nan nor x != np.nan identifies present and missing entries correctly. np.isnan(x) marks missing positions, and x[~np.isnan(x)] keeps present values.

Key Takeaways

  • A mask holds one true/false decision per tested position.
  • Combine comparisons with parenthesized &, |, and ~.
  • A mask sum counts matches; a mask mean gives their fraction.
  • Use a row-length mask to filter whole records.
  • np.where chooses values at every position.
  • Use np.isnan to find NaN.
3

Reshape, transpose and join arrays

A useful array shape expresses how the data belongs together: months within quarters, measurements within records, or batches within a larger collection. Rearrange values with reshape, swap axis roles with transpose, and add length-one axes when a vector needs a row or column role. Joining and splitting then combine or separate those groups, with shape checks that keep the intended structure intact.

3.1 Change an array's shape and swap its axes

Changing shape changes how values are grouped into axes. Reshaping, transposing, and adding an axis do different jobs, even when some of them produce the same final shape.

Reshape without changing the element count
a = np.arange(6)
r = a.reshape(2, 3)
# array([[0, 1, 2], [3, 4, 5]])

The default order fills one row at a time: the last axis changes fastest. Reshaping the same values to (3, 2) gives [[0 1] [2 3] [4 5]]. The product of the new dimensions must equal the original size. Twelve elements fit (3, 4) but not (5, 3).

One dimension can be -1, letting NumPy infer its length. np.arange(12).reshape(-1, 3) gives four rows of three; reshape(2, -1) gives two rows of six. Two unknown dimensions are not allowed because their individual lengths cannot be determined from the total alone.

Transpose swaps the axes

For r above, r.T is [[0 3] [1 4] [2 5]], with shape (3, 2). Each old column is now a row. That arrangement differs from r.reshape(3, 2), even though the resulting shapes match.

OperationWhat happens to r
r.reshape(3, 2)Reads values row by row and regroups them
r.TSwaps row and column roles

A transpose is useful when the next operation needs the opposite axis order. A reshape is useful when a sequence already has a meaningful grouping, such as months grouped into quarters.

A 1-D transpose does not make a column

v = np.arange(3) has only one axis, so v.T still has shape (3,). Add an axis explicitly:

column = v[:, np.newaxis]  # shape (3, 1)
row = v[np.newaxis, :]     # shape (1, 3)

v.reshape(-1, 1) and np.expand_dims(v, 1) also create a column. np.squeeze(column) removes its length-one axis and returns shape (3,). Adding an axis changes no values but tells later arithmetic how they should line up.

Flattening and memory sharing

r.ravel() and r.flatten() both list values in a 1-D result. ravel returns a view when possible; flatten always copies. reshape(-1) is another way to request a 1-D arrangement, but whether it shares memory depends on the input's layout. Reshape may need a copy; transpose shares data in its array view. Use .copy() when independent storage is required.

Group monthly values into quarters

For monthly = np.array([120, 135, 150, 160, 155, 170, 180, 175, 165, 150, 140, 130]), monthly.reshape(4, 3) makes four quarter rows, each with three months. Summing each row with .sum(axis=1) gives [405 485 520 420]. The first total is 120 + 135 + 150 = 405. The reshape works because the chronological input already puts each quarter's months together.

Key Takeaways

  • Reshape preserves element count and follows row-major order by default.
  • One -1 dimension can be inferred.
  • Transpose swaps axis roles and can differ from a same-shape reshape.
  • Use a new axis to turn a vector into a row or column.
  • flatten copies; ravel and reshape can share data.

3.2 Join and split arrays

Joining combines values from several arrays. Splitting cuts one array into pieces. First decide whether the operation should extend an existing axis or introduce a new one.

Concatenate along an existing axis

np.concatenate([a, b], axis=0) joins vectors end to end. Joining [1 2] with [3 4 5] gives [1 2 3 4 5].

For two arrays each shaped (2, 3), axis 0 adds rows and gives (4, 3). Axis 1 adds columns and gives (2, 6). Only the joining axis can differ in length. Thus shapes (2, 3) and (2, 2) can join along axis 1 into (2, 5), but cannot join along axis 0 because their column counts disagree.

The arrays must be passed together as a sequence, such as [a, b]. Joining creates a new combined array and copies the inputs' data.

Stack along a new axis

For p = np.array([1, 2, 3]) and q = np.array([4, 5, 6]):

ExpressionShapeArrangement
np.concatenate([p, q])(6,)One longer vector
np.stack([p, q])(2, 3)One vector per row
np.stack([p, q], axis=1)(3, 2)One vector per column

stack requires equal input shapes and adds an axis. concatenate preserves the number of axes. The helper functions express common arrangements: vstack([p, q]) makes rows, hstack([p, q]) joins these 1-D inputs end to end, and column_stack([p, q]) makes columns. The 1-D behavior of hstack is why its name alone is not enough to predict a table.

Cut by boundaries or by part count

np.split(np.arange(10), [3, 7]) cuts before positions 3 and 7, yielding [0 1 2], [3 4 5 6], and [7 8 9]. The boundary positions are not part lengths.

An integer second argument instead requests equal parts: np.split(x, 3) asks for three equal pieces. Ten elements cannot be divided equally into three integer-sized pieces, so this raises ValueError. np.array_split(np.arange(10), 3) allows unequal lengths and produces 4, 3, and 3. These splitting calls return a collection of arrays, not one array with a new stacking axis.

Build a measurement table
h = np.array([1.62, 1.75, 1.80])  # meters
w = np.array([55.0, 72.5, 80.0])  # kilograms
data = np.column_stack([h, w])

Shape (3, 2) means three people with height and mass in columns. Selecting data[:, 1] / data[:, 0] ** 2 calculates mass divided by squared height for each row, giving approximately 21.0, 23.7, and 24.7 kg/m². Keeping the two measurement arrays in the same person order is essential.

If input arrives in batches, collect the batch arrays in a Python list and call concatenate once. Rejoining a growing array during every loop pass repeatedly copies its existing data.

Key Takeaways

  • Concatenation extends an axis; stacking adds one.
  • Nonjoining dimensions must match for concatenation.
  • Use column_stack to turn matching vectors into table columns.
  • Split positions are boundaries; an integer part count requests equal pieces.
  • array_split permits unequal piece lengths.
  • Collect batches first and join once.
4

Replace loops with vectorized arithmetic, ufuncs and broadcasting

Whole-array expressions let you describe numerical work without writing a Python loop for each value. Begin with matching-position arithmetic, then apply NumPy's mathematical functions and combine different shapes through broadcasting. Reading the shapes explains which values pair and which repeat. Casting rules, invalid inputs, and division warnings also matter when a short expression performs many calculations at once.

4.1 Compute element by element instead of looping

Vectorization expresses a calculation for entire arrays. NumPy handles the repeated element-level work in compiled code, so the Python expression can stay close to the calculation you mean.

Translate a loop into matching-position arithmetic
prices = np.array([2.50, 4.00, 1.20])
qty = np.array([3, 1, 5])
line_totals = prices * qty
order_total = line_totals.sum()

The products are [7.5 4. 6.] and their sum is 17.5. Each price pairs with its own quantity. A Python loop updating a total produces the same result, but makes Python handle each pair separately.

All the arithmetic operators act element by element: +, -, *, /, //, %, and **. A scalar applies to every entry. 10 - np.array([1, 2, 3]) gives [9 8 7]; operand order still matters. Two arrays need equal shapes or compatible broadcasting shapes.

Keep element-wise and matrix products distinct

* multiplies corresponding entries. For A = np.array([[1, 2], [3, 4]]) and B = np.array([[5, 6], [7, 8]]), A * B gives [[5 12] [21 32]]. Matrix multiplication uses @ and would give [[19 22] [43 50]]. Choose * for paired measurements such as price and quantity.

Comparisons also return one answer per position

a == b produces a boolean array. It does not ask whether two arrays are equal as whole objects. An if statement needs one truth value, so if a == b: fails for multi-element results. np.array_equal(a, b) tests exact whole-array equality. For approximate decimals, np.allclose(a, b) tests agreement within tolerance.

Understand division warnings

With default NumPy error settings, floating-point division by zero produces a warning and special values:

np.array([1.0, -1.0, 0.0]) / 0
# array([ inf, -inf, nan])

np.isfinite identifies results that are neither infinite nor NaN. Integer floor division by zero instead returns integer zeros with a warning. Those zeros look finite, so inspect integer denominators with (d == 0).any() before floor division. A warning deserves attention even when the program continues.

Decide whether to update in place

a += value modifies existing storage and retains its dtype. If a is an integer array, a += 0.5 raises a casting error because the floating-point result cannot be stored under that operation's casting rule. a = a + 0.5 creates a floating-point result and binds a to it. This differs from assigning one decimal into an integer element, which can silently truncate.

Build a multi-step expression

For old = np.array([2.50, 4.00, 8.00]) and new = np.array([3.00, 3.00, 8.00]), (new - old) / old * 100 gives [20. -25. 0.]. First find each change, then divide by its original value, then express the ratio as a percentage. The signs show a rise, a fall, and no change. The original values must be nonzero for this percentage calculation.

Key Takeaways

  • Vectorized operators calculate on whole arrays element by element.
  • * pairs entries; @ performs a matrix product.
  • Whole-array comparisons need a single-result function.
  • Check denominators and inspect division warnings.
  • In-place arithmetic retains the destination dtype.

4.2 Apply universal functions to whole arrays

A universal function, or ufunc, applies a calculation separately at each array position. These functions extend vectorization beyond ordinary arithmetic to roots, logarithms, rounding, comparisons, and other numerical operations.

Choose an array-aware function

Unary ufuncs take one input. np.sqrt(np.array([1, 4, 9])) gives [1. 2. 3.], and np.abs(np.array([-2, 3])) gives [2 3]. np.exp is the exponential function, np.log is the natural logarithm, and np.log10 is the base-10 logarithm. For example, np.exp(0) is 1.0 and np.log10(1000) is 3.0.

Python's math module works on individual numbers. math.sqrt(np.array([1, 4])) cannot calculate both roots and raises a type error. Use NumPy's version for numerical arrays. Operators also call ufuncs: a + b corresponds to np.add(a, b) and a * b to np.multiply(a, b).

Compare corresponding values or reduce a whole array

Binary ufuncs take two inputs. np.maximum([1, 5, 3], [4, 2, 6]) gives [4 5 6], choosing the larger value at every position. np.minimum chooses the smaller, and np.power raises corresponding bases to powers.

np.maximum(x, 0) sets negative entries to zero in a new result. It is different from np.max(x), an aggregation that returns one largest value. For [1, 5, 3], max gives 5; maximum needs another input and retains the element-wise structure.

Round with the intended rule
FunctionRuleResult for −2.5
np.floorDown toward negative infinity−3.0
np.ceilUp toward positive infinity−2.0
np.truncToward zero−2.0
np.roundNearest; exact halves to even−2.0

np.round(x, 2) keeps two decimal places. Exact halves follow the even rule: np.round([0.5, 1.5, 2.5]) gives [0. 2. 2.]. Binary approximation can affect decimal-looking ties, so interpret displayed decimals with their floating-point representation in mind.

Inspect values outside a function's domain

For real floating-point inputs, np.sqrt(-1.0) returns NaN with a warning, while np.log(0.0) returns negative infinity with a warning under default error settings. Unlike math.sqrt(-1), these calls do not normally halt with a domain exception. Check the inputs when the mathematical operation requires a restricted range. np.isnan marks NaN; np.isfinite marks values that are neither NaN nor infinite; np.isclose compares values with a tolerance.

Combine ufuncs into a useful calculation

For coordinate arrays x = np.array([3, 5, 8]) and y = np.array([4, 12, 15]), calculate distance from the origin with np.sqrt(x ** 2 + y ** 2). Squaring gives [9 25 64] and [16 144 225]; adding gives [25 169 289]; the roots are [5. 13. 17.]. np.hypot(x, y) calculates those distances directly.

Key Takeaways

  • Ufuncs perform numerical operations at each position.
  • Use NumPy functions for arrays, including roots and logarithms.
  • maximum compares positions; max reduces values.
  • Floor, ceiling, truncation, and rounding use different rules.
  • Inspect NaN and infinity after invalid real-valued operations.

4.3 Combine arrays of different shapes with broadcasting

Broadcasting lets arrays with different shapes participate in element-wise calculations. The aligned axes determine which values pair and which repeat.

Compare dimensions from the right

Line up shapes at their right-hand ends. Each pair of axis lengths must be equal or have one length equal to 1. Missing leading axes count as length 1. A length-one axis expands conceptually to match the other length; NumPy need not copy the repeated input values.

For (4, 3) and (3,), the last lengths match at 3. The missing leading dimension acts as 1 and expands to 4. The result is (4, 3): the vector applies to every row. (4, 3) and (4,) fail because the trailing lengths 3 and 4 disagree and neither is 1. An incompatible pair raises ValueError.

Center or standardize columns
X = np.array([[1, 10], [2, 20], [3, 30]])
centered = X - X.mean(axis=0)

The column means are [2. 20.], shape (2,). They line up with the last axis of (3, 2), giving [[-1. -10.] [0. 0.] [1. 10.]]. Dividing the centered result by X.std(axis=0) standardizes each column, producing approximately −1.22, 0, and 1.22 down both columns. Each column's spread must be nonzero for this division.

Keep an axis for row calculations

Use a score table with four students and three tests:

scores = np.array([[78, 85, 92], [64, 70, 58],
                   [88, 91, 95], [72, 68, 80]])

scores.mean(axis=1) has shape (4,). It cannot broadcast as one mean per row against (4, 3). Preserve the removed axis:

row_mean = scores.mean(axis=1, keepdims=True)
centered = scores - row_mean

row_mean now has shape (4, 1). Its leading 4 matches the rows; its trailing 1 expands across three columns. scores.mean(axis=1)[:, np.newaxis] creates the same shape. For the row [78, 85, 92], subtracting its mean of 85 gives [-7. 0. 7.].

Use the same rule to build a table

np.arange(1, 4)[:, np.newaxis] * np.arange(1, 5) combines (3, 1) and (4,). Both arrays expand to the result shape (3, 4), producing [[1 2 3 4] [2 4 6 8] [3 6 9 12]].

Expansion can also be accidental. A (3, 1) column minus a (3,) vector creates all nine pairwise differences, shape (3, 3). If you intended three corresponding differences, make both inputs shape (3,), for example with column.ravel().

Weight each column before adding

For the same score table and w = np.array([0.2, 0.3, 0.5]), scores * w applies the three weights to every row. Summing with .sum(axis=1) gives [87.1 62.8 92.4 74.8]. The first result is 15.6 + 25.5 + 46.0 = 87.1.

Key Takeaways

  • Align shapes from the right; paired lengths must match or include 1.
  • A length-one axis controls the direction of expansion.
  • Column summaries usually align with a table directly.
  • Keep row summaries shaped as columns with keepdims=True.
  • Broadcasting can create an unintended pairwise table.
  • Weight columns before reducing across each row.
5

Summarize arrays with aggregations along axes

A table can produce an overall total, one summary per record, or one summary per variable. Decide which axis to collapse, then choose a statistic that answers your question. Positions, running totals, and sorted ranks offer different views of the data. Missing values and conditions require their own decisions, because filtering or filling can change both which observations contribute and what the result means.

5.1 Aggregate a whole array or along one axis

An aggregation combines values into fewer results: a total, mean, extreme, or measure of spread. Choosing the axis is part of choosing the question, because it decides which groups of values are combined.

Collapse the axis you name

For a (4, 3) table with four students and three tests, an aggregation without axis uses all 12 values. scores.sum() gives one total. scores.mean(axis=0) collapses the student axis and leaves three test means. scores.mean(axis=1) collapses the test axis and leaves four student means.

scores = np.array([[78, 85, 92], [64, 70, 58],
                   [88, 91, 95], [72, 68, 80]])

Its overall sum is 941. The column means are [75.5 78.5 81.25]; the row means are approximately [85. 64. 91.33 73.33]. Ask which axis should disappear. Saying “axis 0 means each row” reverses the operation: axis 0 combines rows.

Choose the quantity to return
OperationResult type
sum, prodTotal or product
meanArithmetic average
min, maxExtreme value
argmin, argmaxPosition of an extreme
std, varStandard deviation or variance

Methods such as a.sum() and functions such as np.sum(a) express the same basic operation. NumPy's methods avoid the different behavior of Python's built-ins. For example, Python's sum(scores) adds row arrays to produce column totals, while scores.sum() combines all entries. Python's max(scores) tries to compare rows and raises an ambiguous-truth error.

Positions differ from values

scores.mean(axis=1).argmax() is 2: the third student has the highest mean. argmax returns the first position when maxima tie. Without an axis on a table, it returns a row-major flattened index; scores.argmax() is 8. np.unravel_index(8, scores.shape) recovers coordinate (2, 2).

Use keepdims=True when a summary must align with the original table. scores.sum(axis=1, keepdims=True) has shape (4, 1), making it suitable for one normalization value per row. Without it, the result has shape (4,).

Keep intermediate totals when order matters

np.cumsum([3, 1, 4, 1, 5]) gives [3 4 8 9 14]. Each position is the total through that point. np.cumprod([1, 2, 3, 4]) similarly gives [1 2 6 24]. np.diff([3, 1, 4, 1, 5]) gives the four neighbor changes [-2 3 -3 4]. On a table, specify axis=1 for separate running totals across rows.

State the spread convention

std and var divide the squared-deviation total by the number of values by default: ddof=0. Use ddof=1 for the sample formula, whose divisor is one smaller. For [2, 4, 4, 4, 5, 5, 7, 9], the mean is 5, the default standard deviation is 2.0, and the sample standard deviation is about 2.14. A report should make clear which convention it uses.

Key Takeaways

  • The axis argument names the axis being collapsed.
  • No axis means one summary across the whole array.
  • argmin and argmax return positions, including the first tied position.
  • keepdims=True retains reduced axes at length 1.
  • Cumulative functions retain intermediate results.
  • NumPy uses ddof=0 by default; ddof=1 selects the sample divisor.
  • Prefer NumPy aggregations to Python built-ins on arrays.

5.2 Use medians, percentiles, sorting and unique values

Order-based summaries describe where values sit in a sorted distribution. Sorting also supports ranking records, but a table needs careful treatment to keep each record's fields together.

Locate the middle and the quartiles

For x = np.array([12, 15, 11, 20, 18, 14]), the sorted order is [11 12 14 15 18 20]. With six values, np.median(x) averages the middle two, 14 and 15, giving 14.5. For an odd count, the median is the one middle value.

np.percentile(x, q) takes a percentage from 0 to 100. np.quantile(x, q) takes the equivalent fraction from 0 to 1. Their default linear interpolation can give a value between observations. For six values, the 25th percentile's zero-based position is 0.25 × 5 = 1.25. That lies one quarter of the way from 12 to 14, giving 12.5. The 50th and 75th percentiles are 14.5 and 17.25, so the interquartile range is 4.75.

The median resists an extreme value more than the mean does. Adding 200 to these data moves the mean from 15.0 to about 41.4; the median moves from 14.5 to 15.0. Neither measure alone describes the whole distribution.

Choose sorted data or sorting positions

np.sort(x) returns a sorted copy. x.sort() changes x and returns None, so y = x.sort() does not put sorted values into y. For descending values, use np.sort(x)[::-1].

On a 2-D array, sorting defaults to the last axis, sorting each row independently. axis=0 sorts each column independently. Neither operation is a record sort. For tab = np.array([[3, 1], [1, 2], [2, 0]]), np.sort(tab, axis=0) gives [[1 0] [2 1] [3 2]], separating values that originally belonged together.

To preserve records, get an ordering from the key column and apply it to whole rows:

order = tab[:, 0].argsort()
ranked = tab[order]
# array([[1, 2], [2, 0], [3, 1]])

The same index order can reorder related vectors. If avg = np.array([85.0, 64.0, 91.33, 73.33]) and names = np.array(['Ana', 'Ben', 'Chen', 'Dara']), order = np.argsort(avg)[::-1] ranks the means in descending order. names[order] gives ['Chen' 'Ana' 'Dara' 'Ben'].

Count distinct values and test membership

np.unique returns sorted distinct values. With return_counts=True, it also returns corresponding counts:

colors = np.array(['red', 'blue', 'red', 'green', 'blue', 'red'])
values, counts = np.unique(colors, return_counts=True)

The outputs are ['blue' 'green' 'red'] and [2 1 3]. values[counts.argmax()] finds the most frequent value, 'red'. The count positions match the unique-value positions.

np.isin(a, allowed) returns a mask for membership in a collection. For a = np.arange(1, 6), np.isin(a, [2, 4]) gives [False True False True False], ready to select those values or their associated records.

Key Takeaways

  • The median uses sorted position and resists extreme values.
  • Percentiles use 0–100; quantiles use 0–1.
  • Default percentile interpolation can fall between observations.
  • np.sort copies; an array's .sort() mutates and returns None.
  • Use argsort positions to keep records and related arrays aligned.
  • unique(..., return_counts=True) pairs distinct values with frequencies.
  • isin builds a membership mask.

5.3 Summarize data with missing values and conditions

Missing data and filtered subsets need an explicit summary policy. A numerical result can be wrong even when the array operation runs successfully: a placeholder can be counted as a measurement, or an empty subset can be mistaken for a meaningful average.

Find missing values before summarizing

NaN propagates through ordinary sums and means. For x = np.array([3.0, np.nan, 5.0]), both x.sum() and x.mean() give NaN. np.nansum(x) gives 8.0 and np.nanmean(x) gives 4.0, skipping the missing position. Related functions include nanmax, nanmin, nanstd, and nanmedian. If every value is missing, nanmean returns NaN with a warning because no observed values remain.

For sensor readings in °C:

r = np.array([21.5, np.nan, 22.1, 23.0, np.nan, 21.9])
missing = np.isnan(r)

missing.sum() is 2, missing.mean() is about 0.33, and r[~missing] keeps four readings. np.nanmean(r) is 22.125, using only those four values. Comparing r == np.nan would fail to mark the missing readings.

Convert placeholder codes first

A number such as −999 may represent missing data in an input system. NumPy treats it as a real measurement until you replace it:

v = np.array([12, -999, 15, -999, 9]).astype(float)
v[v == -999] = np.nan
np.nanmean(v)  # 12.0

Convert to float first because an integer array cannot store NaN. This replacement is appropriate only when −999 is defined as the missing code for those data.

Filling changes the distribution

Replacing missing temperatures with zero makes the example's mean 14.75, even though no zero-temperature measurement was observed. Filling them with the observed mean, 22.125, preserves that mean but reduces the apparent spread. A filled value is an introduced estimate, so its effect belongs in the analysis decision.

For a 2-D table D, np.nanmean(D, axis=0) summarizes each column's observed values. Each column can have a different count. To drop rows containing any missing value:

complete = ~np.isnan(D).any(axis=1)
clean_rows = D[complete]

The reduction creates one decision per row; negation retains rows with no missing entries. With D = np.array([[1., 2.], [np.nan, 4.], [5., np.nan], [7., 8.]]), this keeps [[1. 2.] [7. 8.]].

Summarize a condition or a group

For temperatures t, t[t > 20].mean() averages only days above 20 °C. In grouped data, use a matching label mask: with group = np.array(['A', 'B', 'A', 'B', 'A']) and value = np.array([10, 20, 14, 26, 12]), value[group == 'A'].mean() is 12.0 and the corresponding B mean is 23.0. Iterate over np.unique(group) to repeat this for each group.

Before summarizing a filtered subset, check mask.any(). An empty selection's mean is NaN with a warning, while its sum is 0. That zero can be a valid empty total, but it does not establish that any measurement was present.

Key Takeaways

  • Ordinary sums and means propagate NaN; NaN-aware versions skip it.
  • Convert defined missing codes to NaN in floating-point storage.
  • Filling missing values changes the statistics.
  • Row-wise missing-value tests can identify complete records.
  • Combine label or condition masks with aggregations.
  • Check for an empty subset before interpreting its mean.
6

Generate random numbers and run simulations

Random arrays support repeatable sampling and practical experiments. Create one seeded Generator, choose a distribution and output shape, and preserve record relationships when shuffling or splitting data. In a simulation, make the trial structure explicit before calculating events or running positions. Compare results with simple exact cases, and separate ordinary sampling variation from mistakes in the code.

6.1 Draw reproducible random samples with a Generator

A random number generator supports sampling, shuffling, and simulation. A seed makes the starting state repeatable, so you can rerun an analysis while investigating its logic.

Create one Generator and reuse it
rng = np.random.default_rng(42)

NumPy recommends this Generator interface for new code. Its default bit generator is PCG64. Without a seed, default_rng() obtains fresh entropy from the operating system. Older calls such as np.random.seed and np.random.rand use shared global state; Generator objects let an analysis manage its own state directly.

Pseudorandom values come from a deterministic algorithm. The same starting state and same sequence of calls reproduce the stream in the same environment. Every draw advances the state. Creating a new Generator with seed 42 inside every loop pass restarts the stream, repeating the same initial draws instead of continuing it. Record the NumPy version and the code as well as the seed, because stream compatibility is not guaranteed across versions or all environments. For passwords or security tokens, use Python's secrets module.

Pick a distribution and an output shape
CallMeaning
rng.random(5)Five decimals from 0 inclusive to 1 exclusive
rng.uniform(2, 8, size=5)Five uniform draws over the interval from 2 to 8
rng.integers(1, 7, size=10)Ten integers from 1 through 6
rng.normal(loc=170, scale=10, size=(3, 4))A 3-by-4 sample from a normal distribution

size can be an element count or a shape tuple. For normal, loc is the distribution mean and scale is its standard deviation. A variance of 100 therefore needs scale=10. A small sample's actual mean and standard deviation need not match the distribution parameters exactly.

For integer draws, the upper bound is excluded by default. A die needs integers(1, 7), since integers(1, 6) cannot draw 6. integers(1, 6, endpoint=True) includes the upper bound and also models a die.

Sample values with or without replacement

rng.choice(['heads', 'tails'], size=5) makes five draws with replacement. A value can appear several times. For distinct sampled positions, use replace=False; requesting more positions than the population has raises ValueError. Probabilities can be supplied as p=[0.7, 0.3], in the same order as the values, and must sum to 1.

Without replacement prevents selecting an input position twice. If the input itself contains duplicate values, equal values can still appear in the sample.

Shuffle records without separating their fields

rng.shuffle(a) rearranges the existing array and returns None. rng.permutation(a) returns a shuffled copy. rng.permutation(10) gives integers 0 through 9 in random order, useful as row indexes.

For a 2-D array, the default axis is 0: complete rows move together. That keeps each observation's fields aligned. To shuffle two related arrays consistently, generate one permutation of their shared record indexes and apply it to both.

Key Takeaways

  • Create a seeded Generator once and reuse its advancing state.
  • Reproducibility depends on the seed, calls, and numerical environment.
  • Integer draws exclude the upper bound unless endpoint=True.
  • Normal scale is standard deviation, not variance.
  • choice samples with replacement by default.
  • shuffle mutates; permutation returns a shuffled result.

6.2 Run vectorized simulations

A vectorized simulation represents repeated trials as arrays, applies the event rule to those arrays, and summarizes the results. The array shape should show what one trial contains.

Turn an event into a proportion
rng = np.random.default_rng(42)
rolls = rng.integers(1, 7, size=100_000)
estimate = (rolls == 6).mean()

The mask is true once for every observed 6. Its mean estimates the probability of that event, close to 1/6, or about 0.1667. rolls.mean() answers a different question: the average die face, close to 3.5. A fixed seed repeats an estimate; it does not make that estimate exact.

Vectorization avoids Python-level work for each draw, often making large simulations much faster than a loop. The speedup depends on the calculation, array size, and computer, so it is not a fixed property of the event.

Use one row per multi-value trial

To simulate two dice in each trial:

dice = rng.integers(1, 7, size=(100_000, 2))
totals = dice.sum(axis=1)
p_seven = (totals == 7).mean()

The table has 100,000 trial rows and two die columns. Reducing axis 1 produces one total per trial. Six of the 36 equally likely ordered pairs sum to 7, so the estimated probability should be near 6/36. Reducing axis 0 would instead give two totals across all trials and lose the trial-level event.

Larger simulations still vary

For independent trials, the standard error of an estimated proportion is:

p(1−p)n

Here p is the event probability and n the trial count. For a die's 6 with 100,000 trials, it is about 0.0012. A normal approximation puts about 95% of estimates within 0.0023 of 1/6. Increasing the trial count by a factor of 100 reduces standard error by a factor of 10. More draws do not correct an incorrectly coded event.

Build and inspect a random walk

steps = rng.choice([-1, 1], size=1000) draws left or right steps. walk = steps.cumsum() gives the position after each step. Its maximum and minimum locate the extreme positions visited. To find the first point at least 10 units from the start:

hit = np.abs(walk) >= 10
if hit.any():
    step_count = hit.argmax() + 1

argmax locates the first true entry, but also returns 0 when every entry is false. The any() check distinguishes a real hit from no hit. Add 1 because array position 0 is the position after step 1.

For many walks, rng.choice([-1, 1], size=(5000, 1000)).cumsum(axis=1) accumulates separately along each row. walks[:, -1] selects all final positions; their mean is near 0 and standard deviation near the square root of 1,000, about 31.6.

Use permutations and exact checks

A random split of 100 records can use idx = rng.permutation(100), then data[idx[:80]] and data[idx[80:]]. The two disjoint slices of one permutation assign every record exactly once. For a simulation, compare a simple case with an exact answer, such as a die mean of 3.5, before trusting more complicated output.

Key Takeaways

  • Represent one trial clearly in the array shape.
  • A boolean mean estimates an event probability.
  • Reduce within trials before combining results across trials.
  • Standard error shrinks with the square root of trial count.
  • Check for a hit before using argmax as a first-hit locator.
  • One permutation can produce disjoint random record splits.
  • Validate simulation logic against an exact simple case.

NumPy Arrays examples

6 Walkthroughs

1

Build a measurement array you can trust

14 steps
Create and inspect an array, choose its initial values, and retain decimals and missing data correctly.
  1. 1
    IntroductionPlan the records and measurements

    A measurement table needs two decisions before any calculation: what each axis represents and what kind of values must be stored. We will build a small table, inspect its shape, and choose creation and conversion methods that preserve the data.

    Keep import numpy as np at the top of the script. The name np gives access to the NumPy functions used throughout the examples.

  2. 2
    ExplanationRead a table through its axes

    Create a = np.array([[2, 4, 6], [3, 5, 7]]). The outer sequence supplies two rows; each inner sequence supplies three values.

    a.shape is (2, 3), a.ndim is 2, and a.size is 6. Shape describes the arrangement, ndim counts axes, and size counts all entries. If each row is one record, this table contains two records with three measurements each.

  3. 3
    Key InsightEqual sizes can have different structures

    A length-six vector has shape (6,). A table with one row has shape (1, 6), and a table with one column has shape (6, 1). Each contains six values, but only the last two have separate row and column axes.

    The trailing comma in (6,) marks a one-entry tuple. It is useful information: the vector has one axis, so it has no separate row direction to transpose into a column.

  4. 4
    ChallengePredict multiplication before running it

    What are the results of [2, 5] * 2 and np.array([2, 5]) * 2?

    ---reveal---

    The list becomes [2, 5, 2, 5]. The array becomes [4 10]. Lists repeat their contents under integer multiplication; numerical arrays multiply the values at each position. The array keeps its shape, which makes it suitable for applying a calculation to every recorded value.

  5. 5
    ExampleReserve a table with a known shape

    Suppose two stations will each supply four rainfall readings in millimeters. Create rain = np.zeros((2, 4)), then assign rain[0] = [4.0, 0.0, 3.5, 6.0].

    The tuple (2, 4) is one shape argument. Zeros uses floating-point storage by default, so the reading 3.5 is retained. Reserving the final shape once avoids repeatedly copying a growing array as readings arrive.

  6. 6
    TipChoose the starting fill deliberately

    Use zeros when initial zeros are meaningful, ones for ones, and full(shape, value) for another repeated value. Their names describe the starting contents.

    empty only reserves storage. Its initial values are not ready to use, so every entry must be filled before it is read. A zeros-filled table is easier to inspect while writing code that will assign only some of its entries.

  7. 7
    ExplanationCount points and gaps separately

    For measurement positions from 0 m through 2 m at intervals of 0.5 m, there are five points and four gaps. np.linspace(0, 2, 5) creates those points and includes both ends.

    np.arange(0, 2, 0.5) uses a step and excludes the stop, so it omits 2 m. Floating-point rounding can also make decimal arange grids surprising; use linspace when the point count is the requirement.

  8. 8
    ChallengeChoose a grid from its endpoints

    A scan requires nine equally spaced positions from 0 cm to 4 cm, including both ends. What creation call fits, and what is the spacing?

    ---reveal---

    Use np.linspace(0, 4, 9). Nine points make eight gaps across 4 cm, so the spacing is 0.5 cm. A third argument of 8 would request eight points, leaving only seven gaps and producing a different interval between readings.

  9. 9
    ExplanationInspect the inferred dtype

    np.array([1, 2.5]) becomes floating-point because one shared dtype must hold both values. Mixing a number with text can instead turn all values into text, causing arithmetic to fail.

    Inspect a.dtype when the values do not behave as expected. a.itemsize reports the storage bytes per element; multiplying it by a.size gives a.nbytes, the total bytes occupied by the elements.

  10. 10
    ExampleWatch an assignment discard decimals

    Start with counts = np.array([2, 4, 6]), then run counts[0] = 3.8. The first entry becomes 3 because the existing storage remains integer.

    To retain later decimals, create floating-point storage first with values = counts.astype(float). astype makes a converted copy. It does not change the dtype of the original array or recover fractional information that an earlier assignment already discarded.

  11. 11
    Key InsightConversion and rounding are separate

    np.array([2.8, -2.8]).astype(int) gives [2 -2]: truncation moves toward zero. np.round rounds to nearest, with exact halves going to even, so 2.5 rounds to 2.0.

    Small integer dtypes introduce a different risk. A uint8 cannot hold 260, so array arithmetic such as 250 plus 10 can wrap to 4. Widen the dtype before calculating values that may exceed its range.

  12. 12
    ChallengePreserve a missing reading

    You have a = np.array([5, 7, 9]) and need to mark its middle reading missing. What preparation does the array need before assigning NaN?

    ---reveal---

    Convert to floating-point storage: a = a.astype(float), then set a[1] = np.nan. Integer storage cannot represent NaN. The result is [5. nan 9.]; substituting zero would record a numerical value instead of marking a missing measurement.

  13. 13
    ChallengeCombine creation and a later update

    You create template = np.array([1, 2]), then need a same-shaped array whose values can later include 1.5 and NaN. What creation choice keeps those values possible?

    ---reveal---

    Use a floating dtype, for example np.zeros_like(template, dtype=float). The default like-function would inherit integer storage. The shape can stay (2,), while choosing float allows both the fractional measurement and the missing-value marker.

  14. 14
    RecapInspect structure before calculating

    For the next array you create, inspect shape, size, and dtype before applying arithmetic. Check that each axis represents the intended group of values and that storage can hold the measurements you will assign.

    Choose a point count or a step deliberately when generating a grid. If decimal values or NaN will appear, plan floating-point storage before writing those values into the array.

2

Select records and control what edits change

16 steps
Use indexes, copies, and boolean masks to select and update the intended numerical data.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionAsk which values belong in the result
  2. 2
    ExplanationFollow start, stop, and step
  3. 3
    ExampleSelect rows and columns in one expression
  4. 4
    ChallengeKeep a column axis
  5. 5
    ExampleTrace a write through a view
  6. 6
    TipMake independence explicit
  7. 7
    ExplanationPair coordinates or choose a block
  8. 8
    ChallengeSeparate a copy from a direct assignment
  9. 9
    ExplanationTurn a condition into a selection
  10. 10
    ExampleCombine interval bounds
  11. 11
    Key InsightCount events or average their values
  12. 12
    ExampleChoose replacement or filtering
  13. 13
    ChallengeRetain complete rows
  14. 14
    TipFind NaN without equality
  15. 15
    ChallengeUpdate selected records independently
  16. 16
    RecapCheck the target of each edit
3

Give values the right shape and grouping

12 steps
Reshape a sequence, swap its axes, then join and split related arrays while preserving their structure.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionMake grouping visible in the shape
  2. 2
    ExampleGroup consecutive values into periods
  3. 3
    ExplanationInfer one missing dimension
  4. 4
    ExampleSwap the meaning of rows and columns
  5. 5
    ChallengeCreate a column from a vector
  6. 6
    TipChoose flattening with editing in mind
  7. 7
    ExplanationExtend an existing axis
  8. 8
    ExampleAdd a batch axis instead
  9. 9
    ChallengeMake two measurement columns
  10. 10
    ExampleSplit by boundaries or part count
  11. 11
    ChallengeRebuild a table from row batches
  12. 12
    RecapRead shapes as data decisions
4

Calculate across records without a Python loop

15 steps
Use element-wise expressions, array-aware functions, and broadcasting to calculate paired and grouped results.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionLet the expression describe the calculation
  2. 2
    ExampleMultiply paired values and total them
  3. 3
    ExplanationUse the right product operator
  4. 4
    TipCheck the destination and denominator
  5. 5
    ChallengeChoose the reference for percentage change
  6. 6
    ExplanationApply mathematical functions to arrays
  7. 7
    ExampleBuild distances in stages
  8. 8
    ChallengeCompare maximum with a reduction
  9. 9
    TipInspect rounding and invalid values
  10. 10
    ExplanationAlign shapes from their right ends
  11. 11
    ExampleKeep row means as a column
  12. 12
    Key InsightA valid broadcast can answer the wrong question
  13. 13
    ChallengePredict a broadcast result
  14. 14
    ChallengeWeight centered measurements
  15. 15
    RecapCheck values, pairing, and output shape
5

Summarize the observations that answer your question

15 steps
Choose reduction axes, sort complete records, and handle missing values and filtered subsets explicitly.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionChoose the question before the statistic
  2. 2
    ExampleReduce the measurement axis
  3. 3
    Key InsightTrack what survives the reduction
  4. 4
    ExampleSeparate position, value, and running total
  5. 5
    ChallengeChoose the variance divisor
  6. 6
    ExampleLocate a median and percentile
  7. 7
    TipSort records through positions
  8. 8
    ChallengeRecover a label from its count
  9. 9
    ExplanationSkip missing values deliberately
  10. 10
    ExampleTranslate a missing code before averaging
  11. 11
    Key InsightFilling creates observations for the calculation
  12. 12
    ExampleBuild one completeness decision per row
  13. 13
    ChallengeRecognize an empty subset
  14. 14
    ChallengeSummarize and compare groups
  15. 15
    RecapReport what contributed to each summary
6

Run a reproducible simulation from draws to results

14 steps
Create a Generator, organize trials, estimate an event probability, and inspect random-walk paths.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionGive each simulated trial a clear shape
  2. 2
    ExplanationCreate the Generator once
  3. 3
    ExampleSet integer and normal draw parameters
  4. 4
    ChallengeFind the repeated randomness bug
  5. 5
    TipChoose replacement and preserve records
  6. 6
    ExampleEstimate an event with a mask
  7. 7
    ExampleReduce within each two-die trial
  8. 8
    ChallengeChange the event to either die
  9. 9
    ExplanationExpect sampling variation
  10. 10
    ExampleAccumulate steps into a path
  11. 11
    TipCheck that the boundary was reached
  12. 12
    ChallengeSplit records exactly once
  13. 13
    ChallengeDecide what a much larger run can fix
  14. 14
    RecapCheck the model and then its precision

NumPy Arrays practice questions

50 Practice Questions in 5 sets

Set 1: Connect selections, shapes, and summaries10 Practice Questions

Question 1 of 10

What does np.arange(4, 16, 5) create?
  1. [4, 9, 14, 16]
  2. [4, 8, 12]
  3. [0, 5, 10, 15]
  4. [4, 9, 14]
Show answerHide answer
Answer: D
The sequence starts at 4 and adds 5, giving 4, 9, and 14 before the next value would exceed the stop. The stop 16 is excluded and is not appended as a final endpoint. Starting at zero would ignore the explicitly supplied start value of 4.

Question 2 of 10

After template = np.array([2, 4, 6]), what values are created by np.full_like(template, 1.8) with the default dtype?
  1. [1, 1, 1]
  2. [1.8, 1.8, 1.8]
  3. [2, 2, 2]
  4. [2, 4, 6]
Show answerHide answer
Answer: A
The like-function inherits the integer dtype of template as well as its shape. Filling that storage with 1.8 converts each value to 1, so all three entries are 1. Inferring a new floating dtype from the fill value would be the behavior of np.full, not this default full_like call.

Question 3 of 10

What is a after a = np.arange(7); b = a[1:5]; c = a[[1, 4]]; b[1] = 90; c[0] = 80?
  1. [0, 80, 90, 3, 4, 5, 6]
  2. [0, 1, 2, 3, 4, 5, 6]
  3. [0, 1, 90, 3, 4, 5, 6]
  4. [0, 90, 2, 3, 80, 5, 6]
Show answerHide answer
Answer: C
The slice b shares data with a, and its index 1 refers to original index 2, so 90 reaches that position. The fancy-indexed c is an independent copy, so assigning 80 into it leaves a unchanged. Treating both selections as views would incorrectly put 80 into original index 1.

Question 4 of 10

For a = np.array([3, 6, 9, 12, 15, 18, 21]), what values does a[1:6:2] select?
  1. [6, 12, 18, 21]
  2. [6, 12, 18]
  3. [3, 9, 15]
  4. [6, 9, 12, 15, 18]
Show answerHide answer
Answer: B
Start at index 1 and move by two positions, selecting indexes 1, 3, and 5. Their values are 6, 12, and 18. Index 6 is outside the excluded stop, so 21 is not included; a step of 2 skips intervening entries rather than taking every value in the interval.

Question 5 of 10

Arrays a and b have shapes (3, 2) and (3, 5). What shape does np.concatenate([a, b], axis=1) have?
  1. (6, 5)
  2. (3, 2, 5)
  3. (3, 7)
  4. (2, 3, 5)
Show answerHide answer
Answer: C
Concatenation along axis 1 extends the columns, adding 2 and 5 while keeping the three matching rows. The result is (3, 7). Introducing a third dimension would require a stacking operation; concatenation extends an existing axis and does not add a new one.

Question 6 of 10

For x = np.array([-3.5, 2.5]), what does np.floor(x) - np.trunc(x) give?
  1. [-1., 0.]
  2. [0., 0.]
  3. [1., 0.]
  4. [-1., -1.]
Show answerHide answer
Answer: A
Floor gives [-4., 2.], while truncation gives [-3., 2.], so subtracting gives [-1., 0.]. Both functions agree for the positive input but differ for the negative input. Treating floor as cutting off decimals would incorrectly make the negative difference zero.

Question 7 of 10

For displacement vectors x = np.array([6., 8.]) and y = np.array([8., 15.]) in meters, keep only points at most 12 m from the origin. What are the retained distances?
  1. [10., 17.]
  2. [14.]
  3. [10., 12.]
  4. [10.]
Show answerHide answer
Answer: D
Compute paired distances with np.hypot(x, y), obtaining 10 m and 17 m, then filter those distances by the 12 m limit. Only 10 m remains. Adding coordinate magnitudes gives 14 and 23, which measures a different path; clipping 17 down to 12 would replace an out-of-range distance instead of excluding the point.

Question 8 of 10

For x = np.array([10., np.nan, 16., np.nan, 22.]), what is the mean after replacing every NaN with zero?
  1. 16.0
  2. 9.6
  3. 12.0
  4. 19.2
Show answerHide answer
Answer: B
Zero filling leaves five entries with a total of 48, so the mean becomes 48 divided by 5, or 9.6. The observed-value mean is 16.0 because it divides by only three present measurements. Filling with zero changes the denominator without adding observed measurements to the total.

Question 9 of 10

What happens when rng.choice(np.arange(5), size=6, replace=False) is called?
  1. It returns six draws with one repeated position allowed.
  2. It returns five draws after reducing the requested size.
  3. It returns six distinct integer labels from 0 through 5.
  4. It raises an error because six distinct positions are unavailable.
Show answerHide answer
Answer: D
Sampling without replacement cannot select more distinct input positions than the five available. The requested size of six therefore raises ValueError. Repeated draws would be possible with replacement, but that is explicitly disabled here; NumPy does not silently shrink the requested sample.

Question 10 of 10

dice contains 60,000 trials of three fair dice with shape (60000, 3). What expression estimates the chance that a trial contains at least one 6?
  1. (dice == 6).any(axis=1).mean()
  2. (dice == 6).all(axis=1).mean()
  3. (dice == 6).mean(axis=1).mean()
  4. (dice == 6).any(axis=0).mean()
Show answerHide answer
Answer: A
First mark sixes, then use any(axis=1) to turn each trial row into one success decision. The mean across those decisions estimates the share of trials with at least one 6. Taking the mean of all die-level comparisons estimates the chance that one die is a 6, losing the trial-level event.
Set 2: Read arrays and choose the right operation10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A table has one row per machine and one column per day. What expression gives one total per machine?
  1. data.sum(axis=0)
  2. data.sum()
  3. data.sum(axis=1)
  4. data.cumsum(axis=1)
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A record table is d = np.array([[9, 30], [2, 80], [5, 40]]). How can you sort records by their first column, smallest first, while keeping each row together?
  1. np.sort(d, axis=0)
  2. d[d[:, 0].argsort()]
  3. d[d[:, 1].argsort()]
  4. np.sort(d, axis=1)
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A generator must draw 20 possible die faces, with all six faces available. What call has the correct integer bounds?
  1. rng.integers(1, 6, size=20)
  2. rng.integers(0, 6, size=20)
  3. rng.integers(1, 7, size=20)
  4. rng.integers(1, 7, size=6)
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What is np.arange(8).reshape(2, 4).T[1]?
  1. [2, 3]
  2. [4, 5, 6, 7]
  3. [0, 4]
  4. [1, 5]
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

An array holds 8 records with 5 measurements per record, one record per row. What is its shape?
  1. (5, 8)
  2. (40,)
  3. (8, 5)
  4. (8, 5, 40)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

You need seven equally spaced positions from 0 m to 3 m, including both ends. What call creates them?
  1. np.arange(0, 3, 0.5)
  2. np.linspace(0, 3, 7)
  3. np.linspace(0, 3, 6)
  4. np.arange(0, 3, 7)
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What values result from np.array([4.9, -4.9]).astype(int)?
  1. [4, -4]
  2. [5, -5]
  3. [4, -5]
  4. [5, -4]
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

For v = np.array([2, 8, 11, 5, 14]), what fraction does (v >= 8).mean() return?
  1. 3.0
  2. 0.4
  3. 11.0
  4. 0.6
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Old unit prices are np.array([5., 8.]) and new prices are np.array([6., 6.]). What percentage changes does (new - old) / old * 100 give?
  1. [20., -25.]
  2. [16.67, -33.33]
  3. [1., -2.]
  4. [-20., 25.]
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A table has rows [batch_id, mass_kg]: d = np.array([[1, 4], [2, 9], [1, 7], [2, 5]]). What is the mean mass of batch 1 records whose mass exceeds 5 kg?
  1. 5.5
  2. 7.0
  3. 8.0
  4. 4.0
Show answerHide answer

Save this lesson to see this answer.

Set 3: Trace data through several array operations10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

Using NumPy's default interpolation, what is np.percentile([4, 8, 12, 20], 25)?
  1. 6.0
  2. 8.0
  3. 7.0
  4. 10.0
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

For x = np.array([1., 3., 5.]), what is x.var(ddof=1)?
  1. 2.6667
  2. 4.0
  3. 2.0
  4. 8.0
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What results from a = np.array([8, 12]); a[0] = 3.7; b = a / 2?
  1. a is [3.7, 12.]; b is [1.85, 6.].
  2. a is [3, 12]; b is [1.5, 6.].
  3. a is [4, 12]; b is [2., 6.].
  4. a is [3, 12]; b is [1, 6].
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

For m = np.arange(20).reshape(4, 5), what are the shape and values of m[1:3, 2:3]?
  1. (2,), with values [7, 12]
  2. (2, 2), with rows [7, 8] and [12, 13]
  3. (1, 2), with row [7, 12]
  4. (2, 1), with rows [7] and [12]
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

For an array t with shape (3, 4, 5), what shape does t[1, :, 2:4] have?
  1. (4, 2)
  2. (1, 4, 2)
  3. (4,)
  4. (2, 4)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Hourly readings v = np.arange(1, 13) are grouped into four consecutive three-hour periods. After swapping the period and within-period axes, what is the first row?
  1. [1, 2, 3, 4]
  2. [1, 5, 9]
  3. [1, 4, 7, 10]
  4. [3, 6, 9, 12]
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What piece lengths does np.array_split(np.arange(14), 4) produce?
  1. 4, 4, 3, 3
  2. 3, 3, 4, 4
  3. 4, 4, 4, 2
  4. 3, 3, 3, 5
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

For A = np.array([[2, 3], [4, 5]]), what does A * A return?
  1. [[16, 21], [28, 37]]
  2. [[4, 6], [8, 10]]
  3. [[2, 3], [4, 5], [2, 3], [4, 5]]
  4. [[4, 9], [16, 25]]
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Rows of X are [2., 6.] and [8., 12.]. Each row needs its own mean subtracted. What result does the mistaken expression X - X.mean(axis=1) actually give?
  1. [[-2., 2.], [-2., 2.]]
  2. [[-3., -3.], [3., 3.]]
  3. [[-2., -4.], [4., 2.]]
  4. [[-5., -1.], [1., 5.]]
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Each row of steps contains five ±1 moves for one walk. You need the share of walks that reach at least 3 units from the start at any recorded step. What expression calculates that share?
  1. (np.abs(steps.cumsum(axis=1)) >= 3).any(axis=1).mean()
  2. (np.abs(steps.cumsum(axis=0)) >= 3).any(axis=1).mean()
  3. (np.abs(steps.sum(axis=1)) >= 3).mean()
  4. (np.abs(steps.cumsum(axis=1)) >= 3).all(axis=1).mean()
Show answerHide answer

Save this lesson to see this answer.

Set 4: Diagnose results that look plausible10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A numerical array a has shape (6, 4) and itemsize == 8. You run b = a[::2, 1:], then c = b[:, ::2].copy(). How many bytes of element storage does c have?
  1. 48
  2. 72
  3. 192
  4. 24
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What does np.array([4, 7]) * 3 produce?
  1. [4, 7, 4, 7, 4, 7]
  2. [7, 10]
  3. [12, 21]
  4. [4, 7, 3]
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

For m = np.arange(12).reshape(3, 4), what is m[[0, 2], [1, 3]]?
  1. [[1, 3], [9, 11]]
  2. [1, 3]
  3. [[4, 5, 6, 7], [8, 9, 10, 11]]
  4. [1, 11]
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Rows [group, reading] are [[1., 6.], [2., np.nan], [1., 10.], [2., 14.], [1., np.nan]] in d. How can you get the mean of present readings in group 1?
  1. np.mean(d[d[:, 0] == 1, 1])
  2. np.nanmean(d[d[:, 0] == 1, 1])
  3. np.nanmean(d[d[:, 1] == 1, 0])
  4. np.nanmean(d[:, 1])
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

After v = np.arange(5), how do v.T.shape and v[:, np.newaxis].shape compare?
  1. (1, 5) and (5, 1)
  2. (5,) and (5, 1)
  3. (5, 1) and (1, 5)
  4. (5,) and (1, 5)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

For x = np.array([-4., 2., 7.]), what does np.maximum(x, 3) produce?
  1. [3., 3., 3.]
  2. [-4., 2., 3.]
  3. [7., 7., 7.]
  4. [3., 3., 7.]
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A (3, 2) table contains paired values for three records. A length-three vector offset gives one correction per record. You need each correction added to both values in its own record. What expression and result shape fit?
  1. X + offset[:, None], shape (3, 2)
  2. X + offset, shape (3, 2)
  3. X[:, :, None] + offset, shape (3, 2, 3)
  4. X.T + offset[:, None], shape (2, 3)
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

values, counts = np.unique([4, 9, 4, 2, 9, 9], return_counts=True). What does values[counts.argmax()] return?
  1. 3
  2. 2
  3. 9
  4. 4
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

For D = np.array([[2., 4.], [np.nan, 6.], [8., np.nan]]), what does np.nanmean(D, axis=0) return?
  1. [3.3333, 3.3333]
  2. [3., 6., 8.]
  3. [np.nan, np.nan]
  4. [5., 5.]
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

ids = np.arange(6) and a separate measurement array have matching record order. You need four training records and two test records, with matching IDs and measurements and no overlap. What plan guarantees this?
  1. Generate one index permutation, slice it into 4 and 2, and apply both slices to both arrays.
  2. Shuffle the ID and measurement arrays independently, then take their first 4 and last 2 entries.
  3. Draw 4 training indexes and 2 test indexes in separate calls, both without replacement.
  4. Generate one permutation for IDs and another for measurements, then slice each into 4 and 2.
Show answerHide answer

Save this lesson to see this answer.

Set 5: Combine array tools in complete analyses10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A simulation uses independent trials to estimate a proportion. If 2,500 trials give a standard error of about 0.01, how many trials are needed for about 0.0025 at the same event probability?
  1. 10,000
  2. 20,000
  3. 160,000
  4. 40,000
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A raw integer vector is np.array([5, -999, 9]), where −999 means missing. You need the observed mean after adding a 0.5 correction to each present reading. What is the correct result?
  1. 7.0
  2. 5.0
  3. -327.8333
  4. 7.5
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

a = np.array([2, 5, 8, 11]); b = a[1:]; c = b[[0, 2]]; b[0] = 20; c[1] = 30; a[[0, 3]] = c. What is a afterward?
  1. [20, 20, 8, 30]
  2. [5, 20, 8, 30]
  3. [5, 5, 8, 30]
  4. [5, 20, 8, 11]
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

For x = np.array([1., np.nan, 4., 7.]), you want the share of observed values that exceed 3. What is that share?
  1. 2/3
  2. 1/2
  3. 3/4
  4. 1/3
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

Two arrays have shape (2, 3). What shape results from np.stack([a, b], axis=1)?
  1. (4, 3)
  2. (2, 6)
  3. (2, 2, 3)
  4. (2, 3, 2)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

After a = np.array([3, 6]), you need values [3.5, 6.5]. Why does a = a + 0.5 work while a += 0.5 raises an error?
  1. The first rounds to integers; the in-place update needs integer operands.
  2. The first broadcasts a scalar; the in-place update needs a same-shape array.
  3. The first creates float storage; the in-place update keeps integer storage.
  4. The first ignores dtype rules; the in-place update needs matching dtypes.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

X = np.array([[2., 6., 10.], [4., 8., 12.]]) is centered separately within each row. What result should the correct expression produce?
  1. [[-4., 0., 4.], [-4., 0., 4.]]
  2. [[-1., -1., -1.], [1., 1., 1.]]
  3. [[-6., -2., 2.], [-2., 2., 6.]]
  4. [[-4., -1., 2.], [-2., 1., 4.]]
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Each row of X = np.array([[3., 9.], [5., 7.], [8., 4.]]) holds two readings. Center each row, then weight the first column by 0.25 and the second by 0.75 and add within each row. What results?
  1. [0., 0., 0.]
  2. [7.5, 6.5, 5.]
  3. [-1.5, -0.5, 1.]
  4. [1.5, 0.5, -1.]
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

For x = np.array([7, 12, 12, 4]), what is x.argmax()?
  1. 12
  2. 1
  3. 2
  4. 3
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Rows [group, reading] in D are [[1., 4.], [1., np.nan], [2., 8.], [2., 10.], [2., np.nan]]. Fill each missing reading with its own group's observed mean. What is the mean of all five filled readings?
  1. 7.3333
  2. 7.0
  3. 6.5
  4. 4.4
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

82 Key Terms, each with its definition

A

Aggregation
An aggregation, or reduction, combines array values into fewer results, such as a total, mean, minimum, or maximum for a chosen group.
Calling table.mean(axis=0) combines records to give one mean for each measurement column.
Aliasing
Aliasing occurs when different names refer to the same object; assigning an array to another name does not copy its data or create a view object.
After b = a, the expression b is a is true, and assigning through either name changes that one array.
Argmax
Argmax is an operation returning a maximum's index position, taking the first occurrence when values tie for the maximum.
For [3, 8, 8, 2], argmax returns 1, which is a position rather than the maximum value 8.
Argsort
Argsort returns the index positions that would place values in sorted order, allowing the same ordering to be applied to other data.
Use names[np.argsort(scores)] to list names in score order without losing the name-score pairing.
Array creation function
An array creation function builds an array from supplied values or from a rule specifying its shape, fill, range, or number of points.
np.full((3, 2), 8) creates three rows of two values without requiring six separately written inputs.
Axis
An axis is one dimension of an array, with its own length and index positions; a 2-D table has a row axis and a column axis.
In a measurement table, selecting data[:, 0] keeps all positions on the row axis and takes its first column.

B

Binary ufunc
A binary ufunc takes two inputs and combines them element by element, such as selecting each pair's maximum or multiplying values.
np.maximum(observed, minimum) chooses the greater of two aligned values at every output position.
Boolean indexing
Boolean indexing selects entries or records where a matching mask is true, producing copied values from the selected positions.
data[data[:, 0] > 10] retains whole rows based on the condition applied to their first column.
Boolean mask
A boolean mask is a true/false array marking positions that satisfy a condition, used for filtering, counting, or assigning selected values.
For a temperature vector, t > 25 marks the days whose recorded temperature exceeds 25 °C.
Broadcasting
Broadcasting aligns compatible array shapes so that length-one axes expand conceptually during element-wise operations without copying repeated inputs.
Adding a shape (3,) vector to a shape (8, 3) table applies that vector to each of the eight rows.

C

Ceiling
The ceiling of a real number is the smallest integer no smaller than it; np.ceil applies this upward rounding to array values.
For −2.3, np.ceil gives −2.0, whereas for 2.3 it gives 3.0.
Centering
Centering subtracts the relevant mean from values so that deviations are measured relative to the selected row, column, or group average.
X - X.mean(axis=0) subtracts each column's mean from the values in that same column.
Clipping
Clipping bounds values within a specified interval by replacing values below the lower limit or above the upper limit with those limits.
np.clip(readings, 10, 30) retains interior values and replaces readings outside that range with 10 or 30.
Column stacking
Column stacking places matching 1-D arrays into columns of a 2-D table, keeping values with the same original index in the same row.
Combine aligned height and mass vectors with np.column_stack to create one two-measurement record per person.
Compatible dimensions
Compatible dimensions have equal lengths or include a length of one when shapes are aligned from their rightmost axes for broadcasting.
Shapes (5, 1) and (4,) combine into (5, 4) because their aligned axes satisfy the compatibility rule.
Complete row
A complete row has no missing entries among its fields; a row-wise missingness test can identify which records meet that requirement.
~np.isnan(data).any(axis=1) creates one true entry for each complete record in a numerical table.
Concatenation
Concatenation joins arrays along an existing axis, requiring all other axis lengths to match and adding the lengths on the joining axis.
Joining shapes (2, 4) and (5, 4) along axis 0 makes a seven-row table with four columns.
Conditional selection
Conditional selection with np.where builds a result by choosing one input at true positions and another at false positions.
np.where(x < 0, 0, x) replaces negative values with zero in a new result of the same overall selection shape.
Conditional summary
A conditional summary calculates a statistic only for values selected by a condition or label, using a mask to identify the contributing records.
mass[batch == 'B'].mean() averages only masses whose matching batch label is B.
Copy
A copy is an array with independent element storage, allowing its values to change without editing the source array's values.
Keeping saved = data[:3].copy() preserves an independent subset for later edits or comparisons.
Cumulative sum
A cumulative sum records the running total through each position, retaining intermediate totals instead of returning only a final sum.
np.cumsum([2, 5, 1]) gives [2, 7, 8], useful for tracking a balance as entries accumulate.

D

Degrees-of-freedom adjustment
A degrees-of-freedom adjustment sets the amount subtracted from the value count in a variance or standard-deviation divisor through ddof.
For five observations and ddof=1, NumPy divides the squared-deviation total by four.
dtype
A dtype describes the kind and storage representation of every element in an array, including widths such as 32-bit or 64-bit numbers.
Inspecting data.dtype can reveal that a stray text label caused numerical-looking values to be stored as strings.

E

Element-wise arithmetic
Element-wise arithmetic applies an operator at corresponding positions of compatible arrays, producing a result for each aligned pair.
Multiplying two (2, 3) arrays with * gives six paired products in another (2, 3) array.
Element-wise logical operation
An element-wise logical operation combines corresponding mask entries using &, |, or ~ for and, or, or negation.
The mask (x >= 2) & (x <= 8) retains values meeting both bounds, with each comparison in parentheses.

F

Fancy indexing
Fancy indexing selects positions using integer lists or arrays, allowing arbitrary order and repetition while returning copied data.
The selection a[[4, 1, 4]] includes position 4 twice and preserves the requested output order.
First-hit time
A first-hit time is the number of steps until a path first reaches a specified condition, requiring a check that a hit occurred at all.
If a walk's hit mask first becomes true at index 6, the boundary was reached after seven steps.
Flattening
Flattening arranges array values into one dimension; flatten copies the data, while ravel can share the original data.
Call table.flatten() when you need a separate 1-D result whose edits cannot change the table.
Floating-point number
A floating-point number stores a finite-precision binary approximation of a numerical value, so many decimal fractions are not represented exactly.
Compare calculated decimal arrays with np.allclose when tiny representation differences should be tolerated.
Floor
The floor of a real number is the greatest integer no larger than it; np.floor applies this downward rounding to each input value.
For −2.3, np.floor gives −3.0 because −2 would lie above the original negative value.
Function domain
A function's domain is the set of inputs for which its mathematical rule is defined in the number system being used.
A real-valued square root requires nonnegative input; np.sqrt(-4.0) normally warns and returns NaN.

G

Generator
A Generator is NumPy's random sampling object, created with default_rng and reused through methods that advance its internal state.
Calling rng.integers twice continues the stream; recreating rng with the same seed restarts it.

H

Homogeneous storage
Homogeneous storage means that every array element follows the same dtype, allowing numerical values to be processed with consistent storage rules.
In np.array([2, 3.5]), the integer input becomes a float so both elements share floating-point storage.

I

Identity array
An identity array is a square 2-D array with ones on its main diagonal and zeros elsewhere, created by a function such as np.eye.
np.eye(4) creates four diagonal ones in a 4-by-4 array, with zeros in the remaining positions.
In-place operation
An in-place operation changes an existing array's storage and keeps its dtype, so some result types cannot be written back by that operation.
Adding 0.5 with += to an integer array fails, while an ordinary addition can create floating-point storage.
Index
An index is a position used to select an array element along an axis; positions start at zero and negative indexes count backward from the end.
For five readings, index 4 and index −1 both refer to the final reading along that axis.
Indexed assignment
An indexed assignment writes values into selected positions of an existing array, applying the destination's dtype and shape rules.
The line data[:2, 0] = 0 replaces the first-column values in the first two rows of the table.
Infinity
Infinity is a floating-point value representing an unbounded numerical result, written inf or -inf and detected as nonfinite.
Dividing positive floating-point entries by zero normally produces inf with a warning under default NumPy settings.
Integer overflow
Integer overflow occurs when an arithmetic result exceeds the range of a fixed-width integer type, which can cause wraparound in array calculations.
Adding two uint8 arrays containing 250 and 10 wraps to 4 because that dtype cannot hold 260.
Integer selector
An integer selector chooses one position on an axis and removes that axis from the result, unlike a slice covering a single position.
For a table with shape (8, 3), data[:, 1] returns shape (8,) after removing the column axis.

L

Linear spacing
Linear spacing means neighboring points have equal gaps across an interval; linspace creates this grid from its endpoints and point count.
Five linearly spaced points from 0 m to 8 m form four gaps, each measuring 2 m.

M

Mean filling
Mean filling replaces missing entries with the observed mean, retaining that mean while making the completed values appear less spread out.
Filling a sensor's NaN entries with its observed average changes the spread even when the reported average stays fixed.
Median
The median is the middle sorted value, or the average of the two middle values for an even count, making it resistant to extreme observations.
The median of [1, 3, 6, 100] is 4.5 even though the unusually large final value raises the mean sharply.
Memory sharing
Memory sharing means arrays refer to overlapping stored data; np.shares_memory tests whether two particular arrays overlap.
A copied fancy-indexed selection does not share memory with its source, while an ordinary nonempty slice does.
Missing-value code
A missing-value code is an agreed placeholder marking absent observations, which must be recognized before it is treated as numerical data.
Replace a defined code such as −999 with NaN in a float array before calculating the mean of readings.

N

NaN
NaN, short for not a number, is a floating-point marker used for missing values and some invalid results; it is unequal even to itself.
The values [4.0, np.nan, 8.0] require floating-point storage, and np.isnan identifies the missing position.
NaN-aware aggregation
A NaN-aware aggregation deliberately skips NaN entries when computing a statistic, using functions such as nanmean or nanmedian.
np.nanmean([5., np.nan, 9.]) returns 7.0 by averaging the two observed values.
ndarray
An ndarray is NumPy's array object, a rectangular collection of elements arranged along zero or more axes with one shared dtype.
A table of 50 records and three measurements per record can be represented by an ndarray with shape (50, 3).
Normal distribution
A normal distribution is a symmetric bell-shaped model specified by a mean and standard deviation, sampled with rng.normal.
A call with loc=100 and scale=4 uses distribution mean 100 and standard deviation 4, not variance 4.

P

Paired coordinates
Paired coordinates are row-column positions matched entry by entry from index arrays, selecting one element for each corresponding pair.
The expression m[[0, 2], [1, 3]] selects coordinates (0, 1) and (2, 3), not a 2-by-2 block.
Percentile
A percentile describes a position in a sorted distribution using a scale from 0 to 100, with NumPy interpolating linearly by default.
The 50th percentile matches the median, while the 25th and 75th percentiles mark the quartile positions.
Permutation
A permutation rearranges all input positions without omitting or repeating any, supporting shuffled copies and random record indexes.
Split one rng.permutation(n) into disjoint index slices to assign every record to exactly one subset.
Pseudorandom sequence
A pseudorandom sequence is produced by a deterministic algorithm but designed to behave like random draws for tasks such as sampling and simulation.
Repeating a seeded analysis can reproduce the draw stream when its calls and numerical environment are kept the same.

Q

Quantile
A quantile describes a distribution position using a fraction from 0 to 1, corresponding to a percentile divided by 100.
np.quantile(x, 0.75) requests the same position as np.percentile(x, 75) with matching options.

R

Random walk
A random walk builds a path by accumulating random steps, with each running sum giving the position after that step.
Simulating ±1 moves and applying cumsum(axis=1) creates separate walk positions along each trial row.
Reduction axis
A reduction axis is the dimension combined by an aggregation; it disappears from the output shape unless retained with keepdims.
Reducing axis 1 of shape (6, 4) leaves shape (6,), with one result per original row.
Reshape
A reshape rearranges an array into a new axis structure while preserving its element count, reading values row by row by default.
Twelve consecutive monthly values reshape to (4, 3) when one row should hold each quarter's three months.
Row-major order
Row-major order traverses an array with its last index changing fastest, reading every value of one row before moving to the next.
Default reshaping of [0, 1, 2, 3, 4, 5] to (2, 3) puts [0, 1, 2] in the first row.

S

Sampling with replacement
Sampling with replacement allows the same input position to be selected more than once, which is the default behavior of rng.choice.
A five-draw sample from three labels can repeat a label because each draw can revisit an earlier position.
Seed
A seed supplies information that initializes a random generator's state, allowing its subsequent sequence of draws to be reproduced.
Creating np.random.default_rng(17) at the start gives a repeatable starting point for the analysis.
Shape
An array's shape is the tuple of its axis lengths in order, describing how its elements are arranged rather than only how many there are.
Shape (2, 6) describes two rows of six values, while shape (12,) describes one vector of twelve values.
Simulation
A simulation uses a model and repeated generated trials to estimate outcomes such as an event probability or a long-run average.
Drawing a table with two die columns per trial supports estimating the frequency of selected two-die totals.
Singleton axis
A singleton axis has length one and can give a vector a row or column role without changing how many values the array contains.
Adding [:, None] to a length-four vector creates shape (4, 1), suitable for one value per table row.
Size
An array's size is its total number of elements, equal to the product of its shape lengths for an array with one or more axes.
An array shaped (4, 7) has size 28 even though its ndim attribute reports only two axes.
Slice
A slice selects a regular sequence of positions using a start, an excluded stop, and an optional step while retaining the selected axis.
The slice a[2:7:2] selects positions 2, 4, and 6, skipping one position between selected values.
Splitting
Splitting divides an array along an axis using cut positions or a requested part count; array_split allows unequal part lengths.
Cutting np.arange(9) at [2, 6] gives parts of lengths 2, 4, and 3 because the numbers are boundaries.
Stacking
Stacking joins equal-shaped arrays along a new axis whose length equals the number of input arrays, increasing the dimension count by one.
Stacking three length-five vectors along axis 0 creates shape (3, 5), with one input vector per row.
Standard deviation
The standard deviation measures spread around the mean as the square root of variance, with the same unit as the original measurements.
Temperature data summarized with std() use divisor N by default; ddof=1 selects the sample formula.
Standard error
A standard error describes sampling variation of an estimate across repeated independent runs, decreasing as the square root of trial count grows.
For a fixed event probability, increasing simulation trials from 100 to 400 approximately halves the proportion's standard error.
Standardization
Standardization subtracts a mean and divides by the corresponding nonzero standard deviation, expressing values in units of that spread.
(X - X.mean(axis=0)) / X.std(axis=0) standardizes columns that have nonzero standard deviations.
Step size
A step size is the intended difference between successive values in a generated sequence, specified by the third argument of np.arange.
np.arange(2, 15, 4) uses a step size of 4 to create the sequence [2 6 10 14].

T

Transpose
A transpose changes axis order; in a 2-D array it swaps row and column roles while retaining each value's relationship to its original axes.
Transposing a (2, 5) table gives shape (5, 2), with each old column becoming a row.
Trial
A trial is one repetition of a simulated experiment, including every generated value needed to decide its outcome.
When a row contains three coin flips, reducing across that row evaluates one trial before results are combined.
Truncation
Truncation removes a number's fractional part toward zero, so a positive value decreases and a negative value increases toward zero.
Converting −7.9 with astype(int) gives −7; applying floor instead would give −8.
Type conversion
Type conversion represents values using a different dtype; astype returns a converted copy, and some conversions discard information.
Calling np.array([2.7, 5.1]).astype(int) converts the values to 2 and 5 without rounding to nearest.

U

Unary ufunc
A unary ufunc takes one input and applies its numerical rule to each element, as in absolute value, logarithm, or square root.
Calling np.abs on a vector of signed errors produces a vector containing their magnitudes.
Uninitialized array
An uninitialized array has allocated storage whose initial values have not been set for use, so those values must be assigned before reading.
Use np.empty(100) only when subsequent code will fill every entry before any calculation uses it.
Unique values
Unique values are the distinct values represented in an array; np.unique returns them sorted and can also return their matching occurrence counts.
A repeated label appears once in the unique output, with its frequency stored at the matching count position.
Universal function
A universal function, or ufunc, applies a numerical operation element by element to arrays, supporting compatible input shapes.
np.sqrt(distances_squared) calculates a square root at every position without using Python's scalar math.sqrt.

V

Vectorization
Vectorization expresses repeated numerical calculations as whole-array operations, letting NumPy run the element-level work in compiled code.
The expression price * quantity calculates every line total without a separate Python loop over items.
View
A view is an array object that shares an existing data buffer, so modifying its entries changes the corresponding stored values in its source.
After b = a[1:4], setting b[0] = 50 changes a[1] because the basic slice shares data.

W

Weighted total
A weighted total adds values after multiplying each by its assigned weight, allowing different columns to contribute by different amounts.
(scores * weights).sum(axis=1) creates a weighted result for every row when weights align with columns.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started