DEV Community

Cover image for NumPy Ninja: Unleashing the Power of Python for Data Wizards
amiogithub
amiogithub

Posted on

NumPy Ninja: Unleashing the Power of Python for Data Wizards

Introduction to NUMPY

WHAT IS NUMPY?

Image description

NumPy is like a superhero for numbers in the world of programming. It stands for "Numerical Python." It's a library, which is like a set of tools or special powers that make it easy to work with numbers in the Python programming language.

Why use NumPy?

?

Imagine you have a big box of Lego bricks. Each brick represents a number or a piece of data. NumPy is like a magic glove that helps you organize, manipulate, and play with those Lego bricks in really efficient ways. It's super fast and makes your life easier when dealing with lots of numbers.

Numpy

Importance of NumPy in Data Science:

  • Speed: NumPy is super fast because it's written in a language called C, which is like the Flash of programming languages.
  • Efficiency: NumPy uses smart techniques to handle large datasets without making your computer feel like it's lifting a mountain.
  • Math Magic: Data science involves a lot of math, and NumPy has tons of functions that make mathematical operations easy, like adding, multiplying, or even doing fancy calculus stuff.
  • Compatibility: Many other data science tools and libraries in Python are like friends that understand NumPy's language, so they work well together.

How impactful is NumPy?

NumPy is like the secret sauce in the recipe of data science. Without it, things would be much harder and slower. It's used everywhere, from simple calculations to training complex machine learning models.

How easy is it to use?

Numpy works like a magic

Imagine you have a magic wand. You say a spell "Expecto Patronum"(or write a line of code), and NumPy does what you want. It's designed to be user-friendly, with simple functions that do powerful things. With a bit of practice, you'll find yourself saying, "Wow, that was easy!"

What becomes impossible without NumPy?

Without NumPy, working with large sets of data would be like trying to build a massive Lego castle without the special glove. It would take forever, and you might even give up because it's just too hard. NumPy makes the impossible possible in the world of data science!

*Let's dive into a simple example to see how NumPy helps a data scientist. *

# Without NumPy
math_grades = [90, 85, 88, 92, 78]
physics_grades = [88, 80, 85, 90, 82]

Enter fullscreen mode Exit fullscreen mode

Lets see what happens without using Numpy

# Without NumPy
num_students = len(math_grades)
total_math_grades = sum(math_grades)
total_physics_grades = sum(physics_grades)

average_math_grade = total_math_grades / num_students
average_physics_grade = total_physics_grades / num_students

class_average = (average_math_grade + average_physics_grade) / 2

print("Class Average (Without NumPy):", class_average)

Enter fullscreen mode Exit fullscreen mode

Now see what happens when you use Numpy




import numpy as np

# With NumPy
math_grades = np.array([90, 85, 88, 92, 78])
physics_grades = np.array([88, 80, 85, 90, 82])

average_math_grade = np.mean(math_grades)
average_physics_grade = np.mean(physics_grades)

class_average = np.mean([average_math_grade, average_physics_grade])

print("Class Average (With NumPy):", class_average)

Enter fullscreen mode Exit fullscreen mode

So, now we all have a basic understanding of why we will use Numpy right? So lets get started!

Firstly we will learn about Numpy arrays. In python, we are familiar with Lists right? Array is also another datatype which is present in other languages too like C++,JAVA etc.

There can be many dimensions like 2D,3D,4D etc.

Numpy arrays can be represented in Vectors slash matrices.

Now lets create an array:

np.arrange(0,10,1)
Enter fullscreen mode Exit fullscreen mode

here arrange function is used to create a numpy array. The syntax will be np.arrange(start,stop,step). It gives an array of length 10 starting from 0 to 9 and the difference between two consecutive numbers will be the step size that is 1.

But there are other ways to create an array too.

np.zeros(3) #returns a 1D array of length 3 with all zero elements
np.zeros((5,5))# returns a 2d array of 5 rows and 5 columns
np.zeros((2,3)) 
np.ones((3,4)) # all the elements will be one

Enter fullscreen mode Exit fullscreen mode

Imagine you have a toy train, and you want it to travel smoothly from one end of your play table to the other. Now, you don't want it to move too fast or too slow – you want it to make exactly 5 stops along the way.

np.linspace is like your magical train conductor tool in the world of Python and NumPy. It helps you create a list of numbers (like train stops) that are evenly spaced, making your train (or calculations) run smoothly.

Here's how you would use np.linspace:

import numpy as np

# Let's say you want your train to start at 0 and end at 10, making 5 stops.
train_stops = np.linspace(0, 10, 5)

print(train_stops)

Enter fullscreen mode Exit fullscreen mode

Tips
How do you simply understand the dimension of an array by seeing it? Look at the brackets. If there is 1 bracket that means the array is 1D array and so on.

Identity matrix:

Identity matrix is a 2D square matrix where number of rows is equal to the number of columns. The elements in primary diagonals will be 1

np.eye(4)  # identity matrix of 4*4 
Enter fullscreen mode Exit fullscreen mode

You can also generate random numbers through numpy libraries with the help of an array. How cool is that ?

  • np.random.rand()

This function gives you random numbers between 0 and 1, like picking candies from a jar where each candy is a number.

import numpy as np

random_numbers = np.random.rand(3)
print("Random Numbers between 0 and 1:", random_numbers)

Enter fullscreen mode Exit fullscreen mode
  • np.random.randint() It's like a magical dice roll. This function gives you random integers within a specified range.
random_integer = np.random.randint(1, 7)  # Imagine a 6-sided die
print("Random Integer:", random_integer)

Enter fullscreen mode Exit fullscreen mode
  • np.random.randn() This one is like a mysterious recipe that gives you numbers with a mean of 0 and standard deviation of 1. It's like a magic potion, creating numbers with a special pattern.
random_standard_numbers = np.random.randn(3)
print("Random Standard Numbers:", random_standard_numbers)

Enter fullscreen mode Exit fullscreen mode
  • np.random.choice() Imagine you have a bag of marbles with numbers on them. This function lets you randomly pick one or more marbles from the bag.
marbles = np.array([1, 2, 3, 4, 5])
random_pick = np.random.choice(marbles, size=2)
print("Randomly Picked Marbles:", random_pick)

Enter fullscreen mode Exit fullscreen mode
  • np.random.shuffle() It's like shuffling a deck of cards. This function rearranges the order of your numbers randomly.
deck_of_cards = np.array([1, 2, 3, 4, 5])
np.random.shuffle(deck_of_cards)
print("Shuffled Deck of Cards:", deck_of_cards)

Enter fullscreen mode Exit fullscreen mode

num

Remember, these functions are like magic spells for generating randomness in Python with NumPy. They make working with random numbers fun and easy!

RESHAPE

Alright, imagine you have a bunch of building blocks, and you want to rearrange them to make a new shape, like turning a flat square into a tall tower. The reshape function in NumPy is like your magical building block organizer. It helps you change the arrangement of your numbers or data without adding or removing any.

Here's how you might use it:

import numpy as np

# Imagine you have a flat square of building blocks (numbers 1 to 9)
flat_square = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])

# Now, you want to reshape it into a 3x3 grid, like making a tower with 3 floors and 3 blocks on each floor.
tower = flat_square.reshape(3, 3)

print("Original Flat Square:")
print(flat_square)

print("\nReshaped Tower:")
print(tower)

Enter fullscreen mode Exit fullscreen mode

The reshape function is like telling your magical organizer, "Hey, take these building blocks and arrange them in a way that there are 3 rows and 3 columns." And poof! Your flat square turns into a tower with three floors, each having three blocks.

It's super handy when you want to change the shape of your data without changing the actual data. It's like playing with LEGO blocks and transforming them into different cool structures!

Caution: Suppose you have an linear array of 25 elements and now you reshape the array into 2D arrays. okay that's fine. simply write new_arr=arr.reshape(5,5). here number of rows times number of column will be 25 which is equivalent to your previous array element number. but if you give (6 times 5) or anything that is greater than 25 it will throw an error due to insufficiency of elements.

Let's talk about the max, min, and index-related functions in NumPy, as if we're building with LEGO blocks.

np.max() and np.min()
Imagine you have a stack of LEGO towers, each tower representing a set of numbers. Now, you want to find the tallest tower (max) and the shortest tower (min).

import numpy as np

towers = np.array([[2, 5, 8],
                   [3, 9, 1],
                   [7, 4, 6]])

# Finding the tallest tower (max)
tallest_tower = np.max(towers)
print("Tallest Tower:", tallest_tower)

# Finding the shortest tower (min)
shortest_tower = np.min(towers)
print("Shortest Tower:", shortest_tower)

Enter fullscreen mode Exit fullscreen mode

It's like looking at your LEGO towers and saying, "Hey, tell me the height of the tallest one and the smallest one." The np.max() and np.min() functions do just that.

Index-Related Functions
Now, imagine each LEGO tower has numbered floors, and you want to know on which floor is the tallest and the shortest block. NumPy has functions for that too!


# Finding the index of the tallest block
index_of_tallest = np.argmax(towers)
print("Index of Tallest Block:", index_of_tallest)

# Finding the index of the shortest block
index_of_shortest = np.argmin(towers)
print("Index of Shortest Block:", index_of_shortest)
Enter fullscreen mode Exit fullscreen mode

Here, it's like saying, "Okay, I found the tallest and shortest towers. Now, tell me on which floor the tallest and the shortest blocks are." The np.argmax() and np.argmin() functions give you the indices (or positions) of the maximum and minimum values in your LEGO towers.

In summary, these functions are your LEGO tower inspectors. They help you find the tallest and shortest towers and tell you on which floor the special blocks are located!

Alright, let's dive into the concepts of checking the shape and datatype of your NumPy arrays, imagining we're playing with toys.

np.shape
Think of your NumPy array as a toy box with different toys inside. The np.shape function is like asking, "How many rows and columns does my toy box have?"

import numpy as np

# Imagine your toy box is a 2x3 grid of toys.
toy_box = np.array([[1, 2, 3],
                    [4, 5, 6]])

# Checking the shape of the toy box
shape_of_toy_box = np.shape(toy_box)

print("Shape of Toy Box:", shape_of_toy_box)

Shape of Toy Box: (2, 3)
It's like saying, "My toy box has 2 rows and 3 columns of toys
Enter fullscreen mode Exit fullscreen mode

np.dtype
Now, let's talk about the type of toys in your box. The np.dtype function is like asking, "What kind of toys are in my toy box?"

# Checking the datatype of the toys in the toy box
datatype_of_toys = toy_box.dtype

print("Datatype of Toys in Toy Box:", datatype_of_toys)
Datatype of Toys in Toy Box: int64

Enter fullscreen mode Exit fullscreen mode

Alright, let's embark on a magical journey in the world of Harry Potter using NumPy!

code

The Magical Quidditch Match

Imagine there's a magical Quidditch match happening in the wizarding world. The Quidditch field is represented as a grid, and each cell in the grid corresponds to a magical creature's power level. We want to create a team of wizards and magical creatures to ensure a fair match.

Step 1: Create the Quidditch Field

import numpy as np

# The Quidditch field is a 5x5 grid
quidditch_field = np.zeros((5, 5))
Enter fullscreen mode Exit fullscreen mode

Here, we've created a magical field using np.zeros(). Each cell is initialized to zero, symbolizing the absence of magical creatures

Step 2: Summon Magical Creatures

# Let's summon magical creatures with random power levels (between 1 and 10)
magical_creatures = np.random.randint(1, 11, size=(5, 5))

Enter fullscreen mode Exit fullscreen mode

Now, we have a team of magical creatures with random power levels generated by np.random.randint().

Step 3: Assign Creatures to the Quidditch Field

# Assign magical creatures to the Quidditch field
quidditch_field = np.maximum(quidditch_field, magical_creatures)

Enter fullscreen mode Exit fullscreen mode

We use np.maximum() to ensure that if there's already a magical creature in a cell, we don't replace it with a weaker one.

Step 4: Check the Team's Power

Find the total power of the magical creatures in each row

row_powers = np.sum(quidditch_field, axis=1)

Find the most powerful row

most_powerful_row_index = np.argmax(row_powers)
most_powerful_row_power = np.max(row_powers)

Here, we use np.sum() and np.argmax() to find the row with the most powerful magical creatures.

Step 5: Shape and Datatype Check

Check the shape and datatype of the Quidditch field

field_shape = np.shape(quidditch_field)
field_datatype = quidditch_field.dtype

Summary
In this magical scenario, we created a Quidditch field, summoned magical creatures, assigned them to the field, found the most powerful row, and checked the shape and datatype of our magical world.

Remember, in the wizarding world of NumPy, the arrays are your magical tools, and the functions are your spells!

Alright, let's imagine you have a magical spell book called NumPy, and it helps you find and modify elements in your magical array using square brackets – just like casting spells!

Finding Elements with Bracket Indexing

import numpy as np

# Imagine you have a magical array with numbers
magical_array = np.array([1, 2, 3, 4, 5])

# Let's use bracket indexing to find the second element (remember, we start counting from 0!)
second_element = magical_array[1]

print("Second Element:", second_element)
Second Element: 2

Enter fullscreen mode Exit fullscreen mode

Slicing with Bracket Indexing

# Now, let's use bracket indexing to get a slice of our magical array
slice_of_array = magical_array[1:4]

print("Slice of Array:", slice_of_array)
Slice of Array: [2 3 4]

Enter fullscreen mode Exit fullscreen mode

Modifying Elements with Bracket Indexing

Caution: If we try to modify the existing array in numpy, due to memory efficiency, the previous array memory gets lost. so in order to modify multiply or specific elements, we have to create a copy array so both of the arrays remain stored.


Broadcasting :Numpy arrays differ from a normal Python list because of their ability to broadcast

Enter fullscreen mode Exit fullscreen mode

Setting a value with index range (Broadcasting)

arr[0:5]=100

Show

arr




arr=np.random.randint(1,100,10)
arr_copy=arr.copy()
print(arr)


Output: array([66,  4,  1, 40, 97, 12, 97, 39, 88, 84])
Enter fullscreen mode Exit fullscreen mode
print(arr_copy[:]=100)

Output: array([100, 100, 100, 100, 100, 100, 100, 100, 100, 100])
Enter fullscreen mode Exit fullscreen mode
print(arr)

Output: array([66,  4,  1, 40, 97, 12, 97, 39, 88, 84])
Enter fullscreen mode Exit fullscreen mode

2D Array Indexing

# Imagine you have a magical 2D array
magical_2d_array = np.array([[1, 2, 3],
                             [4, 5, 6],
                             [7, 8, 9]])

# Let's use bracket indexing to find an element in this 2D array
element_in_2d_array = magical_2d_array[1, 2]

print("Element in 2D Array:", element_in_2d_array)
Element in 2D Array: 6

Enter fullscreen mode Exit fullscreen mode

bracket indexing is like having a magical wand that helps you point to specific elements or ranges in your arrays, and you can even use it to modify them!

# 2D array slicing

a=np.random.randint(1,100,50)
a=a.reshape(10,5)
a[4:7,1:4]

print(a)

Output:[[10, 56, 43],
       [ 5, 45, 99],
       [75, 95, 53]]
Enter fullscreen mode Exit fullscreen mode

here it means, these are row column representations. 4:7 means from row 4 to row 6, we slice the array and from column 1 to column 3 we slice the array. the elements within this range will show as output.

Sure thing! Let's explore arithmetic operations in NumPy, imagining we're playing with magical numbers.

NumPy Operations

import numpy as np
arr = np.arange(0,10)  [0,1,2,3,4,5,6,7,8,9]

print(arr+arr)  #[ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18]
print(arr*arr)  #[ 0,  1,  4,  9, 16, 25, 36, 49, 64, 81]
print(arr-arr)  #[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
print(arr**3)   #[ 0,   1,   8,  27,  64, 125, 216, 343, 512, 729]


Enter fullscreen mode Exit fullscreen mode

But for division there is a caution. in maths, when we divide something by zero we get infinity(error). in python also we get an error. On the bright side, numpy will not throw you an error. rather, it will show the output as a null value and throw you a warning instead. for some negative value divided by zero we will get negative infinity in output with a warning for free.

print(arr/arr) 

Output: [ nan,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.]


print(1/arr)

Output: [ inf,  1. ,  0.5,  0.33333333,  0.25 ,0.2 , 0.16666667,  0.14285714,  0.125,  0.11111111]
Enter fullscreen mode Exit fullscreen mode

Universal Array Functions
Numpy comes with many universal array functions, which are essentially just mathematical operations you can use to perform the operation across the array. Let's show some common ones:

#Taking Square Roots
np.sqrt(arr)
print(arr)

[ 0.  ,  1. ,  1.41421356,  1.73205081,  2. ,2.23606798,  2.44948974,  2.64575131,  2.82842712,  3.]

Enter fullscreen mode Exit fullscreen mode
#Calcualting exponential (e^)
np.exp(arr)

#LOg
np.log(arr)
Enter fullscreen mode Exit fullscreen mode

Numpy Exercises

Now that we've learned about NumPy let's test your knowledge. We'll start off with a few simple tasks, and then you'll be asked some more complicated questions.

import numpy as np

Create an array of 10 zeros


arr=np.zeros(10,'int')
arr
Enter fullscreen mode Exit fullscreen mode

Create an array of 10 ones

arr=np.ones(10,'int')
arr
Enter fullscreen mode Exit fullscreen mode

**
Create an array of 10 fives**

arr=np.full(5,10)
arr
Enter fullscreen mode Exit fullscreen mode

Create an array of all the even integers from 10 to 50

arr=np.arange(10,51,2)
arr
Enter fullscreen mode Exit fullscreen mode

Create a 3x3 matrix with values ranging from 0 to 8

arr=np.arange(0,9).reshape(3,3)
arr
Enter fullscreen mode Exit fullscreen mode
**Create a 3x3 identity matrix**
arr
arr=np.eye(3)
arr
Enter fullscreen mode Exit fullscreen mode

***Use NumPy to generate a random number between 0 and 1*

np.random.rand(1)
Enter fullscreen mode Exit fullscreen mode

Use NumPy to generate an array of 25 random numbers sampled from a standard normal distribution

np.random.randn(25)
Enter fullscreen mode Exit fullscreen mode

Create an array of 20 linearly spaced points between 0 and 1

np.linspace(0,1,20)
Enter fullscreen mode Exit fullscreen mode

**
Numpy Indexing and Selection**

array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25]])


mat[2:5,1:5]

array([[12, 13, 14, 15],
       [17, 18, 19, 20],
       [22, 23, 24, 25]])
Enter fullscreen mode Exit fullscreen mode

**
Get the sum of all the values in mat**

np.sum(mat)
mat.sum()
Enter fullscreen mode Exit fullscreen mode

Get the standard deviation of the values in mat

np.std(mat)
Enter fullscreen mode Exit fullscreen mode

Get the sum of all the columns in mat

mat.sum(axis=0)
Enter fullscreen mode Exit fullscreen mode

Summary: The NumPy Adventure

In the enchanted land of Python, there exists a magical library called NumPy. It's like a spell book that empowers wizards (programmers) to perform incredible feats with arrays and numbers. As we embarked on this NumPy adventure, we uncovered some of its most powerful spells:

Creating Arrays:

np.array(): Conjuring arrays from thin air.
np.arange(): Crafting sequences of numbers.
np.zeros() and np.ones(): Summoning arrays filled with mystical zeros and ones.
np.linspace(): Unveiling evenly spaced numbers.
np.identity(): Creating magical identity matrices.
Random Number Magic:

np.random.randint(): Rolling the dice for random integers.
np.random.randn(): Brewing a potion of random standard normal numbers.
np.random.choice(): Drawing numbers from a magical bag.
np.random.shuffle(): Shuffling the deck of numbers.
Enter fullscreen mode Exit fullscreen mode
Shape Transformation:

reshape(): Rearranging the layout of magical elements.
Exploring and Analyzing:

np.max() and np.min(): Finding the tallest towers and smallest caves.
np.argmax() and np.argmin(): Locating the peaks and valleys in the mystical landscape.
np.shape(): Revealing the dimensions of the magic grid.
dtype: Uncovering the type of magical essence within.
Fancy Indexing:

Using arrays of indices to precisely pick out or modify elements.
Magical Arithmetic:

Enter fullscreen mode Exit fullscreen mode

_Conjuring spells like addition, subtraction, multiplication, and division on arrays.
Our journey through the NumPy realm has equipped us with mighty tools and incantations. Armed with this knowledge, you can now weave your own spells and perform powerful transformations on arrays in Python. May your NumPy adventures continue, and may your code be as magical as the wizarding world itself! 🧙✨
_

Sayoonara~~
Good night!
Signing off tata!

end

Top comments (0)