<jupyter_start><jupyter_text>**My Medium Article Link:** **https://towardsdatascience.com/numpy-the-king-of-scientific-computing-with-python-d1de680b811d?source=friends_link&sk=5de650b6beb5fc66ac5f7164c1eceac3** **Connect with me on:-****Linkedin:** [shubhanshu001](https://www.linkedin.com/in/shubhanshu001/) **Github:** [shubhanshu1995](https://github.com/shubhanshu1995) **Medium:** [@shubhanshu1995](https://medium.com/@shubhanshu1995) **Instagram:** [<NAME>](https://www.instagram.com/shubhanshu._.singh/) **Facebook:** [shubhanshu1995](https://www.facebook.com/shubhanshu1995) **Twitter:** [TheCuriousLad](https://twitter.com/TheCuriousLad)   **Let's use NumPy**<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>**NumPy Arrays**  **Let's create NumPy Arrays using python Lists**<jupyter_code>just_a_list = [1,2,3]
just_a_list
np.array(just_a_list)
just_a_matrix = [[1,2,3],[4,5,6],[7,8,9]]
just_a_matrix
np.array(just_a_matrix)<jupyter_output><empty_output><jupyter_text>**Built-in Methods**  **arange** **It returns evenly spaced values within a given interval.**<jupyter_code>np.arange(0,20)
np.arange(0,10,2)<jupyter_output><empty_output><jupyter_text>**Zeros and Ones** **Let's generate arrays of zeros or ones**<jupyter_code>np.zeros(4)
np.zeros((3,3))
np.ones(4)
np.ones((3,3))<jupyter_output><empty_output><jupyter_text>**linspace** **Return evenly spaced numbers over a specified interval.**<jupyter_code>np.linspace(0,10,3)
np.linspace(0,10,20)<jupyter_output><empty_output><jupyter_text>**eye**  **Creates an identity matrix**<jupyter_code>np.eye(3)<jupyter_output><empty_output><jupyter_text>**Random**Numpy also has lot of ways to create random number arrays:  **rand** **Create an array of the given shape and populate it with random samples from a uniform distribution over [0, 1).**<jupyter_code>np.random.rand(2)
np.random.rand(3,3)<jupyter_output><empty_output><jupyter_text>**randn** **Return a sample (or samples) from the "Standard Normal" or "Gaussian" distribution. Unlike rand which is uniform:**<jupyter_code>np.random.randn(2)
np.random.randn(4,4)<jupyter_output><empty_output><jupyter_text>**randint** **Return random integers from low (inclusive) to high (exclusive).**<jupyter_code>np.random.randint(1,100)
np.random.randint(1,100,10)<jupyter_output><empty_output><jupyter_text>**Array Attributes and Methods**  **Reshape****Returns an array containing the same data with a new shape.**<jupyter_code>arr = np.arange(16)
arr
arr.reshape(4,4)<jupyter_output><empty_output><jupyter_text>**max,min,argmax,argmin** **These are useful methods for finding max or min values. Or to find their index locations using argmin or argmax**<jupyter_code>random_arr = np.random.randint(0,50,10)
random_arr
random_arr.max()


random_arr.argmax()
random_arr.min()
random_arr.argmin()<jupyter_output><empty_output><jupyter_text>**Shape** **Shape is an attribute that arrays have (not a method):**<jupyter_code># Vector
arr.shape
# Notice the two sets of brackets
arr.reshape(1,16)
arr.reshape(1,16).shape
arr.reshape(16,1)
arr.reshape(16,1).shape<jupyter_output><empty_output><jupyter_text>**dtype** **You can also grab the data type of the object in the array:**<jupyter_code>arr.dtype<jupyter_output><empty_output><jupyter_text>**NumPy Indexing and Selection****Now we will learn how to select elements or group of elements from an array**  **The simplest way of picking up one or more elements from an array looks very similar to python lists**<jupyter_code>#Get a value at an index
arr[5]
#Get values in a range
arr[1:5]<jupyter_output><empty_output><jupyter_text>**Broadcasting** **Numpy arrays differ from a normal Python list because of their ability to broadcast:**<jupyter_code>#Setting a value with index range (Broadcasting)
arr[0:5]=100

#Show
arr
# Reset array, we'll see the reason behid it soon
arr = np.arange(0,11)

#Show
arr
slice_of_arr = arr[0:6]

#Show slice
slice_of_arr
#Change Slice
slice_of_arr[:]=99

#Show Slice again
slice_of_arr<jupyter_output><empty_output><jupyter_text>Now note the changes also occur in our original array!<jupyter_code>arr
#To get a copy, you need to be explicit
arr_copy = arr.copy()

arr_copy<jupyter_output><empty_output><jupyter_text>Let's see another example of broadcasting<jupyter_code>a = [[1,2,3],[4,5,6]]

#Converting to numpy 2d array
np_a = np.array(a)

#show
np_a
#2 rows, 3 columns
np_a.shape
b = [100,200,300]

# converting to numpy array
np_b = np.array(b)

#show
np_b
np_b.shape
np_b_reshaped = np_b.reshape(1,3)

#show
np_b_reshaped
# 1 row, 3 columns
np_b_reshaped.shape<jupyter_output><empty_output><jupyter_text>See the magic of broadcasting<jupyter_code>np_a + np_b_reshaped<jupyter_output><empty_output><jupyter_text>So basically np_b_reshaped replicates itself for the second row & it's shape becomes (2,3)<jupyter_code>np.array([[100,200,300],[100,200,300]])<jupyter_output><empty_output><jupyter_text>**Indexing a 2D array (matrices)****The general format is arr_2d[row][col] or arr_2d[row,col].**<jupyter_code>arr_2d = np.array(([1,2,3],[4,5,6],[7,8,9]))

#Show
arr_2d
#Indexing row
arr_2d[1]
# Format is arr_2d[row][col] or arr_2d[row,col]

# Getting individual element value
arr_2d[1][0]
# Getting individual element value
arr_2d[1,0]
# 2D array slicing

#Shape (2,2) from top right corner
arr_2d[:2,1:]
#Shape bottom row
arr_2d[2]
#Shape bottom row
arr_2d[2,:]<jupyter_output><empty_output><jupyter_text>**Selection****Let's briefly go over how to use brackets for selection based on comparison operators.**<jupyter_code>arr1 = np.arange(1,11)
arr1
arr1 > 5
bool_arr = arr1 > 5
bool_arr
arr1[bool_arr]
arr1[arr1 > 2]
x = 2
arr1[arr1 > x]<jupyter_output><empty_output><jupyter_text>**NumPy Operations** **Arithmetic** **You can easily perform array with array arithmetic, or scalar with array arithmetic. Let's see some examples:**<jupyter_code>arr2 = np.arange(0,10)
arr2 + arr2
arr2 * arr2
arr2 - arr2
# Warning on division by zero, but not an error!
# Just replaced with nan
arr2 / arr2
# Also warning, but not an error instead infinity
1 / arr2
arr2 ** 3<jupyter_output><empty_output><jupyter_text>**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:**<jupyter_code>#Taking Square Roots
np.sqrt(arr2)
#Calcualting exponential (e^)
np.exp(arr2)
np.max(arr2) #same as arr.max()
np.sin(arr2)
np.log(arr2)<jupyter_output>/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in log
  """Entry point for launching an IPython kernel.<jupyter_text>**Vectorization**<jupyter_code>import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

tic= time.time()
c = np.dot(a,b)
toc = time.time()

print("Time taken in vectorized version: "+str(1000 * (toc - tic) )+" ms")<jupyter_output>Time taken in vectorized version: 1.483917236328125 ms<jupyter_text>**For loop version**<jupyter_code>c = 0

tic = time.time()
for i in range(1000000):
  c += a[i] * b[i]  

toc = time.time()
print("Time taken in for loop version: "+str(1000 *(toc - tic)) + " ms")<jupyter_output>Time taken in for loop version: 579.4703960418701 ms<jupyter_text>**That's all folks !!**<jupyter_code><jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1403843532779065, 'fraction_numerical': 0.043478260869565216, 'mean_word_length': 7.4734411085450345, 'pattern_counts': {'":': 0, '<': 103, '<?xml version=': 0, '>': 107, 'https://': 7, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '97305', 'license': 'MIT', 'n_tokens_mistral': 2950, 'n_tokens_neox': 2745, 'n_words': 637, 'path': 'A_Comprehensive_Guide_to_NumPy.ipynb', 'repo_name': 'shubhanshu1995/My-Medium-Articles', 'size': '7347'}