# Introduction to NumPy This post provides an introductionary documentation for getting started with NumPy in Python.

```# importing numpy into this python script
import numpy
# building some lists and adding them with Python base library
a = [1,2,3]
b = [1,2,3]
a+b
```
`[1, 2, 3, 1, 2, 3]`
```# declaring an array with numpy
a_np = numpy.array([1,2,3])
# checking the type fo the array to confirm it is a numpy array
type(a_np)
```
`numpy.ndarray`
```# numpy arrays have an attribute .dtype, allowing you to check the numpy data type of the array
a_np.dtype
```
`dtype('int32')`
```# a_np is of type integer; let try to assign a float
a_np = 13.33
a_np
```
`array([13,  2,  3])`
```# numpy arrays have a .ndim attribute, allowing you to see the number of dimensions of the array
a_np.ndim
```
`1`
```# numpy arrays also have a .size attribute;
# .size is allowing you to see the number of elements contained by the array
a_np.size
```
`3`
```# math becomes possible element-wise, when using numpy arrays
# -- creating a second numpy array to test some element-wise mathematical operations
b_np = numpy.array([2,3,4])
a_np + b_np
```
`array([11, -1, -1])`
```# subtraction
a_np - b_np
```
`array([11, -1, -1])`
```# multiplication
a_np * b_np
```
`array([26,  6, 12])`
```# one to the power of the other
a_np ** b_np
```
`array([169,   8,  81], dtype=int32)`
```# divison
a_np / b_np
```
`array([6.5       , 0.66666667, 0.75      ])`
```# modulo; testing a_np modulo 2
a_np % numpy.array([2,2,2])
```
`array([1, 0, 1], dtype=int32)`
```# modulo; testing b_np modulo 2
b_np % numpy.array([2,2,2])
```
`array([0, 1, 0], dtype=int32)`
```# numpy allows for using "universal functions";
# universal functions work element-wise, with numpy arrays
# one example is .sin
numpy.sin(a_np)
```
`array([0.42016704, 0.90929743, 0.14112001])`
```# another example is .sqrt
numpy.sqrt(a_np)
```
`array([3.60555128, 1.41421356, 1.73205081])`
```# building a 2D data table using numpy
c_np = numpy.array([[1,2,3],
[4,5,6]])
c_np
```
```array([[1, 2, 3],
[4, 5, 6]])```
```# indexing, i.e. obtaining the value stored in a defined cell;
# here: cell in first row, first colum
c_np
```
`1`
```# here: cell in last row, last colum
c_np[-1][-1]
```
`6`
```# here: cell in second row, first column
c_np
```
`4`
```# an alternative way of doing the above
c_np[1,0]
```
`4`
```# slicing through simple 1d numpy array
# here: get second and third value in d_np
d_np = numpy.array([7,9,11])
d_np[1:3]
```
`array([ 9, 11])`
```# get first and third element
d_np[0:3:2] # from:to:step
```
`array([ 7, 11])`
```# here: getting every other element in d_np
d_np[::2]
```
`array([ 7, 11])`
```# here: getting every third element
d_np[::3]
```
`array()`
```# we can create a 1D array using .arange, a method from the numpy module
e_np = numpy.arange(0,26) #param1: from; param2: to (last value excluded)
e_np
```
```array([ 0,  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])```
```# let's check the type of e_np
type(e_np)
```
`numpy.ndarray`
```# numpy arrays can be re-shaped, using the numpy .reshape method
f_np = e_np.reshape(2,13) #param1: number of rows; param2: number of columns
f_np
```
```array([[ 0,  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]])```
```# I can use .reshape not just for creating 2D out of 1D;
# e.g. see this
g_np = numpy.array([1,2,3,4,5,6,7,8,9,10,11,12]).reshape(3,2,2)
g_np
```
```array([[[ 1,  2],
[ 3,  4]],

[[ 5,  6],
[ 7,  8]],

[[ 9, 10],
[11, 12]]])```
```# g_np is nor 3D; let slice some dimensions out of this data cube
# all values in first directions of second dimension
g_np[:,0,:]
```
```array([[ 1,  2],
[ 5,  6],
[ 9, 10]])```
```# one specific cell; first in all dimensions
g_np[0,0,0]
```
`1`
```# one specific cell; last in all dimensions
g_np[-1,-1,-1]
```
`12`
```# one specific cell; SECOND last in all dimensions
g_np[-2,-2,-2]
```
`5`
```# let's complete this first tutorial on numpy with another example;
# I create a 2d array and show it to you
example = numpy.array([[1,2,3,4,5],
[1.1,2.2,3.3,4.4,5.5],
[1.11,2.22,3.33,4.44,5.55],
[1.111,2.222,3.333,4.444,5.555],
[1.1111,2.2222,3.3333,4.4444,5.5555]])
example
```
```array([[1.    , 2.    , 3.    , 4.    , 5.    ],
[1.1   , 2.2   , 3.3   , 4.4   , 5.5   ],
[1.11  , 2.22  , 3.33  , 4.44  , 5.55  ],
[1.111 , 2.222 , 3.333 , 4.444 , 5.555 ],
[1.1111, 2.2222, 3.3333, 4.4444, 5.5555]])```
```# now lets access the values 2.2, 4.4, 2.222, and 4.444 - in just one line of code
example[1::2,1::2]
```
```array([[2.2  , 4.4  ],
[2.222, 4.444]])```
```# now some examples what happens when you
# do copying by reference
a_np = numpy.array([1,2,3])
b_np = a_np[:1]
b_np
```
`array()`
```# changing b_np element
b_np = 10000
b_np
```
`array()`
```# let's npw check a_np
a_np
```
`array([10000,     2,     3])`
```# above is the effect of copying by reference;
# this happens when we slice through numpy arrays;
# does it happen with standard python list?
a = [1,2,3]
b = a[:1]
b = 1000
a
```
`[1, 2, 3]`
```# copying by reference does not happen when slicing default lists in pyhton;
# if we do not want to copy by reference then we can use .copy() method, as part of numpy
c_np = numpy.array([1,2,3,4,5])
d_np = c_np.copy()
d_np = 10000
c_np = 99999
# let's check c_np now
print("this is c_np:" + str(c_np))
```
```this is c_np:[99999     2     3     4     5]
```
```# what about d_np?
d_np
```
`array([10000,     2,     3,     4,     5])`
`# copying with .copy() allows to work with two objects, with independent references; `