Numbers, Arrays, and NumPy: How AI Represents Data

Created by eneaslari 9/9/2026

AI series

In the previous article, we used pandas to load a dataset, inspect its rows and columns, find missing values, filter records, and calculate useful statistics.

That gave us a convenient way to look at data as humans.

A table such as this makes immediate sense to us:

Hours Studied Attendance Previous Grade Passed
5.5 92 78 1
2.0 68 55 0
7.0 95 91 1
3.5 81 73 1
4.5 88 79 1

We understand what the columns mean. We know that 92 represents attendance, that 5.5 represents hours studied, and that 1 in the final column means the student passed.

But a machine-learning model does not look at this table and understand “students,” “attendance,” or “grades” the way we do.

Most machine-learning models ultimately work with numbers arranged in specific structures.

One student's features might become:

[5.5, 92, 78]

Several students might become:

[
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
]

That second structure may look like a simple table without headings, but it introduces several ideas that appear everywhere in artificial intelligence:

arrays, vectors, matrices, dimensions, and shapes.

This is where NumPy becomes useful.

NumPy is a Python library built for working efficiently with numerical arrays. It sits underneath a huge amount of scientific computing, data science, and machine-learning work in Python.

The goal of this article is not to memorize dozens of NumPy functions.

The important goal is to understand how data becomes numbers, how those numbers are organized, and what terms such as vector, matrix, dimension, and shape actually mean when you see them in AI code.

Once those ideas make sense, a lot of machine-learning code becomes much less mysterious.


Everything Starts With Numbers

Consider a student named Anna.

We might describe her like this:

Hours studied: 5.5
Attendance: 92%
Previous grade: 78

For a machine-learning model, we can represent those three features numerically:

[5.5, 92, 78]

The meaning has not disappeared.

We know which position corresponds to which feature:

[hours studied, attendance, previous grade]

so:

[5.5, 92, 78]

means:

hours studied   = 5.5
attendance      = 92
previous grade  = 78

This is a simple but extremely important idea.

Real-world information has been converted into an organized numerical representation.

That is what happens throughout machine learning.

A house can become numbers describing its size, age, number of rooms, and location.

A customer can become numbers describing purchases, account age, activity, and spending.

A photograph can become numbers representing pixels.

A sentence can eventually become arrays of numbers representing tokens and meaning.

The real world is complicated.

Models need mathematical representations they can calculate with.

NumPy gives us one of the main tools for working with those representations in Python.


Installing and Importing NumPy

If NumPy is not already installed, you can install it with:

pip install numpy

Then import it in Python:

import numpy as np

You will see this line constantly in data science and machine learning:

import numpy as np

np is simply the conventional short name used for NumPy.

Instead of writing:

numpy.array(...)

we write:

np.array(...)

Python Lists vs NumPy Arrays

You already know Python lists.

For example:

scores = [72, 84, 91, 68, 80]

A list is a general-purpose Python container. It can store numbers, strings, objects, or combinations of different things.

NumPy introduces another structure called an array:

import numpy as np

scores = np.array([72, 84, 91, 68, 80])

print(scores)

Output:

[72 84 91 68 80]

At first, the NumPy array does not look dramatically different from the Python list.

The important difference appears when we start performing numerical operations.

Imagine that every student receives five bonus points.

With a normal Python list, this does not work:

scores = [72, 84, 91, 68, 80]

scores + 5

Python cannot simply add the number 5 to every item in the list.

You could write a loop:

new_scores = []

for score in scores:
    new_scores.append(score + 5)

With NumPy:

scores = np.array([72, 84, 91, 68, 80])

new_scores = scores + 5

print(new_scores)

Output:

[77 89 96 73 85]

NumPy applies the operation across the array.

The same applies to multiplication:

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

print(values * 10)

Output:

[10 20 30 40]

Or division:

attendance = np.array([92, 68, 95, 81, 88])

attendance_decimal = attendance / 100

print(attendance_decimal)

Output:

[0.92 0.68 0.95 0.81 0.88]

This style of working with whole arrays is one reason NumPy is so useful.

Instead of thinking:

Take item one, calculate something, take item two, calculate something, take item three...

you can often describe the operation directly:

attendance / 100

NumPy handles the element-by-element calculation for you.

This is commonly called vectorized computation.

You do not need to master that term yet. The important idea is simpler:

NumPy lets us perform numerical operations on collections of numbers without manually looping through every value.


An Important Difference: + Does Not Mean the Same Thing

Here is another example worth understanding.

With Python lists:

a = [1, 2, 3]
b = [10, 20, 30]

print(a + b)

Output:

[1, 2, 3, 10, 20, 30]

Python joins the two lists.

Now try NumPy:

a = np.array([1, 2, 3])
b = np.array([10, 20, 30])

print(a + b)

Output:

[11 22 33]

NumPy adds corresponding values:

1 + 10 = 11
2 + 20 = 22
3 + 30 = 33

That difference becomes extremely important when mathematical calculations start appearing in machine learning.

NumPy arrays are not simply Python lists with a different appearance.

They are structures designed specifically for numerical computation.


Scalars, Vectors, and Matrices

Three words appear constantly when learning AI:

scalar

vector

matrix

The names sound mathematical, but the basic ideas are straightforward.

Scalar: One Number

A scalar is simply one value.

For example:

5.5

or:

92

or:

0.73

A student's study time could be represented by one scalar:

5.5

Nothing complicated yet.


Vector: A Sequence of Numbers

Now suppose we want to describe one student using three features:

Hours studied
Attendance
Previous grade

We can store those values together:

student = np.array([5.5, 92, 78])

print(student)

Output:

[ 5.5 92.  78. ]

This one-dimensional array can represent a vector.

Conceptually:

student
   ↓
[5.5, 92, 78]
  ↑    ↑   ↑
hours  |  previous grade
       |
   attendance

A vector allows several related numerical values to describe one thing.

In machine learning, this is extremely common.

A house could be:

[120, 3, 8]

where the values represent:

[size, bedrooms, age]

A customer could be:

[42, 13, 580.50]

representing:

[age, purchases, total spending]

A machine could be:

[82.4, 0.32, 1450]

representing:

[temperature, vibration, RPM]

The numbers themselves do not tell us what they mean.

Their meaning comes from the feature definition and their position in the vector.

That is why keeping features consistent is so important.

If position zero means hours_studied during training, position zero must not suddenly mean attendance when making a prediction.


Matrix: Many Vectors Together

One student can be represented by one vector:

[5.5, 92, 78]

But machine-learning datasets usually contain many examples.

Suppose we have five students:

students = np.array([
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
])

print(students)

Output:

[[ 5.5 92.  78. ]
 [ 2.  68.  55. ]
 [ 7.  95.  91. ]
 [ 3.5 81.  73. ]
 [ 4.5 88.  79. ]]

Now we have a two-dimensional array.

We can think of it as a matrix.

Each row represents one student:

Student 1 → [5.5, 92, 78]
Student 2 → [2.0, 68, 55]
Student 3 → [7.0, 95, 91]
Student 4 → [3.5, 81, 73]
Student 5 → [4.5, 88, 79]

Each column represents one feature:

            hours      attendance    previous grade
              ↓             ↓              ↓

Student 1    5.5            92             78
Student 2    2.0            68             55
Student 3    7.0            95             91
Student 4    3.5            81             73
Student 5    4.5            88             79

This is one of the most important structures in classical machine learning.

You will often see something called X:

X = np.array([
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
])

In many machine-learning examples:

X = input features
y = target or labels

So we might also have:

y = np.array([1, 0, 1, 1, 1])

where:

1 = passed
0 = failed

The complete structure is therefore:

X                              y

[5.5, 92, 78]  ------------>  1
[2.0, 68, 55]  ------------>  0
[7.0, 95, 91]  ------------>  1
[3.5, 81, 73]  ------------>  1
[4.5, 88, 79]  ------------>  1

The model receives the features in X and learns their relationship with the known answers in y.

We are not training that model yet.

For now, we are learning what the data going into that model actually looks like.


Understanding Shape

Once you start working with NumPy, you will constantly see the word shape.

Shape tells us how an array is organized.

Consider:

students = np.array([
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
])

print(students.shape)

Output:

(5, 3)

What does (5, 3) mean?

It means:

5 rows
3 columns

In our dataset:

5 examples
3 features per example

This is exactly the same basic idea you saw with:

df.shape

in pandas.

The difference is that we are now looking directly at a numerical array.

Think of:

shape = (rows, columns)

for a simple two-dimensional dataset.

So:

(1000, 20)

could mean:

1000 examples
20 features per example

A model receiving that dataset is receiving 20 numerical values for each of 1,000 examples.


Dimensions: What Does ndim Mean?

NumPy arrays can have different numbers of dimensions.

You can check this with:

array.ndim

Consider:

scores = np.array([72, 84, 91, 68, 80])

print(scores.ndim)

Output:

1

This is a one-dimensional array.

Its shape is:

print(scores.shape)
(5,)

That means there is one axis containing five values.

The comma in:

(5,)

is simply Python's notation for a tuple containing one item.

Now consider our student dataset:

print(students.ndim)

Output:

2

And:

print(students.shape)

Output:

(5, 3)

It has two dimensions:

rows × columns

A useful beginner picture is:

one value           → scalar

[1, 2, 3]           → 1D array / vector

[[1, 2, 3],
 [4, 5, 6]]         → 2D array / matrix

Arrays can also have three, four, or many more dimensions.

That becomes especially important for images and deep learning.


shape, ndim, and size Are Different

These three properties are easy to confuse.

Consider:

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

Check them:

print(data.shape)
print(data.ndim)
print(data.size)

Output:

(2, 3)
2
6

They answer different questions.

shape

(2, 3)

How is the data arranged?

Two rows and three columns.

ndim

2

How many dimensions or axes does the array have?

Two.

size

6

How many individual values are stored in total?

Six.

So:

shape → organization
ndim  → number of dimensions
size  → total number of elements

This distinction becomes useful very quickly when debugging machine-learning code.


Selecting Values From an Array

Just like Python lists, NumPy arrays use indexes starting at zero.

Consider:

scores = np.array([72, 84, 91, 68, 80])

The first value is:

print(scores[0])

Output:

72

The third:

print(scores[2])

Output:

91

Two-dimensional arrays introduce rows and columns.

Using our student dataset:

students = np.array([
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
])

The first student is:

print(students[0])

Output:

[ 5.5 92.  78. ]

The second student:

print(students[1])

Output:

[ 2. 68. 55.]

To select one specific value, provide both the row and column:

print(students[0, 1])

Output:

92.0

Why?

students[0, 1]
         ↑  ↑
        row column

Row 0 is the first student.

Column 1 is attendance.

Therefore:

students[0, 1]

means:

Give me the attendance value for the first student.


Selecting an Entire Column

This syntax appears strange the first time you see it:

students[:, 0]

But it becomes easy once you read it correctly.

The colon means:

Take everything along this dimension.

So:

students[:, 0]

means:

all rows
column 0

Column zero contains study hours:

study_hours = students[:, 0]

print(study_hours)

Output:

[5.5 2.  7.  3.5 4.5]

Attendance is column one:

attendance = students[:, 1]

print(attendance)

Output:

[92. 68. 95. 81. 88.]

Previous grade is column two:

previous_grades = students[:, 2]

This gives us a useful mental model:

students[row, column]

Examples:

students[0, :]   # every feature from the first student
students[:, 0]   # study hours from every student
students[:, 1]   # attendance from every student
students[:, 2]   # previous grades from every student

You do not need advanced NumPy indexing yet.

If these four examples make sense, you already have enough indexing knowledge for many beginner AI examples.


One Dimension Is Not the Same as Two Dimensions

This causes many beginner errors.

Look at this:

student = np.array([5.5, 92, 78])

print(student.shape)

Output:

(3,)

This is a one-dimensional array containing three values.

Now:

student_2d = np.array([
    [5.5, 92, 78]
])

print(student_2d.shape)

Output:

(1, 3)

These arrays contain the same three numbers, but their shapes are different.

(3,)   → one-dimensional array with 3 values

(1, 3) → two-dimensional array with
          1 row
          3 columns

That distinction matters because many machine-learning functions expect data in the form:

(number of examples, number of features)

So one student with three features may need to look like:

(1, 3)

rather than:

(3,)

You can change the shape with reshape():

student = np.array([5.5, 92, 78])

student_2d = student.reshape(1, 3)

print(student_2d)
print(student_2d.shape)

Output:

[[ 5.5 92.  78. ]]

(1, 3)

Nothing about the actual values changed.

Only their organization changed.

This is exactly what reshape means.


Data Types: What Kind of Numbers Are Stored?

NumPy arrays also have a data type, usually called a dtype.

Create an integer array:

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

print(numbers.dtype)

NumPy reports an integer type.

Now:

numbers = np.array([1.5, 2.5, 3.5])

print(numbers.dtype)

It reports a floating-point type.

You normally do not need to choose the exact dtype when starting out, but understanding that it exists is useful.

NumPy generally stores an array using one common data type.

For example:

student = np.array([5.5, 92, 78])

print(student)

You may notice:

[ 5.5 92.  78. ]

The values 92 and 78 are displayed as floating-point numbers.

Why?

Because the array also contains 5.5.

NumPy chooses a compatible numerical type that can represent all the values.

This is usually exactly what we want for numerical computation.

But it can also reveal mistakes.

For example:

values = np.array([10, 20, "30"])

print(values)
print(values.dtype)

Because one value is text, NumPy may represent the array as strings rather than as normal numerical values.

That can cause problems later if you expect to perform mathematics.

It is one reason data types matter when preparing datasets.


Performing Calculations on Arrays

Now that we understand how arrays are organized, we can use them for calculations.

Consider:

scores = np.array([72, 84, 91, 68, 80])

Add five:

print(scores + 5)
[77 89 96 73 85]

Multiply everything by two:

print(scores * 2)
[144 168 182 136 160]

Divide everything by 100:

print(scores / 100)
[0.72 0.84 0.91 0.68 0.8 ]

We can also compare values:

print(scores >= 80)

Output:

[False  True  True False  True]

NumPy performed the comparison for every value.

We can use that result to select only the matching values:

high_scores = scores[scores >= 80]

print(high_scores)

Output:

[84 91 80]

Read this expression:

scores[scores >= 80]

as:

Give me the values from scores where the condition score >= 80 is true.

This same basic idea is closely related to the filtering you used with pandas.

Different library, same general data-thinking skill.


What Is Broadcasting?

You have already used broadcasting without realizing it.

When we wrote:

scores + 5

we combined:

an array containing several values

with:

one value

NumPy understood that the 5 should be applied across the array.

Conceptually:

[72, 84, 91, 68, 80]
 +
  5

behaves like:

[72 + 5,
 84 + 5,
 91 + 5,
 68 + 5,
 80 + 5]

NumPy calls this kind of compatible expansion broadcasting.

Broadcasting can become much more sophisticated when multidimensional arrays are involved, but we do not need those rules yet.

For now, remember this:

NumPy can often apply smaller numerical values or arrays across larger arrays when their shapes are compatible.

When shapes are not compatible, NumPy will tell you.

And that leads us to one of the most common NumPy problems.


Shape Mismatches

Consider:

a = np.array([1, 2, 3])
b = np.array([10, 20])

print(a + b)

NumPy cannot pair these values cleanly.

We have:

a → 3 values
b → 2 values

What should happen?

Should NumPy calculate:

1 + 10
2 + 20
3 + ???

There is no obvious answer.

So the operation fails because the shapes are incompatible.

This is why examining:

array.shape

is one of the first things you should do when numerical AI code produces a confusing error.

You will eventually encounter many errors whose real meaning is simply:

The numbers are arranged differently from what this operation expects.

Understanding shape now will save you a lot of confusion later.


From pandas to NumPy

Now we can connect this directly to the previous article.

Suppose our data starts in a CSV file:

hours_studied,attendance,previous_grade,passed
5.5,92,78,1
2.0,68,55,0
7.0,95,91,1
3.5,81,73,1
4.5,88,79,1

Load it with pandas:

import pandas as pd

df = pd.read_csv("students.csv")

Then select the input features:

X = df[
    ["hours_studied", "attendance", "previous_grade"]
]

And the target:

y = df["passed"]

At this point, X is still a pandas DataFrame.

Print it:

print(X)

You get something conceptually like:

   hours_studied  attendance  previous_grade
0            5.5          92              78
1            2.0          68              55
2            7.0          95              91
3            3.5          81              73
4            4.5          88              79

pandas is excellent here because the column names carry meaning.

But we can convert those values into a NumPy array:

X_array = X.to_numpy()

print(X_array)

Output:

[[ 5.5 92.  78. ]
 [ 2.  68.  55. ]
 [ 7.  95.  91. ]
 [ 3.5 81.  73. ]
 [ 4.5 88.  79. ]]

Now:

print(X_array.shape)

gives:

(5, 3)

Five examples.

Three features.

We can do the same with the labels:

y_array = y.to_numpy()

print(y_array)
print(y_array.shape)

Output:

[1 0 1 1 1]

(5,)

This is the connection between pandas and NumPy:

CSV file
   ↓
pandas DataFrame
   ↓
inspect and prepare data
   ↓
numerical arrays
   ↓
machine-learning calculations

You should not take this diagram too literally.

Many machine-learning libraries can accept pandas DataFrames directly, so you do not always need to manually call .to_numpy() before training a model.

The important lesson is conceptual.

The headings, labels, and table formatting are useful to us as programmers.

The calculations performed by machine-learning algorithms ultimately operate on numerical values with specific dimensions and shapes.

That is the world NumPy helps us understand.


Images Are Arrays of Numbers

So far, our data already started as numbers.

But what about something that looks completely different, such as a photograph?

A computer image is also numerical data.

Let's start with the simplest case: a tiny grayscale image.

Imagine this 3 × 3 image:

dark     gray     bright
gray     bright   gray
bright   gray     dark

We could represent it as:

image = np.array([
    [0,   128, 255],
    [128, 255, 128],
    [255, 128, 0]
])

For a common 8-bit grayscale representation:

0   → black
255 → white

Values between them represent different brightness levels.

So:

128

is roughly halfway between black and white.

Our matrix:

[
    [0,   128, 255],
    [128, 255, 128],
    [255, 128, 0]
]

is not just a random collection of numbers.

It describes an image.

Check its shape:

print(image.shape)

Output:

(3, 3)

Three rows of pixels.

Three columns of pixels.

The model does not need a tiny picture drawn on the screen.

It can work with the numerical values that represent that picture.

That is the important connection:

what we see:

an image

what the computer can work with:

an array of pixel values

What About Color Images?

A color image needs more information.

One common representation uses three values for each pixel:

Red
Green
Blue

or RGB.

A pixel might therefore look like:

[255, 0, 0]

which represents strong red with no green or blue.

Another pixel could be:

[0, 255, 0]

for green.

And:

[0, 0, 255]

for blue.

Instead of each pixel containing one number, each pixel now contains three.

That means a color image can have a shape such as:

(1080, 1920, 3)

Conceptually:

height × width × color channels

or:

1080 rows of pixels
1920 columns of pixels
3 color values per pixel

We will return to images properly when we reach computer vision later in this series.

For now, the important point is not image processing.

The important point is:

Something that looks visual to us can still be represented as a multidimensional numerical array.


Text Must Become Numbers Too

Images becoming pixels may feel intuitive.

Text is less obvious.

Suppose we have:

AI learns from data

A mathematical model cannot directly perform ordinary numerical calculations on those letters.

Modern language systems therefore transform text into numerical representations.

A simplified intermediate step might look like:

AI104
learns  → 582
from27
data    → 913

producing:

[104, 582, 27, 913]

Real language models usually break text into units called tokens, and those tokens can be associated with numerical IDs.

There is an important warning here.

If:

data → 913
from27

that does not mean the word data has more meaning than from because 913 is larger than 27.

Those numbers can simply identify tokens.

Modern language models then use richer numerical representations, including vectors called embeddings, to represent useful patterns and relationships.

We will explore tokenization and embeddings properly later in this series.

For now, remember the larger idea:

table → numerical features

image → pixel values

text → tokens and numerical representations

Different kinds of information eventually become structures made from numbers.

That is one of the foundations of modern AI.


A Complete NumPy Exercise

Let's put the important pieces together.

Start by importing NumPy:

import numpy as np

Create our student feature matrix:

students = np.array([
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91],
    [3.5, 81, 73],
    [4.5, 88, 79]
])

And the labels:

passed = np.array([1, 0, 1, 1, 1])

First inspect the arrays:

print(students)
print(passed)

Now examine the structure:

print("Students shape:", students.shape)
print("Students dimensions:", students.ndim)
print("Students size:", students.size)

print("Labels shape:", passed.shape)

You should get:

Students shape: (5, 3)
Students dimensions: 2
Students size: 15

Labels shape: (5,)

Why is the size 15?

Because:

5 students × 3 features = 15 values

Now retrieve the first student:

first_student = students[0]

print(first_student)

Output:

[ 5.5 92.  78. ]

Retrieve only the study hours:

study_hours = students[:, 0]

print(study_hours)

Output:

[5.5 2.  7.  3.5 4.5]

Retrieve attendance:

attendance = students[:, 1]

print(attendance)

Output:

[92. 68. 95. 81. 88.]

Convert attendance percentages to decimal values:

attendance_decimal = attendance / 100

print(attendance_decimal)

Output:

[0.92 0.68 0.95 0.81 0.88]

Select students with at least 90 percent attendance:

high_attendance = students[
    students[:, 1] >= 90
]

print(high_attendance)

The matching rows are:

[[ 5.5 92.  78. ]
 [ 7.  95.  91. ]]

Notice what happened.

We began with a complete matrix.

We selected one column.

We performed a numerical operation on that entire column.

We created a condition.

Then we used that condition to select matching rows.

That is already a small but realistic numerical-data workflow.

And we did it without manually looping through every student.


Common NumPy Mistakes

NumPy is not especially difficult, but a few ideas confuse almost everyone at the beginning.

Mistake 1: Treating a NumPy Array Like a Python List

Remember:

[1, 2, 3] + [4, 5, 6]

joins lists.

But:

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

performs numerical addition.

Know which type of object you are working with.


Mistake 2: Ignoring Shape

These are not the same:

(3,)

and:

(1, 3)

One is one-dimensional.

The other is a two-dimensional matrix with one row and three columns.

When machine-learning code complains about dimensions, print the shape:

print(X.shape)

That simple line often tells you exactly where the problem is.


Mistake 3: Confusing size With shape

For:

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

we have:

shape = (2, 3)
size  = 6

Shape tells you the structure.

Size tells you the total number of values.


Mistake 4: Mixing Incompatible Shapes

This works:

np.array([1, 2, 3]) + 10

This also works:

np.array([1, 2, 3]) + np.array([10, 20, 30])

But this does not naturally match:

np.array([1, 2, 3]) + np.array([10, 20])

Whenever an array operation fails, compare the shapes of the arrays involved.


Mistake 5: Forgetting About Data Types

This looks innocent:

data = np.array([10, 20, "30"])

But "30" is text.

That can influence the dtype of the entire array and prevent the numerical behavior you expected.

Machine-learning datasets often fail for surprisingly simple reasons such as numbers accidentally being stored as strings.


Mistake 6: Thinking Numerical IDs Automatically Carry Meaning

If a token is represented by:

913

and another by:

27

you cannot conclude that the first token is somehow “larger,” “stronger,” or “more important.”

Numerical representation does not always mean numerical magnitude carries meaning.

Understanding what each number represents is just as important as having the number itself.


Mini Challenge: Build a Tiny Image

Create a 3 × 3 grayscale image using a NumPy array.

Use values between:

0 and 255

where:

0   = black
255 = white

Start with:

import numpy as np

image = np.array([
    [..., ..., ...],
    [..., ..., ...],
    [..., ..., ...]
])

Choose your own pixel values.

Then answer these questions using Python:

  1. What is the shape of the image?
  2. How many dimensions does it have?
  3. How many pixel values are stored?
  4. What is the darkest pixel value?
  5. What is the brightest pixel value?
  6. What happens if you calculate 255 - image?

Try it before reading the solution.


One Possible Solution

For example:

image = np.array([
    [0,   128, 255],
    [64,  192, 64],
    [255, 128, 0]
])

Check the shape:

print(image.shape)
(3, 3)

Check the number of dimensions:

print(image.ndim)
2

Check the number of values:

print(image.size)
9

Find the darkest value:

print(image.min())
0

Find the brightest:

print(image.max())
255

Now invert the values:

inverted = 255 - image

print(inverted)

Result:

[[255 127   0]
 [191  63 191]
 [  0 127 255]]

Notice what happened.

A black pixel:

0

became:

255

A white pixel:

255

became:

0

And the intermediate shades changed accordingly.

We performed an operation on an entire image using one expression:

255 - image

That tiny example demonstrates exactly why numerical arrays are so powerful.

Once data has been represented numerically, mathematical operations can transform many values at once.


The Bigger Picture

At this point, NumPy should not feel like just another Python library.

It represents a larger idea.

When we build AI systems, we repeatedly convert information into structured numbers.

One student:

[5.5, 92, 78]

is a vector of features.

Many students:

[
    [5.5, 92, 78],
    [2.0, 68, 55],
    [7.0, 95, 91]
]

form a matrix.

A grayscale image can become:

[
    [0, 128, 255],
    [128, 255, 128],
    [255, 128, 0]
]

A color image can have a shape such as:

(height, width, 3)

Text can be transformed into tokens and later into richer numerical vectors.

Different types of data look completely different to us.

But once converted into numerical representations, models can perform mathematical operations on them.

This is one of the bridges between the real world and machine learning.


Key Takeaways

The important ideas from this article are:

  • NumPy is a Python library for numerical array computing.
  • A scalar is one numerical value.
  • A vector can represent several related values, such as the features of one example.
  • A matrix can represent many examples, with rows usually representing examples and columns representing features.
  • A NumPy array's shape tells you how its values are organized.
  • ndim tells you how many dimensions an array has.
  • size tells you how many total values it contains.
  • NumPy can perform operations across entire arrays without requiring explicit Python loops.
  • Array indexing lets you select individual values, rows, columns, and subsets.
  • Shape mismatches are one of the most common sources of confusion in numerical code.
  • pandas is excellent for loading and inspecting tabular data, while NumPy helps expose its numerical structure.
  • Images can be represented as arrays of pixel values.
  • Text must also eventually be converted into numerical representations before modern machine-learning models can process it.
  • Understanding arrays and shapes now will make later machine-learning code much easier to understand.

What Comes Next

We now have the pieces needed to describe data numerically.

We know what it means when a dataset has a shape such as:

(1000, 20)

We know how one example can become a vector, how many examples can become a matrix, and how completely different kinds of information such as images and text can eventually be represented using numbers.

But having numbers is only the beginning.

The next question is:

What mathematics do machine-learning systems actually perform with those numbers?

This is where many people assume AI suddenly requires advanced mathematics.

It does not.

Before learning actual machine-learning algorithms, we need a small collection of mathematical ideas that appear again and again: averages, variation, probability, relationships between variables, functions, vectors, matrices, and prediction error.

That is what we will cover next in The Math You Actually Need for AI.

The goal will not be to turn this series into a mathematics textbook.

It will be to understand enough mathematics that when a machine-learning model starts calculating, measuring errors, and learning patterns, you understand what those calculations are trying to accomplish.

More to read


Working With Data Using Pandas
13/8/2026

Once you move from basic Python into data science, machine learning, or AI, one of the first things you need to become comfortable with is working with tables of data. Most AI projects do not begin with a clever model or a complicated algorithm.

Python for AI: The Minimum You Actually Need
13/8/2026

If you already know how to write a variable, create a function, run a loop, and use an `if` statement, you know enough Python to start moving toward AI.

What Makes a Good AI Problem?
13/8/2026

Artificial intelligence is powerful, but that does not mean every problem should be solved with AI. In many situations, a simple rule, a spreadsheet formula, or basic automation can solve the problem faster, more cheaply, and more reliably. A good AI project begins by asking a more important question than “How can we use AI?” The better question is: “Does this problem actually need AI?”

The Complete AI Development Pipeline: From Idea to Deployed AI System
13/8/2026

Artificial intelligence can sometimes look like magic. You give a computer thousands of examples, train a model, and suddenly it can recognize spam emails, detect defects in products, analyze medical images, or answer questions about documents.