Numpy is also incredibly fast, as it has bindings to C libraries. First importing numpy as alias it as np to use np instead of numpy to make to code shorter.

```
import numpy as np
```

Lets create a two dimensional array. First we are creating two dimensional array then converting it to numpy array.

```
python_list = [[1,2,3],[4,5,6]]
numpy_arr = np.array(python_list)
print(python_list)
print("*" * 30)
print(numpy_arr)
```

See the difference between a general python list and numpy two dimensional array.

Now We are declaring numpy_arr to arr1 and arr2 to square of the arr1. We can perform any mathmatical operations between two numpy arrays like below.

```
arr1 = numpy_arr
arr2 = arr1*arr1
print(arr1)
print("*" * 30)
print(arr2)
print("*" * 30)
print(arr2-arr1)
print("*" * 30)
print(arr2/arr1)
print("*" * 30)
print(arr2-arr2)
```

```
arr1 = np.arange(20)#from 0 to 19
arr2 = np.arange(20,40)#from 20 to 39
arr3 = np.arange(20,40,3)#starting from 20 and increment by 3 ending at 39
print(arr1)
print(arr2)
print(arr3)
```

# Indexing¶

```
arr = np.arange(1,11)#creating a simple array
arr
```

```
arr[1]
```

## Lets print values 5 6 7¶

```
arr[4:7] # arr[row,column+1]
```

```
#Setting a value with index range (Broadcasting)
arr[0:5]=100
#Show
arr
```

```
# Reset array, we'll see why I had to reset in a moment
arr = np.arange(0,11)
#Show
arr
```

# Look carefully¶

```
#Important notes on Slices
slice_of_arr = arr[0:6]
#Show slice
slice_of_arr
```

```
#Change Slice
slice_of_arr[:]=99
#Show Slice again
slice_of_arr
```

Now note the changes also occur in our original array!

```
arr
```

Data is not copied, it’s a view of the original array! This avoids memory problems!

```
#To get a copy, need to be explicit
arr_copy = arr.copy()
arr_copy
```

```
```