My NumPy 1D Arrays Journey: Mastering Numerical Computing in Python¶

Author: Mohammad Sayem Chowdhury
Data Science Enthusiast & Python Developer

Welcome to my comprehensive exploration of one-dimensional NumPy arrays! As someone deeply passionate about data science and numerical computing, I've found NumPy to be absolutely essential for efficient data manipulation and mathematical operations.

This notebook represents my personal journey in understanding and applying NumPy's powerful array operations.

Why NumPy Arrays Changed My Data Science Game

After working extensively with Python lists, discovering NumPy arrays was a game-changer for my data analysis workflow. The performance improvements and mathematical capabilities opened up entirely new possibilities for my projects.

In this notebook, I'll share my hands-on experience with NumPy arrays, demonstrating the concepts and operations that have become fundamental to my data science toolkit. Through practical examples and real-world applications, I'll show you why NumPy is indispensable for numerical computing.

Table of Contents

  • Preparation
  • What is Numpy?
    • Type
    • Assign Value
    • Slicing
    • Assign Value with List
    • Other Attributes
  • Numpy Array Operations
    • Array Addition
    • Array Multiplication
    • Product of Two Numpy Arrays
    • Dot Product
    • Adding Constant to a Numpy Array
  • Mathematical Functions
  • Linspace

Estimated time needed: 30 min


My Learning Path Today¶

What I'll Explore:¶

  1. Setting Up My Environment - Essential imports and utility functions
  2. From Python Lists to NumPy Arrays - Why I made the switch
  3. Understanding NumPy Fundamentals
    • Array types and data types
    • Indexing and value assignment
    • Slicing techniques
    • Advanced indexing with lists
    • Essential array attributes
  4. Mathematical Operations That Transform My Analysis
    • Array addition and vector operations
    • Scalar and element-wise multiplication
    • Dot products and their applications
    • Broadcasting with constants
  5. Mathematical Functions for Real Analysis - Trigonometric and mathematical operations
  6. Linspace: My Tool for Data Generation - Creating evenly spaced data
  7. Practical Exercises & Applications - Hands-on problems I've solved
  8. My Key Takeaways & Next Steps - Personal insights and future learning

Estimated Learning Time: 25-30 minutes

This represents my personal understanding and practical application of NumPy concepts.

Setting Up My NumPy Environment {#setup}¶

First, let me import the essential libraries that I use in almost every data science project:

In [ ]:
# Import the libraries

# My essential data science toolkit
import time 
import sys
import numpy as np  # The backbone of numerical computing
import matplotlib.pyplot as plt  # For creating insightful visualizations

# Enable inline plotting for Jupyter notebooks
%matplotlib inline

print("NumPy version:", np.__version__)
print("Environment ready for numerical computing!")
In [ ]:
# My custom visualization functions for vector operations
# These help me understand the geometric interpretation of array operations

def plot_three_vectors(u, z, v):
    """
    Visualize three vectors to understand addition operations.
    I use this to see how vector addition works geometrically.
    """
    ax = plt.axes()
    ax.arrow(0, 0, *u, head_width=0.05, color='red', head_length=0.1, label='Vector u')
    plt.text(*(u + 0.1), 'u', fontsize=12, fontweight='bold')
    
    ax.arrow(0, 0, *v, head_width=0.05, color='blue', head_length=0.1, label='Vector v')
    plt.text(*(v + 0.1), 'v', fontsize=12, fontweight='bold')
    
    ax.arrow(0, 0, *z, head_width=0.05, color='green', head_length=0.1, label='Result z')
    plt.text(*(z + 0.1), 'z=u+v', fontsize=12, fontweight='bold')
    
    plt.ylim(-2, 2)
    plt.xlim(-2, 2)
    plt.grid(True, alpha=0.3)
    plt.title('Vector Addition Visualization')
    plt.axhline(y=0, color='k', linewidth=0.5)
    plt.axvline(x=0, color='k', linewidth=0.5)

def plot_two_vectors(a, b):
    """
    Compare two vectors side by side.
    Perfect for understanding relationships between different vectors.
    """
    ax = plt.axes()
    ax.arrow(0, 0, *a, head_width=0.05, color='red', head_length=0.1)
    plt.text(*(a + 0.1), 'a', fontsize=12, fontweight='bold')
    
    ax.arrow(0, 0, *b, head_width=0.05, color='blue', head_length=0.1)
    plt.text(*(b + 0.1), 'b', fontsize=12, fontweight='bold')
    
    plt.ylim(-2, 2)
    plt.xlim(-2, 2)
    plt.grid(True, alpha=0.3)
    plt.title('Vector Comparison')
    plt.axhline(y=0, color='k', linewidth=0.5)
    plt.axvline(x=0, color='k', linewidth=0.5)

print("Visualization functions loaded successfully!")

Create a Python List as follows:

From Python Lists to NumPy Arrays: My Journey {#transition}¶

Let me start by showing you where I began - with Python lists. Here's a typical mixed-type list I might have used in my early Python days:

In [ ]:
# A typical mixed-type Python list from my early programming days

my_mixed_data = ["score", 85, "grade", "A", 92]
print("My mixed list:", my_mixed_data)
print("List type:", type(my_mixed_data))

We can access the data via an index:

I can access individual elements using index positions, which works fine for small datasets:

Index:   0        1      2        3      4
Value: "score"   85   "grade"   "A"    92
       [0]      [1]     [2]     [3]    [4]

Each element can be accessed using its zero-based index position.

Let me demonstrate the indexing approach I used before discovering NumPy:

In [ ]:
# Accessing elements the traditional way
print("Element at index 0:", my_mixed_data[0])
print("Element at index 1:", my_mixed_data[1])
print("Element at index 2:", my_mixed_data[2])
print("Element at index 3:", my_mixed_data[3])
print("Element at index 4:", my_mixed_data[4])

print("\nThis approach works, but becomes inefficient for large numerical datasets!")
a[0]: 0
a[1]: 1
a[2]: two
a[3]: 3
a[4]: 4


The NumPy Revolution in My Workflow¶

Understanding NumPy Arrays: My Foundation {#fundamentals}¶

Here's where my data science journey truly began. NumPy arrays changed everything for my numerical computing needs.

A NumPy array is like a supercharged Python list, but with crucial advantages that revolutionized my data analysis:

  • Homogeneous data types: All elements are the same type (much faster)
  • Fixed size: More memory efficient than dynamic lists
  • Vectorized operations: Mathematical operations on entire arrays at once
  • Broadcasting: Powerful element-wise operations

Let me show you how I create and work with NumPy arrays:

In [ ]:
# The foundation of my numerical computing toolkit

import numpy as np
print("NumPy imported - ready for high-performance numerical operations!")

Now I'll create my first NumPy array from a simple list of numbers:

In [ ]:
# Creating my first NumPy array
my_scores = np.array([85, 88, 92, 79, 95])
print("My NumPy array:", my_scores)
print("Array type:", type(my_scores))
print("Element type:", my_scores.dtype)
print("Array shape:", my_scores.shape)
Out[ ]:
array([0, 1, 2, 3, 4])

Notice how all elements are now the same type (integers). This homogeneity is what makes NumPy arrays so powerful for mathematical operations:

NumPy Array Structure:
Index:  0   1   2   3   4
Value: 85  88  92  79  95
Type:  int32 (all elements same type)

Unlike Python lists, every element has the same data type, enabling efficient computation.

Accessing elements works the same way as lists, but now with the power of NumPy behind it:

In [ ]:
# Accessing individual scores
print("First score:", my_scores[0])
print("Second score:", my_scores[1])
print("Third score:", my_scores[2])
print("Fourth score:", my_scores[3])
print("Fifth score:", my_scores[4])

print("\nBut NumPy offers much more powerful ways to work with this data!")
a[0]: 0
a[1]: 1
a[2]: 2
a[3]: 3
a[4]: 4

Understanding Data Types: Why They Matter in My Analysis¶

Understanding data types is crucial for my numerical analysis. Let me check what type of NumPy array I've created:

In [ ]:
# Checking the overall array type
array_type = type(my_scores)
print("Array type:", array_type)
print("This tells me I'm working with a NumPy ndarray (n-dimensional array)")
Out[ ]:
numpy.ndarray

As numpy arrays contain data of the same type, we can use the attribute "dtype" to obtain the Data-type of the array’s elements. In this case a 64-bit integer. The dtype attribute tells me the specific data type of the elements. This is crucial for memory efficiency and computational performance:

In [ ]:
# Check the type of the values stored in numpy array

a.dtype

# Understanding the element data type
data_type = my_scores.dtype
print("Element data type:", data_type)
print("This means each element is a 64-bit integer")
print("Memory efficient and perfect for mathematical operations!")
Out[ ]:
dtype('int64')

We can create a numpy array with real numbers:

For my data analysis projects, I often work with decimal numbers. Let me create a floating-point array:

In [ ]:
# Create a numpy array

my_gpa_data = np.array([3.85, 3.92, 3.76, 3.88, 3.95])
print("My GPA data:", my_gpa_data)
print("Data type:", my_gpa_data.dtype)

Even with decimal numbers, I still get a NumPy ndarray, but with a different element type:

In [ ]:
# Confirming it's still a NumPy array
print("Array type:", type(my_gpa_data))
print("Same NumPy ndarray type, different element precision")
Out[ ]:
numpy.ndarray

The dtype shows float64 because NumPy automatically chose the most appropriate precision for my decimal numbers:

In [ ]:
# Examining the float data type
print("Float data type:", my_gpa_data.dtype)
print("This gives me 64-bit precision for accurate decimal calculations")
print("Perfect for statistical analysis and data science!")

# Check the value type

b.dtype
Out[ ]:
dtype('float64')

Modifying Array Values: Dynamic Data Updates¶

We can change the value of the array, consider the array c: In my data analysis workflow, I often need to update or correct values. NumPy makes this straightforward. Let me demonstrate with a sample dataset:

In [ ]:
# Sample test scores that need correction
test_scores = np.array([78, 85, 92, 88, 91])
print("Original test scores:", test_scores)
Out[ ]:
array([20,  1,  2,  3,  4])

Suppose I need to correct the first score due to a grading error. I can easily update it:

In [ ]:
# Correcting the first score
test_scores[0] = 82  # Updated from 78 to 82
print("Corrected scores:", test_scores)
print("Successfully updated the first score!")
Out[ ]:
array([100,   1,   2,   3,   4])

We can change the 5th element of the array to 0 as follows:

scores = [90, 85, 75, 60, 0]

I can also update any other position. Let's adjust the last score:

scores = [90, 85, 75, 60, 0, 100]
In [ ]:
# Updating the last score

test_scores[4] = 94  # Improved from 91 to 94
print("Final updated scores:", test_scores)
print("Data correction complete!")
Out[ ]:
array([100,   1,   2,   3,   0])

Array Slicing: My Tool for Data Extraction¶

Slicing is one of my most-used NumPy techniques. It allows me to extract specific portions of data efficiently. Let me extract the middle scores from my dataset:

Like lists, we can slice the numpy array, and we can select the elements from 1 to 3 and assign it to a new numpy array d as follows:

In [ ]:
# Extracting middle three scores (indices 1, 2, 3)
middle_scores = test_scores[1:4]
print("Original scores:", test_scores)
print("Middle three scores:", middle_scores)
print("Slicing notation: [1:4] means start at index 1, stop before index 4")
Out[ ]:
array([1, 2, 3])

We can assign the corresponding indexes to new values as follows:

I can also assign new values to a range of indices at once. This is incredibly useful for batch updates:

In [ ]:
# Original test scores
test_scores = [85, 90, 75, 80, 70]

# Displaying original scores
print("Original test scores:", test_scores)

# Batch updating the last two scores (bonus points scenario)
test_scores[3:5] = 95, 98  # Giving bonus points
print("After bonus adjustment:", test_scores)
print("Successfully updated multiple scores at once!")
Out[ ]:
array([100,   1,   2, 300, 400])

Advanced Indexing: Selecting Specific Elements¶

Sometimes I need to select non-consecutive elements from my arrays. This is where list-based indexing becomes powerful: Similarly, we can use a list to select a specific index. The list ' select ' contains several values:

In [ ]:
# Create the index list

# Selecting specific positions (first, third, and fourth scores)
selected_indices = [0, 2, 3]
print("Index list for selection:", selected_indices)

We can use the list as an argument in the brackets. The output is the elements corresponding to the particular index:

Using this index list, I can extract exactly the elements I need:

In [ ]:
# Fancy indexing - selecting specific elements
selected_scores = test_scores[selected_indices]
print("Original scores:", test_scores)
print("Selected scores:", selected_scores)
print("This technique is invaluable for data analysis!")
Out[ ]:
array([100,   2, 300])

We can assign the specified elements to a new value. For example, we can assign the values to 100 000 as follows:

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

I can also use fancy indexing to update multiple non-consecutive elements. Let's apply a curve to specific scores:

scores = np.array([88, 92, 79, 85, 90])
curve = np.array([2, 0, 5])
scores[[0, 3, 4]] += curve
In [ ]:
# Applying grade curve to selected scores
test_scores[selected_indices] = 90, 97, 99
print("After grade curve application:", test_scores)
print("Selective updates make data manipulation very flexible!")
Out[ ]:
array([100000,      1, 100000, 100000,    400])

Essential Array Attributes: Understanding My Data¶

Let's review some basic array attributes using the array a:

NumPy arrays come with built-in attributes that provide crucial information about my data. Let me explore these with a fresh example:

In [ ]:
# Sample dataset for attribute exploration
my_data = np.array([75, 82, 88, 91, 79, 86, 93, 77, 85, 90])
print("My dataset:", my_data)
print("Let's explore its properties...")
Out[ ]:
array([0, 1, 2, 3, 4])

The size attribute tells me how many data points I'm working with - crucial for statistical analysis:

In [ ]:
# Get the size of numpy array

a.size

# Understanding dataset size
data_size = my_data.size
print(f"Number of data points: {data_size}")
print(f"Perfect sample size for basic statistical analysis!")
Out[ ]:
5

The ndim attribute shows the dimensionality. For 1D arrays (like time series or simple datasets), this will be 1:

In [ ]:
# Get the number of dimensions of numpy array

a.ndim

# Checking array dimensions
dimensions = my_data.ndim
print(f"Number of dimensions: {dimensions}")
print("One dimension means this is a simple vector - perfect for basic analysis!")
Out[ ]:
1

The shape attribute gives me the exact structure of my array. For 1D arrays, it shows (length,):

In [ ]:
# Get the shape/size of numpy array

a.shape

# Understanding array shape
array_shape = my_data.shape
print(f"Array shape: {array_shape}")
print(f"This confirms I have {array_shape[0]} elements in a 1D structure")
Out[ ]:
(5,)
In [ ]:
# Create a numpy array

a = np.array([1, -1, 1, -1])




print("Performance data:", performance_data)performance_data = np.array([85, 78, 92, 88, 76, 94, 81, 87])

Let me demonstrate some essential statistical operations I use regularly in my data analysis:# Sample data representing performance variations
### Statistical Analysis with NumPy
In [ ]:
# Get the mean of numpy array

mean = a.mean()
mean

# Calculating mean performance
average_performance = performance_data.mean()
print(f"Average performance: {average_performance:.2f}")
print("This gives me the central tendency of my data")
Out[ ]:
0.0
In [ ]:
# Measuring performance variability

# Get the standard deviation of numpy array
standard_deviation = a.std()
standard_deviation

performance_std = performance_data.std()
print(f"Standard deviation: {performance_std:.2f}")
print("This tells me how consistent the performance is")
Out[ ]:
1.0
In [ ]:
# Create a numpy array

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

# New dataset for range analysis
sales_data = np.array([150, 280, 190, 340, 220])
print("Sales data (in thousands):", sales_data)
Out[ ]:
array([-1,  2,  3,  4,  5])
In [ ]:
# Finding peak performance

# Get the biggest value in the numpy array
max_b = b.max()

max_sales = sales_data.max()
print(f"Highest sales: ${max_sales}k")
print("This identifies my best performing period")
Out[ ]:
5
In [ ]:
# Identifying lowest performance
min_sales = sales_data.min()
print(f"Lowest sales: ${min_sales}k")
print(f"Range: ${min_sales}k to ${max_sales}k")
print("This shows the full performance spectrum")

# Get the smallest value in the numpy array

min_b = b.min()
min_b
Out[ ]:
-1


Mathematical Operations: Where NumPy Shines¶

NumPy Array Operations: My Mathematical Toolkit {#operations}¶

This is where NumPy truly revolutionizes data analysis. The vectorized operations enable me to perform complex calculations efficiently on entire datasets.

Vector Addition: Combining Data Streams¶

Let me demonstrate vector addition with two data vectors representing different metrics:

In [ ]:
import numpy as np

# First metric vector (e.g., morning sales)
morning_sales = np.array([120, 85])
print("Morning sales vector:", morning_sales)
Out[ ]:
array([1, 0])

Consider the numpy array v:

Now let me create a second vector representing afternoon performance:

In [ ]:
v = np.array([0, 1])
v

# Second metric vector (e.g., afternoon sales)
afternoon_sales = np.array([80, 140])
print("Afternoon sales vector:", afternoon_sales)
Out[ ]:
array([0, 1])

We can add the two arrays and assign it to z:

Adding these vectors gives me the combined daily performance:

In [ ]:
# Vector addition - combining daily sales

daily_total = morning_sales + afternoon_sales
print("Morning sales:", morning_sales)
print("Afternoon sales:", afternoon_sales)
print("Total daily sales:", daily_total)
print("Element-wise addition: [120+80, 85+140] = [200, 225]")
Out[ ]:
array([1, 1])

This operation has a beautiful geometric interpretation. Vector addition follows the parallelogram rule:

In [ ]:
# Visualizing vector addition geometrically
plot_three_vectors(morning_sales, daily_total, afternoon_sales)
plt.title("Sales Vector Addition: Morning + Afternoon = Daily Total")
plt.xlabel("Sales Metric 1")
plt.ylabel("Sales Metric 2")
plt.show()
No description has been provided for this image

Array Multiplication

Scalar Multiplication: Scaling My Data¶

Consider the vector numpy array y:

Scalar multiplication is perfect for scaling data - like applying percentage increases or converting units:

In [ ]:
# Base performance metrics
base_metrics = np.array([100, 85])
print("Base performance metrics:", base_metrics)
Out[ ]:
array([1, 2])

We can multiply every element in the array by 2: If I want to project a 20% increase across all metrics:

In [ ]:
# Numpy Array Multiplication

# Base metrics
base_metrics = 100

# Applying 20% increase (multiplying by 1.2)
projected_metrics = 1.2 * base_metrics
print("Base metrics:", base_metrics)
print("20% increase projection:", projected_metrics)
print("Each element scaled by the same factor")
Out[ ]:
array([2, 4])

This is equivalent to multiplying a vector by a scaler:

Geometrically, scalar multiplication stretches or shrinks the vector while maintaining its direction:

Product of Two Numpy Arrays

Element-wise Multiplication: Combining Datasets¶

Consider the following array u:

Element-wise multiplication is incredibly useful for combining related datasets. Let me demonstrate:

In [ ]:
# Quantity sold per product
quantities = np.array([50, 30])
print("Quantities sold:", quantities)
Out[ ]:
array([1, 2])

Consider the following array v: Now let me multiply by the unit prices to get revenue:

In [ ]:
# Create a numpy array

v = np.array([3, 2])
v

# Unit prices per product
unit_prices = np.array([25, 40])
print("Unit prices:", unit_prices)
Out[ ]:
array([3, 2])

Element-wise multiplication gives me the revenue for each product:

In [ ]:
# Calculate the production of two numpy arrays

# Calculate revenue per product
revenue_per_product = quantities * unit_prices
print("Quantities:", quantities)
print("Unit prices:", unit_prices)
print("Revenue per product:", revenue_per_product)
print("Calculation: [50×25, 30×40] = [1250, 1200]")
print(f"Total revenue: ${revenue_per_product.sum()}")
Out[ ]:
array([3, 4])

Dot Product: Measuring Similarity and Projection¶

The dot product is fundamental in data science - it measures how much two vectors align. Perfect for correlation analysis:

The dot product of the two numpy arrays u and v is given by:

In [ ]:
# Calculate dot product for correlation analysis

dot_result = np.dot(quantities, unit_prices)

print("Quantities:", quantities)
print("Unit prices:", unit_prices)
print("Dot product:", dot_result)
print("Formula: (50×25) + (30×40) = 1250 + 1200 = 2450")
print("This single number captures the relationship between quantity and price!")
Out[ ]:
7

Adding Constant to a Numpy Array

Broadcasting: Adding Constants Efficiently¶

Consider the following array:

Broadcasting allows me to perform operations between arrays and single values - incredibly useful for data transformation:

In [ ]:
# Sample test scores needing adjustment
raw_scores = np.array([88, 92, 76, 85])
print("Raw test scores:", raw_scores)
Out[ ]:
array([ 1,  2,  3, -1])

Adding the constant 1 to each element in the array:

Suppose I need to apply a 5-point bonus to all scores due to a difficult exam:

In [ ]:
# Applying bonus points to all scores
adjusted_scores = raw_scores + 5
print("Raw scores:", raw_scores)
print("Adjusted scores (+5 bonus):", adjusted_scores)
print("Broadcasting automatically applies the operation to every element!")
Out[ ]:
array([2, 3, 4, 0])

Broadcasting works by automatically extending the scalar value to match the array shape:

Original: [88, 92, 76, 85]
Broadcast: [88, 92, 76, 85] + [5, 5, 5, 5]
Result: [93, 97, 81, 90]

This happens automatically - no loops needed!


Mathematical Functions: My Scientific Computing Arsenal {#math-functions}¶

NumPy provides access to essential mathematical constants and functions that I use regularly in scientific computing and data analysis.

Mathematical Functions

Access to mathematical constants like π is built right into NumPy:

We can access the value of pie in numpy as follows :

Mathematical constant π¶

pi_value = np.pi print(f"π = {pi_value}") print(f"2π = {2 * pi_value}") print("Essential for trigonometric calculations and signal processing!")

In [ ]:
# The value of pie

np.pi

Let me create an array of important angles in radians for trigonometric analysis:
Out[ ]:
3.141592653589793

We can create the following numpy array in Radians:

import numpy as np

# Key angles in radians for analysis
key_angles = np.array([0, np.pi/4, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
print("Key angles (radians):", key_angles)
print("Corresponding degrees:", key_angles * 180 / np.pi)

This code will output the key angles in radians and their corresponding values in degrees.

In [ ]:
# Create the numpy array in radians

x = np.array([0, np.pi/2 , np.pi])

Now I can apply trigonometric functions to analyze wave patterns, cycles, or periodic behavior:

We can apply the function sin to the array x and assign the values to the array y; this applies the sine function to each element in the array:

Trigonometric analysis¶

sine_values = np.sin(key_angles) cosine_values = np.cos(key_angles)

print("Angles (radians):", np.round(key_angles, 3)) print("Sine values:", np.round(sine_values, 3)) print("Cosine values:", np.round(cosine_values, 3)) print("\nPerfect for signal processing and wave analysis!")

In [ ]:
---

## Data Generation with Linspace

# Calculate the sin of each elements

y = np.sin(x)
y
Out[ ]:
array([0.0000000e+00, 1.0000000e+00, 1.2246468e-16])

Linspace: My Tool for Data Generation {#linspace}¶

np.linspace is one of my favorite functions for creating evenly spaced data points. It's essential for plotting functions, creating test data, and sampling continuous ranges.

Linspace

Let me demonstrate how I use linspace to create evenly distributed sample points. This is incredibly useful for plotting smooth curves and generating test datasets:

A useful function for plotting mathematical functions is "linespace". Linespace returns evenly spaced numbers over a specified interval. We specify the starting point of the sequence and the ending point of the sequence. The parameter "num" indicates the Number of samples to generate, in this case 5:

Creating evenly spaced samples¶

sample_points = np.linspace(-2, 2, num=5) print("5 evenly spaced points from -2 to 2:") print(sample_points) print("\nSpacing between points:", sample_points[1] - sample_points[0])

In [ ]:
# Makeup a numpy array within [-2, 2] and 5 elements

np.linspace(-2, 2, num=5)

# Increasing the number of points gives me finer resolution - perfect for smooth plotting:
Out[ ]:
array([-2., -1.,  0.,  1.,  2.])

If we change the parameter num to 9, we get 9 evenly spaced numbers over the interval from -2 to 2:

Higher resolution sampling¶

high_res_points = np.linspace(-2, 2, num=9) print("9 evenly spaced points from -2 to 2:") print(high_res_points) print("\nNew spacing:", high_res_points[1] - high_res_points[0]) print("Smaller spacing = smoother curves!")

In [ ]:
# Makeup a numpy array within [-2, 2] and 9 elements

import numpy as np

# For plotting mathematical functions, I typically use 100 or more points to ensure smooth curves:
x = np.linspace(-2, 2, num=100)
Out[ ]:
array([-2. , -1.5, -1. , -0.5,  0. ,  0.5,  1. ,  1.5,  2. ])

We can use the function line space to generate 100 evenly spaced samples from the interval 0 to 2π:

High-resolution data for smooth plotting¶

x_values = np.linspace(0, 2*np.pi, num=100) print(f"Created {len(x_values)} points from 0 to 2π") print(f"First few points: {x_values[:5]}") print(f"Last few points: {x_values[-5:]}") print("Perfect resolution for smooth curve plotting!")

In [ ]:
# Makeup a numpy array within [0, 2π] and 100 elements 

x = np.linspace(0, 2*np.pi, num=100)

Now I can apply any mathematical function to create beautiful, smooth curves:

We can apply the sine function to each element in the array x and assign it to the array y:

Generate smooth sine wave data¶

y_values = np.sin(x_values) print(f"Generated {len(y_values)} sine values") print(f"Min value: {y_values.min():.3f}") print(f"Max value: {y_values.max():.3f}") print("Ready for beautiful visualization!")

In [ ]:
import numpy as np
import matplotlib.pyplot as plt

# Generate x values
x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)

# Calculate the sine of x list
y = np.sin(x)

# Create beautiful sine wave visualization
plt.figure(figsize=(12, 6))
plt.plot(x, y, 'b-', linewidth=2, label='sin(x)')
plt.grid(True, alpha=0.3)
plt.xlabel('x (radians)', fontsize=12)
plt.ylabel('sin(x)', fontsize=12)
plt.title('My Smooth Sine Wave Using NumPy Linspace', fontsize=14, fontweight='bold')
plt.axhline(y=0, color='k', linewidth=0.5)
plt.axvline(x=0, color='k', linewidth=0.5)
plt.legend()

# Add key points
key_x = np.array([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
key_y = np.sin(key_x)
plt.scatter(key_x, key_y, color='red', s=50, zorder=5)

plt.tight_layout()
plt.show()

print("This demonstrates the power of NumPy for mathematical visualization!")
In [ ]:
# Plot the result

plt.plot(x, y)

---

## Putting It All Together: Practice Exercises
Out[ ]:
[<matplotlib.lines.Line2D at 0x7fd1d145e550>]
No description has been provided for this image

Practical Exercises: Testing My NumPy Skills {#practice}¶

Let me work through some practical problems that I encounter in real data analysis projects.

Quiz on 1D Numpy Array

Exercise 1: Vector subtraction for difference analysis

Suppose I have two performance vectors and want to find the difference:

Implement the following vector subtraction in numpy: u-v

Performance difference analysis¶

team_a_performance = np.array([95, 88]) team_b_performance = np.array([82, 91])

performance_difference = team_a_performance - team_b_performance print("Team A performance:", team_a_performance) print("Team B performance:", team_b_performance) print("Difference (A - B):", performance_difference) print("Interpretation: Team A leads in metric 1 by 13, trails in metric 2 by 3")

In [ ]:
# Write your code below and press Shift+Enter to execute

u = np.array([1, 0])
v = np.array([0, 1])
d = u-v
d
---
Out[ ]:
array([ 1, -1])

Inverting growth data to show decline scenario¶

growth_rates = np.array([15, 22]) # Percentage growth decline_scenario = -0.5 * growth_rates # 50% decline scenario

print("Original growth rates:", growth_rates, "%") print("Decline scenario (-50%):", decline_scenario, "%") print("This helps me model worst-case scenarios!")

Multiply the numpy array z with -2:


In [ ]:
# Write your code below and press Shift+Enter to execute

z = np.array([2, 4])
d = -2*z
d

**Exercise 3:** Element-wise multiplication for selective analysis

I want to apply different weights to different data points:
Out[ ]:
array([-4, -8])


Exercise 4: Vector analysis with visualization

Analyzing the relationship between two vectors using dot product:

Consider the list [1, 2, 3, 4, 5] and [1, 0, 1, 0, 1], and cast both lists to a numpy array then multiply them together:

In [ ]:
import numpy as np
import matplotlib.pyplot as plt

# Define the function to plot two vectors
def plot_two_vectors(u, v):
    plt.quiver(0, 0, u[0], u[1], angles='xy', scale_units='xy', scale=1, color = 'r', label='u',linewidth=1.5)
    plt.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1, color = 'b', label='v',linewidth=1.5)
    plt.xlim(-2, 2)
    plt.ylim(-2, 2)
    plt.grid()
    plt.legend()

# Write your code below and press Shift+Enter to execute
u = np.array([1, 2, 3, 4, 5]) 
v = np.array([1, 0, 1, 0, 1])
u*v

# Vector relationship analysis
vector_u = np.array([-1, 1])
vector_v = np.array([1, 1])

# Calculate dot product
dot_product = np.dot(vector_u, vector_v)

# Visualize the vectors
plot_two_vectors(vector_u, vector_v)
plt.title('Vector Analysis: Checking Orthogonality')
plt.show()

print(f"Vector u: {vector_u}")
print(f"Vector v: {vector_v}")
print(f"Dot product: {dot_product}")
print(f"Angle relationship: {'Orthogonal (90°)' if dot_product == 0 else 'Not orthogonal'}")
Out[ ]:
array([1, 0, 3, 0, 5])

Exercise 5: Perfect orthogonal vectors

Testing the classic orthogonal case:

Convert the list [-1, 1] and [1, 1] to numpy arrays a and b. Then, plot the arrays as vectors using the fuction Plotvec2 and find the dot product:

Classic orthogonal vectors¶

unit_x = np.array([1, 0]) # Unit vector along x-axis unit_y = np.array([0, 1]) # Unit vector along y-axis

dot_result = np.dot(unit_x, unit_y)

plot_two_vectors(unit_x, unit_y) plt.title('Perfect Orthogonal Vectors: X and Y Axes') plt.show()

print(f"X-axis unit vector: {unit_x}") print(f"Y-axis unit vector: {unit_y}") print(f"Dot product: {dot_result}") print("These are perfectly orthogonal - the foundation of coordinate systems!")

In [ ]:
# Write your code below and press Shift+Enter to execute
# Write your code below and press Shift+Enter to execute
u = np.array([-1,1]) 
v = np.array([1,1])
Plotvec2(u, v)
print("The dot product is", np.dot(u,v))

---
The dot product is 0
No description has been provided for this image

Non-orthogonal vector analysis¶

vector_a = np.array([1, 1]) vector_b = np.array([0, 1])

dot_product_ab = np.dot(vector_a, vector_b) magnitude_a = np.linalg.norm(vector_a) magnitude_b = np.linalg.norm(vector_b) angle_radians = np.arccos(dot_product_ab / (magnitude_a * magnitude_b)) angle_degrees = np.degrees(angle_radians)

plot_two_vectors(vector_a, vector_b) plt.title(f'Non-Orthogonal Vectors: {angle_degrees:.1f}° Angle') plt.show()

print(f"Vector a: {vector_a}") print(f"Vector b: {vector_b}") print(f"Dot product: {dot_product_ab}") print(f"Angle between vectors: {angle_degrees:.1f}°") print(f"This demonstrates correlation in data - non-zero dot product!")

Convert the list [1, 0] and [0, 1] to numpy arrays a and b. Then, plot the arrays as vectors using the function Plotvec2 and find the dot product:


In [ ]:
# Write your code below and press Shift+Enter to execute
u = np.array([1,0]) 
v = np.array([0,1])
Plotvec2(u, v)
print("The dot product is", np.dot(u,v))

**Theoretical Insight:** Understanding Dot Product Patterns

Why do some vector pairs give zero dot products while others don't?
The dot product is 0
No description has been provided for this image


My Journey Summary and Next Steps¶

Convert the list [1, 1] and [0, 1] to numpy arrays a and b. Then plot the arrays as vectors using the fuction Plotvec2 and find the dot product:

My Key Takeaways from NumPy 1D Arrays {#conclusion}¶

This exploration of NumPy has reinforced why it's absolutely essential for my data science workflow. Here's what I've learned and applied:

Technical Mastery Achieved:¶

1. Array Fundamentals

  • Understanding homogeneous data types for performance
  • Efficient indexing and slicing techniques
  • Advanced indexing with boolean and integer arrays

2. Mathematical Operations

  • Vectorized operations that eliminate slow loops
  • Broadcasting for efficient scalar operations
  • Dot products for measuring vector relationships

3. Practical Applications

  • Statistical analysis with built-in functions
  • Data generation using linspace
  • Vector visualization for geometric understanding

Why This Matters for My Projects:¶

  • Performance: NumPy operations are 10-100x faster than pure Python
  • Memory Efficiency: Homogeneous arrays use less memory
  • Code Clarity: Vectorized operations are more readable and maintainable
  • Scientific Computing: Foundation for pandas, scikit-learn, and other libraries

My Next Learning Goals:¶

  1. 2D Arrays and Matrices: Expanding to higher dimensions
  2. Advanced Indexing: Boolean masking and fancy indexing patterns
  3. Linear Algebra: Matrix operations and decompositions
  4. Integration with Pandas: Seamless data analysis workflows
  5. Performance Optimization: Memory layout and computational efficiency

Personal Reflection¶

NumPy has transformed how I approach numerical computing. The elegant combination of mathematical rigor and computational efficiency makes it indispensable for serious data analysis. Every concept I've explored here forms the foundation for more advanced data science techniques.

This notebook represents my personal understanding and practical application of NumPy fundamentals. The journey from Python lists to NumPy arrays marks a crucial milestone in any data scientist's development.


About This Learning Journey

This comprehensive exploration reflects my hands-on experience with NumPy's core concepts. Each example and insight comes from real applications in data analysis projects.

© 2025 Mohammad Sayem Chowdhury. Shared for educational purposes and community learning.

In [67]:
# Write your code below and press Shift+Enter to execute
u = np.array([1,1]) 
v = np.array([0,1])
Plotvec2(u, v)
print("The dot product is", np.dot(u,v))
The dot product is 1
No description has been provided for this image

Why are the results of the dot product for [-1, 1] and [1, 1] and the dot product for [1, 0] and [0, 1] zero, but not zero for the dot product for [1, 1] and [0, 1]?

Hint: Study the corresponding figures, pay attention to the direction the arrows are pointing to.

The vectors used for question 4 and 5 are perpendicular. As a result, the dot product is zero


Copyright © 2018 IBM Developer Skills Network. This notebook and its source code are released under the terms of the MIT License.