⚙️ Element-wise Operations

Element-wise operations are the heart of NumPy's power! Instead of writing loops to process each element individually, NumPy applies operations to every element automatically. This includes not just basic arithmetic, but also complex mathematical functions, comparisons, and logical operations.

Understanding element-wise behavior is key to thinking "like NumPy" and writing efficient, readable code!

import numpy as np

# Element-wise operations demonstration
data = np.array([1, 4, 9, 16, 25])

print(f"Original: {data}")
print(f"Square root: {np.sqrt(data)}")
print(f"Logarithm: {np.log(data)}")
print(f"Sine: {np.sin(data)}")
print(f"Greater than 10: {data > 10}")

🔍 Understanding Element-wise Behavior

Every operation in NumPy applies to corresponding elements independently:

import numpy as np

# Element-wise behavior explanation
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])

print(f"Array a: {a}")
print(f"Array b: {b}")

# Element-wise operations
addition = a + b        # [10+1, 20+2, 30+3]
multiplication = a * b  # [10*1, 20*2, 30*3]
power = a ** b         # [10**1, 20**2, 30**3]

print(f"a + b: {addition}")
print(f"a * b: {multiplication}")
print(f"a ** b: {power}")

# Visual breakdown
print(f"\nElement-wise breakdown:")
for i in range(len(a)):
    print(f"  Position {i}: {a[i]} + {b[i]} = {a[i] + b[i]}")

📐 Mathematical Functions

NumPy provides a vast library of mathematical functions that work element-wise:

import numpy as np

# Mathematical functions examples
angles_deg = np.array([0, 30, 45, 60, 90])
print(f"Angles (degrees): {angles_deg}")

# Convert to radians and calculate trigonometric functions
angles_rad = np.radians(angles_deg)
sine_values = np.sin(angles_rad)
cosine_values = np.cos(angles_rad)

print(f"Radians: {angles_rad}")
print(f"Sine: {sine_values}")
print(f"Cosine: {cosine_values}")

# Exponential and logarithmic functions
numbers = np.array([1, 2, 4, 8, 16])
print(f"\nNumbers: {numbers}")
print(f"Square root: {np.sqrt(numbers)}")
print(f"Natural log: {np.log(numbers)}")
print(f"Base-10 log: {np.log10(numbers)}")
print(f"Exponential: {np.exp([1, 2, 3])}")

# Rounding functions
decimals = np.array([1.2, 2.7, 3.14159, -1.8])
print(f"\nDecimals: {decimals}")
print(f"Rounded: {np.round(decimals)}")
print(f"Floor: {np.floor(decimals)}")
print(f"Ceiling: {np.ceil(decimals)}")
print(f"Absolute: {np.abs(decimals)}")

🔍 Comparison Operations

Comparison operations return boolean arrays, enabling powerful data filtering:

import numpy as np

# Comparison operations
test_scores = np.array([85, 92, 78, 96, 89, 74, 88, 93])
print(f"Test scores: {test_scores}")

# Different comparison operations
high_scores = test_scores > 90
low_scores = test_scores < 80
passing_scores = test_scores >= 80
exact_match = test_scores == 85

print(f"High scores (>90): {high_scores}")
print(f"Low scores (<80): {low_scores}")
print(f"Passing (≥80): {passing_scores}")
print(f"Exactly 85: {exact_match}")

# Using boolean arrays for filtering
print(f"Students with high scores: {test_scores[high_scores]}")
print(f"Students with low scores: {test_scores[low_scores]}")

# Counting with boolean arrays
num_high = np.sum(high_scores)    # True = 1, False = 0
num_low = np.sum(low_scores)
pass_rate = np.mean(passing_scores) * 100

print(f"High performers: {num_high}")
print(f"Low performers: {num_low}")
print(f"Pass rate: {pass_rate:.1f}%")

🧠 Logical Operations

Logical operations combine boolean arrays and conditions:

import numpy as np

# Logical operations
ages = np.array([16, 22, 17, 30, 19, 25, 15, 28])
incomes = np.array([0, 35000, 8000, 55000, 15000, 45000, 0, 50000])

print(f"Ages: {ages}")
print(f"Incomes: {incomes}")

# Individual conditions
adults = ages >= 18
earners = incomes > 20000
students = (ages >= 16) & (ages <= 22)

print(f"Adults (≥18): {adults}")
print(f"Earners (>20k): {earners}")
print(f"Students (16-22): {students}")

# Combining conditions
working_adults = adults & earners
young_earners = (ages < 25) & (incomes > 30000)
dependents = ~adults  # NOT adults (minors)

print(f"Working adults: {working_adults}")
print(f"Young high earners: {young_earners}")
print(f"Dependents: {dependents}")

# Extract data using conditions
print(f"Working adult ages: {ages[working_adults]}")
print(f"Young earner incomes: {incomes[young_earners]}")

🎯 Conditional Operations

Use np.where() for conditional element-wise operations:

import numpy as np

# Conditional operations with np.where()
temperatures = np.array([18, 25, 32, 15, 28, 35, 22])
print(f"Temperatures (°C): {temperatures}")

# Simple conditional: "Hot" or "Cool"
weather = np.where(temperatures > 25, "Hot", "Cool")
print(f"Weather: {weather}")

# Numerical conditional operations
grades = np.array([85, 92, 78, 96, 74, 88, 93])
print(f"Grades: {grades}")

# Apply curve: +5 points if < 80, +2 points if ≥ 80
curved = np.where(grades < 80, grades + 5, grades + 2)
print(f"Curved grades: {curved}")

# Multiple conditions (nested where)
letter_grades = np.where(grades >= 90, "A",
                np.where(grades >= 80, "B",
                np.where(grades >= 70, "C",
                np.where(grades >= 60, "D", "F"))))
print(f"Letter grades: {letter_grades}")

# Conditional calculations
sales = np.array([1500, 2200, 800, 3500, 1200])
# Bonus: 10% if sales > 2000, 5% otherwise
bonus = np.where(sales > 2000, sales * 0.10, sales * 0.05)
print(f"Sales: {sales}")
print(f"Bonuses: {bonus}")

🔄 Chaining Operations

Element-wise operations can be chained together for complex calculations:

import numpy as np

# Chained operations example
print("📊 Data Processing Pipeline")
print("=" * 30)

# Raw sensor data (temperature readings)
raw_data = np.array([22.3, 23.8, 21.9, 24.5, 22.1, 25.2, 23.7])
print(f"Raw data: {raw_data}")

# Step 1: Remove outliers (> 2 standard deviations)
mean_temp = np.mean(raw_data)
std_temp = np.std(raw_data)
outlier_threshold = 2 * std_temp

print(f"Mean: {mean_temp:.2f}, Std: {std_temp:.2f}")

# Step 2: Create cleaned data
cleaned = np.where(
    np.abs(raw_data - mean_temp) > outlier_threshold,
    mean_temp,  # Replace outliers with mean
    raw_data    # Keep normal values
)
print(f"Cleaned: {cleaned}")

# Step 3: Normalize to 0-1 scale
min_val = np.min(cleaned)
max_val = np.max(cleaned)
normalized = (cleaned - min_val) / (max_val - min_val)
print(f"Normalized: {normalized}")

# Step 4: Apply calibration curve
calibrated = normalized * 100 + 50  # Scale to 50-150 range
print(f"Calibrated: {calibrated}")

# All steps in one line (advanced)
processed = ((np.where(np.abs(raw_data - np.mean(raw_data)) > 2*np.std(raw_data), 
                      np.mean(raw_data), raw_data) - np.min(raw_data)) / 
            (np.max(raw_data) - np.min(raw_data))) * 100 + 50
print(f"One-liner result: {processed}")

🧪 Scientific Computing Examples

Element-wise operations excel in scientific applications:

import numpy as np

print("🧪 Scientific Computing Examples")
print("=" * 32)

# Example 1: Physics - Projectile motion
print("🎯 Projectile Motion")
time = np.array([0, 0.5, 1.0, 1.5, 2.0])  # seconds
initial_velocity = 20  # m/s
gravity = 9.81  # m/s²

# Position equation: y = v₀t - ½gt²
height = initial_velocity * time - 0.5 * gravity * time**2
velocity = initial_velocity - gravity * time

print(f"Time: {time} s")
print(f"Height: {height} m")
print(f"Velocity: {velocity} m/s")

# Example 2: Chemistry - pH calculations
print(f"\n🧪 pH Calculations")
h_concentration = np.array([1e-3, 1e-7, 1e-11, 1e-2, 1e-9])
ph_values = -np.log10(h_concentration)

print(f"[H+] concentration: {h_concentration}")
print(f"pH values: {ph_values}")
print(f"Acidic (pH < 7): {ph_values < 7}")

# Example 3: Statistics - Z-scores
print(f"\n📊 Z-score Standardization")
test_scores = np.array([78, 85, 92, 88, 76, 94, 82])
mean_score = np.mean(test_scores)
std_score = np.std(test_scores)

z_scores = (test_scores - mean_score) / std_score
print(f"Test scores: {test_scores}")
print(f"Z-scores: {z_scores}")
print(f"Above average: {z_scores > 0}")

🎯 Key Takeaways

🚀 What's Next?

Excellent! You now understand how operations work on individual elements. Next, let's explore broadcasting - NumPy's powerful system for working with arrays of different shapes.

Continue to: Broadcasting Rules

Ready to master array compatibility! 📡✨

Was this helpful?

😔Poor
🙁Fair
😊Good
😄Great
🤩Excellent