Python Data Science Essentials: A Comprehensive Guide to NumPy, PyTorch, and Scientific Computing

Python Fundamentals

Basic Data Types

Checking variable types:

data_type = type(variable)

String Operations

# String formatting examples
message = '{} {} {}'.format(greeting, target, number)
print(message)

# sprintf-style formatting
formatted = '%s %s %d' % (greeting, target, number)
print(formatted)

# String manipulation methods
text = "example"
print(text.capitalize())  # "Example"
print(text.upper())       # "EXAMPLE"
print(text.rjust(10))     # Right-justify with spaces
print(text.center(10))    # Center with spaces
print(text.replace('x', '(ecks)'))  # Replace substrings
print('  trimmed  '.strip())  # Remove whitespace

Containers

Lists

# List creation and manipulation
collection = [3, 1, 2]
collection.append('item')
removed_item = collection.pop()

# Generating sequences
numbers = list(range(10))  # [0, 1, 2, ..., 9]

Loops and List Comprehensions

# Enumerated loop
elements = ['apple', 'banana', 'cherry']
for index, item in enumerate(elements):
    print(f'#{index + 1}: {item}')

# List comprehension
values = [0, 1, 2, 3, 4, 5, 6]
squared_evens = [x ** 2 for x in values if x % 2 == 0]
print(squared_evens)  # [0, 4, 16, 36]

Dictionaries

# Dictionary operations
inventory = {'apple': 5, 'banana': 8, 'cherry': 12}
print(inventory['apple'])  # 5
print('apple' in inventory)  # True
inventory['orange'] = 7  # Add new item
print(inventory.get('pear', 'Not found'))  # Default value
del inventory['apple']  # Remove item

Dictionary Loops and Comprehensions

# Iterating through dictionaries
attributes = {'person': 2, 'dog': 4, 'spider': 8}
for creature, legs in attributes.items():
    print(f'A {creature} has {legs} legs')

# Dictionary comprehension
numbers = [0, 1, 2, 3, 4, 5]
even_squares = {x: x ** 2 for x in numbers if x % 2 == 0}
print(even_squares)  # {0: 0, 2: 4, 4: 16}

Sets

# Set operations
fruits = {'apple', 'banana'}
print('apple' in fruits)  # True
fruits.add('cherry')
fruits.add('apple')  # No duplicates
fruits.remove('banana')
print(len(fruits))  # 2

Set Comprehensions

import math
numbers = {int(math.sqrt(x)) for x in range(30)}
print(numbers)  # {0, 1, 2, 3, 4, 5}

Tuples

# Tuples as dictionary keys
coordinate_dict = {(x, x + 1): x for x in range(10)}
position = (5, 6)
print(coordinate_dict[position])  # 5

Classes

class Salutation:
    # Constructor
    def __init__(self, recipient):
        self.recipient = recipient
    
    # Instance method
    def greet(self, enthusiastic=False):
        if enthusiastic:
            print(f'HELLO, {self.recipient.upper()}!')
        else:
            print(f'Hello, {self.recipient}')

# Using the class
greeter = Salutation('Alice')
greeter.greet()  # "Hello, Alice"
greeter.greet(enthusiastic=True)  # "HELLO, ALICE!"

PyTorch Fundamentals

Setup and Configuration

import torch

# Check CUDA availability
has_cuda = torch.cuda.is_available()
print(f"CUDA available: {has_cuda}")

Tensor Operations

Creating Tensors

# Basic tensor creation
vector = torch.tensor([1, 2, 3], dtype=torch.int32)
matrix = torch.tensor([[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]], dtype=torch.float32)

# Tensor properties
print(f"Data type: {matrix.dtype}")
print(f"Dimensions: {matrix.ndim}")
print(f"Shape: {matrix.shape}")
print(f"Device: {matrix.device}")

Gneerating Data

# Special tensors
ones_matrix = torch.ones(3, 4)
zeros_matrix = torch.zeros(2, 5)

# Random tensors
random_uniform = torch.rand(3, 3)  # [0, 1)
random_integers = torch.randint(low=2, high=18, size=(3, 4))
random_normal = torch.randn(2, 4)  # Standard normal

# Creating tensors similar to existing ones
similar_tensor = torch.rand_like(random_normal, dtype=torch.float32)

# From NumPy
import numpy as np
numpy_array = np.array([1, 2, 3])
torch_tensor = torch.from_numpy(numpy_array)

Reshaping and Manipulating Tensors

# Reshaping
original = torch.rand(3, 4)
reshaped = original.reshape(2, 6)  # or original.view(2, 6)

# Flattening
flattened = original.flatten()
partially_flattened = original.flatten(start_dim=1, end_dim=2)

# Concatenation
tensor_a = torch.tensor([[1, 2], [3, 4]])
tensor_b = torch.tensor([[5, 6], [7, 8]])
concatenated = torch.cat([tensor_a, tensor_b], dim=0)

# Stacking
vector_a = torch.tensor([1, 2, 3])
vector_b = torch.tensor([4, 5, 6])
stacked = torch.stack([vector_a, vector_b], dim=0)

# Extracting values
element = tensor_a[1, 0].item()  # Gets Python scalar

Mathemtaical Operations

# Basic arithmetic
result1 = tensor_a + tensor_b
result2 = torch.add(tensor_a, tensor_b, out=result1)
tensor_a.add_(tensor_b)  # In-place operation

# Matrix multiplication
matrix_a = torch.rand(3, 4)
matrix_b = torch.rand(4, 5)
product1 = torch.matmul(matrix_a, matrix_b)
product2 = matrix_a @ matrix_b

# Statistical operations
values = torch.rand(4, 5)
total = torch.sum(values)
minimum = torch.min(values)
maximum = torch.max(values)
min_index = torch.argmin(values)
max_index = torch.argmax(values)
average = torch.mean(values)
median = torch.median(values)

# Common functions
data = torch.rand(2, 4) * 2 - 1
absolute = torch.abs(data)
ceiling = torch.ceil(data)
floor = torch.floor(data)
clamped = torch.clamp(data, -0.5, 0.5)

GPU Operations

# Moving tensors to GPU
if torch.cuda.is_available():
    device = torch.device("cuda")
    tensor = tensor.to(device)

Indexing

# Advanced indexing
indices = [1, 3, 5, 5]
selected = original[indices]

Automatic Differentiation

# Autograd example
inputs = torch.ones(5)
targets = torch.zeros(3)
weights = torch.randn(5, 3, requires_grad=True)
bias = torch.randn(3, requires_grad=True)

outputs = torch.matmul(inputs, weights) + bias
loss = torch.nn.functional.binary_cross_entropy_with_logits(outputs, targets)

loss.backward()
print(weights.grad)
print(bias.grad)

# Disabling gradient tracking
with torch.no_grad():
    outputs_no_grad = torch.matmul(inputs, weights) + bias
print(outputs_no_grad.requires_grad)  # False

NumPy Essentials

Array Creation

import numpy as np

# Basic arrays
vector = np.array([1, 2, 3])
print(f"Type: {type(vector)}")
print(f"Shape: {vector.shape}")

# Multi-dimensional arrays
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(f"Shape: {matrix.shape}")

# Special arrays
zeros = np.zeros((2, 3))
ones = np.ones((3, 4))
constant = np.full((2, 2), 7)
identity = np.eye(3)
random_values = np.random.random((2, 3))

Array Indexing

Slicing

# Create a sample array
data = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

# Extract subarray
subset = data[:2, 1:3]  # First 2 rows, columns 1 and 2

# Slices are views, not copies
print(data[0, 1])  # 2
subset[0, 0] = 77
print(data[0, 1])  # 77 (original array is modified)

Integer Array Indexing

# Integer indexing
elements = np.array([[1, 2], [3, 4], [5, 6]])
selected = elements[[0, 1, 2], [0, 1, 0]]  # [1, 4, 5]

# Advanced indexing with arange
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
indices = np.array([0, 2, 0, 1])
selected_elements = matrix[np.arange(4), indices]  # [1, 6, 7, 11]

# Modifying elements
matrix[np.arange(4), indices] += 10

Boolean Indexing

# Boolean indexing
data = np.array([[1, 2], [3, 4], [5, 6]])
mask = data > 2  # Boolean mask
print(data[mask])  # [3, 4, 5, 6]

# Direct boolean indexing
print(data[data > 2])  # [3, 4, 5, 6]

Array Mathematics

# Element-wise operations
x = np.array([[1, 2], [3, 4]], dtype=np.float64)
y = np.array([[5, 6], [7, 8]], dtype=np.float64)

# Basic arithmetic
sum_result = x + y  # or np.add(x, y)
difference = x - y  # or np.subtract(x, y)
product = x * y     # or np.multiply(x, y)
quotient = x / y    # or np.divide(x, y)
square_root = np.sqrt(x)

# Matrix multiplication
matrix_product = x.dot(y)  # or np.dot(x, y)

# Aggregation functions
total = np.sum(x)
column_sums = np.sum(x, axis=0)
row_sums = np.sum(x, axis=1)

# Transposition
transposed = x.T

Broadcasting

# Broadcasting example
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
vector = np.array([1, 0, 1])
result = matrix + vector  # Vector added to each row

# Alternative approaches without broadcasting
stacked_vector = np.tile(vector, (4, 1))  # Stack 4 copies
reshaped_vector = vector.reshape((3, 1))  # Reshape for broadcasting

# Pairwise addition of two 1D arrays
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
pairwise_sum = a.reshape(-1, 1) + b

SciPy Utilities

Image Operations

from scipy import misc
import matplotlib.pyplot as plt

# Read and process images
image = misc.imread('example.jpg')
print(f"Image type: {image.dtype}, shape: {image.shape}")

# Image manipulation
tinted_image = image * [1, 0.95, 0.9]  # Adjust color channels
resized_image = misc.imresize(tinted_image, (300, 300))

# Save the result
misc.imsave('processed_image.jpg', resized_image)

Distance Calculations

import numpy as np
from scipy.spatial.distance import pdist, squareform

# Create sample points
points = np.array([[0, 1], [1, 0], [2, 0]])

# Compute pairwise distances
distances = squareform(pdist(points, 'euclidean'))
print(distances)

Matplotlib Visualization

import numpy as np
import matplotlib.pyplot as plt
from scipy import misc

# Load and process images
original_image = misc.imread('example.jpg')
processed_image = original_image * [1, 0.95, 0.9]

# Create side-by-side comparison
plt.figure(figsize=(10, 5))

# Original image
plt.subplot(1, 2, 1)
plt.imshow(original_image)
plt.title('Original')

# Processed image
plt.subplot(1, 2, 2)
plt.imshow(np.uint8(processed_image))
plt.title('Processed')

plt.show()

Tags: python Numpy pytorch SciPy matplotlib

Posted on Mon, 31 Aug 2026 16:36:15 +0000 by KevMull