Array-Oriented Programming with NumPy

A beginner-friendly teaching edition — concepts, examples, outputs, mistakes and revision
Big idea: Python lists are useful general-purpose collections, but data science often needs to process large amounts of numerical data efficiently. NumPy provides the high-performance multidimensional ndarray, which this chapter simply calls an array. The chapter then introduces pandas Series and DataFrame collections for more flexible data analysis.

What You Will Learn

  • Create NumPy arrays from existing data and ranges.
  • Understand array dimensions, shape, size and element type.
  • Create arrays filled with zeros, ones or a specified value.
  • Compare list and array performance with IPython %timeit.
  • Perform arithmetic on entire arrays using array-oriented programming.
  • Understand broadcasting.
  • Use NumPy calculation methods such as sum, min, max, mean, std and var.
  • Use NumPy universal functions.
  • Index and slice one- and two-dimensional arrays.
  • Understand shallow views versus deep copies.
  • Reshape and transpose arrays.
  • Use pandas Series and DataFrame for data-science tasks.

Chapter Structure

7.1 Introduction7.2 Creating Arrays7.3 Attributes7.4 Specific Values7.5 Ranges%timeitArray OperatorsCalculation MethodsUniversal FunctionsIndexing & SlicingViews & CopiesReshapingpandas SeriesDataFrames

7.1 Introduction

NumPy means Numerical Python. It provides a high-performance, richly functional n-dimensional array type called ndarray. In this chapter, we use the shorter word array.

The important difference from a normal Python list is that NumPy is designed for efficient numerical array processing. The book notes that many array operations can be up to two orders of magnitude faster than corresponding list operations, which can matter greatly when processing large datasets.

Python list
General-purpose collection

Very flexible, good for many everyday tasks.
NumPy array
Numerical, multidimensional collection

Optimized for fast array-oriented calculations.

Array-Oriented Programming

With a list, you often write a loop yourself to process every element. NumPy lets you write an operation once and apply it to an entire array.

ArrayOne operationAll elements

This style is concise and can reduce the kinds of bugs that occur when manually writing many external loops.

Remember: NumPy arrays are especially important when your data is numerical, multidimensional and large enough that performance matters.

7.2 Creating Arrays from Existing Data

The usual convention is:

import numpy as np

The alias np lets you write np.array, np.arange, np.zeros, and so on.

Creating an Array from a List

import numpy as np

numbers = np.array([1, 2, 3, 4, 5])
print(numbers)
[1 2 3 4 5]

Creating a Two-Dimensional Array

grades = np.array([
    [87, 96, 70],
    [100, 87, 90],
    [94, 77, 90]
])

print(grades)
[[ 87  96  70]
 [100  87  90]
 [ 94  77  90]]

Here we have 3 rows × 3 columns.

Connection with Chapter 5: A nested list can represent a table too. NumPy makes numerical operations on such multidimensional data much more convenient.

7.3 array Attributes

NumPy arrays have attributes that describe their structure and stored data.

AttributeEasy meaning
ndimNumber of dimensions
shapeSize of each dimension
sizeTotal number of elements
dtypeType of elements stored in the array
itemsizeNumber of bytes used by each element
integers = np.array([[1, 2, 3], [4, 5, 6]])

print(integers.ndim)
print(integers.shape)
print(integers.size)
print(integers.dtype)
2
(2, 3)
6
int64

How to Think About These Attributes

ndim = how many dimensions?shape = how arranged?size = how many total?dtype = what type?

Iterating Through Multidimensional Arrays

You can use nested loops when you need external iteration:

for row in integers:
    for value in row:
        print(value, end=' ')

NumPy also provides the flat attribute to iterate through all elements as if the array were one-dimensional:

for value in integers.flat:
    print(value, end=' ')
1 2 3 4 5 6
Practical idea: You can iterate manually, but NumPy's strength is that many operations can be expressed without writing these loops yourself.

7.4 Filling Arrays with Specific Values

NumPy provides convenient functions for creating arrays filled with common values.

FunctionPurpose
np.zeros()Create an array filled with 0
np.ones()Create an array filled with 1
np.full()Create an array filled with a specified value
print(np.zeros(5))
print(np.ones((2, 4), dtype=int))
print(np.full((3, 5), 13))
[0. 0. 0. 0. 0.]

[[1 1 1 1]
 [1 1 1 1]]

[[13 13 13 13 13]
 [13 13 13 13 13]
 [13 13 13 13 13]]

The first argument can be an integer for one dimension or a tuple for multiple dimensions.

dtype: dtype lets you specify the element type. For example, dtype=int creates integer elements.

7.5 Creating Arrays from Ranges

NumPy provides optimized functions for creating ranges of values.

Integer Ranges with arange

print(np.arange(5))
print(np.arange(5, 10))
print(np.arange(10, 1, -2))
[0 1 2 3 4]
[5 6 7 8 9]
[10  8  6  4  2]

The idea is similar to Python's range, but arange directly creates a NumPy array and is optimized for array use.

Floating-Point Ranges with linspace

linspace creates evenly spaced floating-point values. The ending value is included.

np.linspace(0.0, 1.0, num=5)
array([0.  , 0.25, 0.5 , 0.75, 1.  ])

Creating a Range and Reshaping It

numbers = np.arange(1, 21)
table = numbers.reshape(4, 5)

print(table)
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]
 [11 12 13 14 15]
 [16 17 18 19 20]]
Memory trick: arange → range based on a step. linspace → a specified number of evenly spaced values.

7.6 List vs. Array Performance: Introducing %timeit

When you want to compare how fast two pieces of code run in IPython/Jupyter, the book uses the %timeit magic command.

%timeit [i * 2 for i in range(1000)]

%timeit executes the expression repeatedly and reports timing information. The exact timing depends on your computer and environment.

The chapter compares creating millions of die rolls using a list with NumPy-based approaches. The important lesson is:

Performance lesson: NumPy arrays can be much faster than Python lists for numerical operations, with the book reporting up to two orders of magnitude in relevant array operations.

7.7 array Operators

NumPy lets arithmetic operators work on an entire array. This is called an element-wise operation.

numbers = np.arange(1, 6)

print(numbers * 2)
print(numbers ** 3)
[ 2  4  6  8 10]
[  1   8  27  64 125]

Instead of writing a loop, NumPy applies the operation to every element.

Original Array Is Not Automatically Changed

numbers = np.arange(1, 6)

result = numbers * 2

print(numbers)
print(result)
[1 2 3 4 5]
[ 2  4  6  8 10]

But augmented assignment modifies the array:

numbers += 10
print(numbers)
[11 12 13 14 15]

Broadcasting

Normally, arithmetic between two arrays works when their shapes are compatible. When one operand is a scalar—a single value—NumPy can apply that value to every element. This is called broadcasting.

numbers = np.array([10, 20, 30])
print(numbers + 5)
[15 25 35]

NumPy can also broadcast compatible arrays of different shapes. For example, a one-dimensional array with three values can be applied to every row of a two-dimensional array with three columns.

numbers3 = np.array([[10, 20, 30],
                     [40, 50, 60]])

numbers4 = np.array([2, 4, 6])

print(np.multiply(numbers3, numbers4))
[[ 20  80 180]
 [ 80 200 360]]
Broadcasting warning: Not every pair of different-shaped arrays is compatible. If the shapes cannot be broadcast together, NumPy raises a ValueError.

7.8 NumPy Calculation Methods

Arrays provide calculation methods that can summarize their contents.

MethodMeaning
sum()Total
min()Smallest value
max()Largest value
mean()Average
std()Standard deviation
var()Variance
grades = np.array([
    [87, 96, 70],
    [100, 87, 90],
    [94, 77, 90],
    [100, 81, 82]
])

print(grades.sum())
print(grades.min())
print(grades.max())
print(grades.mean())
print(grades.std())
print(grades.var())
1054
70
100
87.83333333333333
8.792357792739987
77.30555555555556

Calculations by Row or Column

For a multidimensional array, the axis argument tells NumPy which dimension to use.

For example, axis=0 calculates down the rows, producing a result for each column:

grades.mean(axis=0)
[95.25 85.25 83.  ]
Axis idea: Do not memorize axis numbers blindly. Look at the table and ask: "Do I want one answer for each column or one answer for each row?"

7.9 Universal Functions

NumPy provides many universal functions (ufuncs). They perform operations element by element on arrays.

CategoryExamples
Mathadd, subtract, multiply, divide, sqrt, log, power
Trigonometrysin, cos, tan
Bit manipulationbitwise_and, bitwise_or
Comparisongreater, less, equal, logical_and
Floating pointfloor, ceil, isnan, fabs
numbers = np.array([1, 4, 9, 16])

print(np.sqrt(numbers))
[1. 2. 3. 4.]

Universal functions fit naturally with array-oriented programming because you can operate on the whole array instead of writing a loop.

7.10 Indexing and Slicing

One-dimensional NumPy arrays use indexing and slicing syntax similar to Python sequences.

numbers = np.array([10, 20, 30, 40, 50])

print(numbers[0])
print(numbers[1:4])
10
[20 30 40]

Two-Dimensional Indexing

For a two-dimensional array, provide row and column indices:

numbers = np.array([
    [10, 20, 30],
    [40, 50, 60]
])

print(numbers[0, 1])
print(numbers[1, 2])
20
60

Think of it as:

array[row, column]

Slicing a Two-Dimensional Array

print(numbers[:, 1])
print(numbers[0, :])
[20 50]
[10 20 30]

: means "take all values along this dimension."

Easy mental model: numbers[row, column]. First choose the row, then choose the column.

7.11 Views: Shallow Copies

A view is a shallow copy that shares the underlying data with the original array. This means changing the data through one can affect the other.

numbers = np.array([1, 2, 3, 4, 5])

numbers_view = numbers.view()

numbers[1] = 20

print(numbers)
print(numbers_view)
[ 1 20  3  4  5]
[ 1 20  3  4  5]
Important: A view is not an independent copy of the data. Both arrays can refer to the same underlying data.

7.12 Deep Copies

When you need a completely separate array, use the array's copy() method.

numbers = np.array([1, 2, 3, 4, 5])
numbers_copy = numbers.copy()

numbers[1] = 20

print(numbers)
print(numbers_copy)
[ 1 20  3  4  5]
[1 2 3 4 5]
View vs Copy:
View → shares underlying data.
Copy → independent data.

The book also notes that for other Python object types, the copy module's deepcopy() can be used when a deep copy is needed.

7.13 Reshaping and Transposing

reshape()

reshape changes how the same elements are arranged into dimensions. The number of elements must remain the same.

numbers = np.arange(1, 7)

print(numbers.reshape(2, 3))
[[1 2 3]
 [4 5 6]]

A six-element array can become 2 × 3 or 3 × 2, but it cannot become 4 × 4 because that would require 16 elements.

reshape() vs resize()

MethodEffect
reshape()Returns a reshaped view; original shape is not changed.
resize()Changes the original array's shape.
grades = np.array([[87, 96, 70],
                    [100, 87, 90]])

reshaped = grades.reshape(1, 6)

print(reshaped)
print(grades)

Transpose

The T attribute transposes an array. For a two-dimensional array, rows become columns and columns become rows.

grades = np.array([
    [87, 96, 70],
    [100, 87, 90]
])

print(grades.T)
[[ 87 100]
 [ 96  87]
 [ 70  90]]

Other Shape Tools

The chapter also introduces flatten() and ravel() for producing one-dimensional representations of multidimensional arrays.

2-D arrayreshapenew dimensions
2-D arrayTrows ↔ columns

7.14 Intro to Data Science: pandas Series and DataFrames

NumPy arrays are excellent for numerical data, but real-world data can be messy. Data-science applications often need mixed data types, custom indexing, missing data and data that is not structured perfectly.

pandas provides two major array-like collections:

Series
One-dimensional collection

Supports custom indices and missing data.
DataFrame
Two-dimensional table

Rows and columns with labels.

Series and DataFrames use NumPy arrays internally and can work together with many NumPy operations.

7.14.1 pandas Series

A Series is an enhanced one-dimensional array. Unlike a basic NumPy array, it can use custom indices, including strings.

Creating a Series

import pandas as pd

grades = pd.Series([87, 100, 94])
print(grades)
0     87
1    100
2     94
dtype: int64

By default, the indices are 0, 1, 2, ....

Creating a Series with the Same Value

pd.Series(98.6, range(3))
0    98.6
1    98.6
2    98.6
dtype: float64

Custom Indexing

grades = pd.Series(
    [87, 100, 94],
    index=['Alice', 'Bob', 'Cara']
)

print(grades)

Now the labels themselves identify the values.

Series Calculations

print(grades.count())
print(grades.mean())
print(grades.min())
print(grades.max())
print(grades.std())

describe() provides several descriptive statistics together.

grades.describe()
Missing data: Series can represent missing data, and many Series operations ignore missing data by default.

7.14.2 DataFrames

A DataFrame is a two-dimensional pandas collection. Think of it as a labeled table with rows and columns.

grades = pd.DataFrame(
    [[87, 96, 70],
     [100, 87, 90],
     [94, 77, 90],
     [100, 81, 82]],
    columns=['Test1', 'Test2', 'Test3'],
    index=['Wally', 'Eva', 'Sam', 'Katie']
)

print(grades)
       Test1  Test2  Test3
Wally     87     96     70
Eva      100     87     90
Sam       94     77     90
Katie    100     81     82

Selecting Data with Labels

The book demonstrates pandas selection using labels and integer positions.

print(grades.loc['Test1'])

More generally:

  • loc uses labels.
  • iloc uses integer positions.

Boolean Indexing

Boolean indexing lets you select values that satisfy a condition.

grades[grades >= 90]

Values that do not satisfy the condition appear as missing values in the resulting DataFrame.

For multiple conditions, pandas uses bitwise operators such as & and | rather than Python's and and or.

grades[(grades >= 80) & (grades < 90)]
Common pandas mistake: When combining Boolean conditions in pandas, use & for AND and | for OR, with each condition enclosed in parentheses.

Accessing One DataFrame Cell

at uses row/column labels, while iat uses integer positions.

grades.at['Wally', 'Test1']
grades.iat[0, 0]

Sorting DataFrames

The chapter demonstrates sort_index() and sort_values().

grades.sort_index(axis=1)
grades.sort_values(by='Test1', axis=1, ascending=False)

By default, these sorting operations return a copy. The book also demonstrates inplace=True when you want the DataFrame itself modified rather than returning a copy.

DataFrame mental model: It is a labeled two-dimensional table. You can select, filter, calculate, sort and transform its rows and columns.

Quick Concept Map

NumPy → numerical computing

ndarray / array → n-dimensional numerical collection

Creationarray zerosonesfull arangelinspace

Attributesndim shapesizedtype itemsize

Operations → element-wise arithmetic → broadcasting → universal functions

Calculations → sum → min → max → mean → std → var

Access → indexing → slicing

Memory → view → deep copy

Shape → reshape → resize → transpose → flatten/ravel

pandas → Series → DataFrame

List vs NumPy Array vs Series vs DataFrame

CollectionMain strengthTypical use
ListGeneral-purpose Python sequenceEveryday collections
NumPy arrayFast numerical array processingScientific computing and numerical data
Series1-D data + custom labelsSingle columns/series of data
DataFrame2-D labeled tableData analysis and tabular datasets

Common Mistakes

  1. Forgetting the standard import alias: import numpy as np.
  2. Confusing shape with size.
  3. Trying to reshape an array into a shape with a different number of total elements.
  4. Assuming normal arithmetic always modifies the original array.
  5. Forgetting that augmented assignment such as += modifies the array.
  6. Using incompatible shapes and expecting broadcasting to work.
  7. Confusing a view with an independent copy.
  8. Forgetting that two-dimensional indexing is array[row, column].
  9. Using Python and/or instead of &/| for pandas Boolean conditions.
  10. Thinking Series and DataFrames are unrelated to NumPy—they are closely connected to NumPy arrays.

Remember These Points

  • NumPy array = ndarray.
  • np.array() creates an array from existing data.
  • np.zeros(), np.ones() and np.full() create initialized arrays.
  • np.arange() creates integer-style ranges; np.linspace() creates evenly spaced values.
  • ndim = dimensions; shape = arrangement; size = total elements.
  • NumPy arithmetic is usually element-wise.
  • Broadcasting lets compatible differently shaped arrays or scalars participate in operations.
  • sum, min, max, mean, std and var summarize array data.
  • View shares data; copy has independent data.
  • reshape() changes dimensions without changing the number of elements.
  • T transposes a two-dimensional array.
  • Series is one-dimensional; DataFrame is two-dimensional.
  • loc uses labels; iloc uses integer positions.

Revision Questions

  1. What is NumPy and what is an ndarray?
  2. Why can NumPy arrays be faster than Python lists for numerical processing?
  3. Why is import numpy as np commonly used?
  4. How do you create a one-dimensional and two-dimensional array?
  5. What do ndim, shape, size, dtype and itemsize mean?
  6. What is the difference between arange and linspace?
  7. What are zeros, ones and full used for?
  8. What does %timeit do?
  9. What is element-wise array arithmetic?
  10. What is broadcasting?
  11. What does the axis argument do?
  12. What are universal functions?
  13. How do you access an element of a two-dimensional array?
  14. What is the difference between a view and a deep copy?
  15. What is the difference between reshape and resize?
  16. What does the T attribute do?
  17. What is a pandas Series?
  18. What is a DataFrame?
  19. What is the difference between loc and iloc?
  20. How does Boolean indexing work in pandas?

Practice Programs

1. Array basics
Create a NumPy array containing 1–10 and display its ndim, shape, size and dtype.
2. Array arithmetic
Create an array of five numbers and calculate its double, square and cube without writing a loop.
3. Student grades
Create a two-dimensional NumPy array for several students and exams. Calculate the overall mean and each exam's mean.
4. Broadcasting
Create a 3×3 array and add 10 to every element using broadcasting.
5. Reshaping
Create numbers 1–20 with arange and reshape them into a 4×5 array.
6. View vs copy
Create an array, make both a view and a copy, change the original and observe which object changes.
7. Series
Create a pandas Series of five student grades with student names as custom indices. Calculate mean() and describe().
8. DataFrame
Create a DataFrame containing students and three test scores. Select values using loc, iloc, Boolean indexing and sorting.

Chapter Wrap-Up

This chapter introduced NumPy's high-performance ndarray, referred to here simply as an array. You learned how to create arrays, inspect their attributes, fill them with values, create ranges, compare performance with lists, perform element-wise calculations and use broadcasting.

You also learned NumPy calculation methods, universal functions, indexing and slicing, views and deep copies, reshaping and transposing. These features make array-oriented programming concise and especially useful for numerical and data-science workloads.

The chapter then began the book's introduction to pandas. A Series provides a labeled one-dimensional collection, while a DataFrame provides a labeled two-dimensional table. These collections offer capabilities such as custom indexing, missing-data handling, selection, filtering, calculations and sorting.

Big picture: You now have four important array-like tools in your toolkit: lists → NumPy arrays → pandas Series → pandas DataFrames. The later data-science chapters build heavily on these structures.

Teaching note: This page is a simplified teaching edition based on the chapter organization and concepts in the supplied Python for Programmers source. Examples are rewritten for learning clarity rather than reproduced verbatim.