```import numpy as np
```

```a = np.array([[10, 9],
[8, 3]])

print("array a:")
print(a)

print("\nMaximum value of a:")

print("\nMinimum value of a:")

print("\nReturn an array of the max in each column of a:")
print(a.max(axis=0))

print("\nReturn an array of the min in each row of a:")
print(a.min(axis=1))

print("\nReturn a, sorted within each column:")
b = np.copy(a)
b.sort(axis=0)
print(b)

# note: a.sort(axis=0) is enough, so why did I add
# b = np.copy(a) ? Because when you sort in numpy,
# it CHANGES the object permanently, and I wanted to leave
# a unchanged for the next question
#
# try this: change the solution above to just  a.sort(axis=0)
# and rerun this whole cell block. then look at your answer
# to the next question... it will be different! (it's a row sort
# after a column sort)

print("\nReturn a, sorted within each row:")
a.sort(axis=1)
print(a)
```
```array a:
[[10  9]
[ 8  3]]

Maximum value of a:
10

Minimum value of a:
3

Return an array of the max in each column of a:
[10  9]

Return an array of the min in each row of a:
[9 3]

Return a, sorted within each column:
[[ 8  3]
[10  9]]

Return a, sorted within each row:
[[ 9 10]
[ 3  8]]
```
```b = np.arange(40).reshape((20,2))
print("array b:")
print(b)

print("\nPrint elements of the first column of b above that column's 80th percentile:")
p80 = np.percentile(b[:,0],80)
print(b[   b[:,0]>p80   , 0])
#b[:,0]>p80 finds the rows of b where the first columns value is above p80
#b[ that, 0] prints the firms column

print("\nCovariance matrix of the columns of b:")
print(np.cov(b.T))
```
```array b:
[[ 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]
[26 27]
[28 29]
[30 31]
[32 33]
[34 35]
[36 37]
[38 39]]

Print elements of the first column of b above that column's 80th percentile:
[32 34 36 38]

Covariance matrix of the columns of b:
[[140. 140.]
[140. 140.]]
```