Earlier in this week, we created only `1-dimensional`

Numpy arrays. But Pyhon can do a lot more, it can handle `high dimensional or multi dimensional`

arrays as well.

If we try to check the type of Numpy arrays that was created earlier, we would see that it's of type:

```
`numpy.ndarray`
```

`numpy.`

tells us, it was defined in the numpy package.`ndarray`

- stands for*n-dimensional*array.

To create an n-dimensional numpy array, (say) a two-dimensional array we follow this template:

`variable = np.arary( [ [elem1, elem2, ... , elem(n-j)], [elem1, elem2, ... , elem(n-k)] ] )`

```
In [19]:
```import numpy as np
# e.e. create a 2d array
np_2d = np.array([ [1, 2, 3, 4, 5, 6, 7 ],
[ 8, 9,10, 11, 12, 13, 14] ])
# print np_2d
print( np_2d )
print( type( np_2d ) )
"""
+ The output is of rectangualar data structure.
+ Each sublist ~ "row" in the 2D arary.
"""

```
Out[19]:
```

**Shape of n-dimensional array**

We can also look the type of structure our n-dimensional array object is, by calling the `shape`

on the array itself.

`< array_name > . shape`

`shape`

is a*attribute*which gives us more information about the structure of the data structure.

**Note: **

*All rules of numpy arrays also apply to multi-dimensional arrays as well.*

- i.e. an array can only contain a
*single type*.

If we change a (say) float elem to string,

*all array elements will be coerced to "strings"*.- i.e. we end up with the homogenous array!

- Can think of them as
*improved list-of-list*.

```
In [10]:
```# check the shape of the previously created numpy array
np_2d.shape

```
Out[10]:
```

**Subsetting on n-dimensional arrays**

As discussed earlier, Numpy n-dimensional arrays share all rules as that of Python array and some of it's own as well.

We can subset them as well, but this time it's a little bit different, here's how:

`N-dimensional_array_name[ < row index of desired elem > ] [ < coloumn index of desired elem > ]`

Alternative,

`N-dimensional_array_name[ < row index> , < col index > ]`

```
In [18]:
```# subset a row and coloumn
"""
+ Colon before comma specifies both rows.
+ Then follows the usual subsetting of any list.
+ Since we only wan't the 2nd and 3rd coloumn, hence
we put the indices 1 to 3.
- Remember, the 3rd index is not computed.
+ The "intersection" gives us two rows and colomns.
"""
print("Two rows and two coloumns: \n" + str(np_2d[:, 1:3]))
# Select a row completely
"""
Here's are n-dimensional array:
col: 0 1 2 3 4 5 6
^ ^ ^ ^ ^ ^ ^
[ [ 1 2 3 4 5 6 7 ] ----- row 0
[ 8 9 10 11 12 13 14 ] ] ----- row 1
i.e we want the whole 1st row 2( index 0 )
"""
print("\nThe 1st row at index 0 is: " + str( np_2d[ 0, :]) ) # second row and coloumns

```
```

**RQ1: ***What charaterizes multi-dimensional Numpy arrays?*

**Ans: **You can create a 2D Numpy array from a regular list of lists.

**RQ2: **You created the following 2D Numpy array, `x`

:

```
import numpy as np
x = np.array(["a", "b", "c", "d"],
["e", "f", "g", "h"] ] )
```

*Which Python command do you use to select the string "g" from x?*

**Ans: **`x[1, 2]`

**RQ3: ***What does the resulting array z contain after executing the following lines of Python code?*

```
import numpy as np
x = np.array([[1, 2, 3],
[1, 2, 3]])
y = np.array([[1, 1, 1],
[1, 2, 3]])
z = x - y
```

**Ans: **Since the arithematic operations on a two even on a 1D array is done element wise, same goes for ND arrays, i.e. rules are all the same.

```
import numpy as np
x = np.array([[1, 2, 3],
[1, 2, 3]])
y = np.array([[1, 1, 1],
[1, 2, 3]])
z = x - y
```

**Objective:**

Creating 2D arrays.

Perform some analyses on them.

- Your First 2D Numpy Arrays.

- Baseball data in 2D form.

- Subsetting 2D Numpy Arrays.

- 2D Arithematic

**1. Your First 2D Numpy Arrays -- 100xp, status: earned.**

Preface: Before working on the actual MLB data, let's try to create a 2D Numpy array from a small list of lists.

In this exercise, `baseball`

is a list of lists. The main list contains 4 elements. Each of these elements is a list containing the height and the weight of 4 `baseball`

players, in this order.

Instructions:

Use

`np.array()`

to create a 2D Numpy array from`baseball`

. Name it`np_baseball`

.Print out the type of np_baseball.

Print out the

`shape`

attribute of`np_baseball`

.- Use
`np_baseball.shape`

.

- Use

```
In [21]:
```# Create baseball, a list of lists
baseball = [[180, 78.4],
[215, 102.7],
[210, 98.5],
[188, 75.2]]
# Import numpy
import numpy as np
# Create a 2D Numpy array from baseball: np_baseball
np_baseball = np.array(baseball)
# Print out the type of np_baseball
print( type( np_baseball ) )
# Print out the shape of np_baseball
print( np_baseball. shape )

```
```

**2. Baseball data in 2D form**

Preface:

You have another look at the MLB data and realize that it makes more sense to restructure all this information in a 2D Numpy array. This array should have 1015 rows, corresponding to the 1015 baseball players you have information on, and 2 columns (for height and weight).

The MLB was, again, very helpful and passed you the data in a different structure, a Python list of lists. In this list of lists, each sublist represents the height and weight of a single baseball player. The name of this embedded list is baseball.

Store the data as a 2D array to unlock Numpy's extra functionality.

Instructions:

- Use
`np.array()`

to create a 2D Numpy array from`baseball`

. Name it`np_baseball`

.

- Print out the
`shape`

attribute of`np_baseball`

.

```
In [23]:
```# baseball is available as a regular list of lists
# Import numpy package
import numpy as np
# Create a 2D Numpy array from baseball: np_baseball
np_baseball = np.array( baseball )
# Print out the shape of np_baseball
print( np_baseball.shape )

```
```

**3. Subsetting 2D Numpy Arrays:**

Preface:

If your 2D Numpy array has a regular structure, i.e. each row and column has a fixed number of values, complicated ways of subsetting become very easy. Have a look at the code below where the elements "a" and "c" are extracted from a list of lists.

```
# regular list of lists
x = [["a", "b"], ["c", "d"]]
[x[0][0], x[1][0]]
# numpy
import numpy as np
np_x = np.array(x)
np_x[:,0]
```

Thus for 2D Numpy arrays:

- Indexes before the comma refer to rows.

- While those after the comma, refered to as coloumns.

- The
`:`

is for slicing.

Instructions:

- Print out the 50th row of np_baseball.

- Make a new variable,
`np_weight`

, containing the entire second column of`np_baseball`

.

- Select the height (first column) of the 124th baseball player in
`np_baseball`

and print it out.

```
In [ ]:
```# baseball is available as a regular list of lists
# Import numpy package
import numpy as np
# Create np_baseball (2 cols)
np_baseball = np.array(baseball)
# Print out the 50th row of np_baseball
#Ans: print( np_baseball[49,:])
# Select the entire second column of np_baseball: np_weight
#Ans: np_weight = np_baseball[1,:]
# Print out height of 124th player
#Ans: print( np_baseball[] )

**2D Arithematic**

Instructions:

You managed to get hold on the changes in weight, height and age of all baseball players. It is available as a 2D Numpy array, update.

- Add
`np_baseball`

and`update`

and print out the result.

- Add

You want to convert the units of height and weight.

- As a first step, create a numpy array with three values: 0.0254, 0.453592 and 1. Name this arary conversion.

- Multiply
`np_baseball`

with`conversion`

and print out the result.

```
In [25]:
```# baseball is available as a regular list of lists
# update is available as 2D Numpy array
# Import numpy package
import numpy as np
# Create np_baseball (3 cols)
np_baseball = np.array(baseball)
# Print out addition of np_baseball and update
# Ans : print( np_baseball + update)
# Create Numpy array: conversion
# Ans: conversion = np.array([0.0254, 0.453592, 1])
# Print out product of np_baseball and conversion
# Ans: print( np_baseball * conversion )