Commit 0033a614 authored by Mirko Birbaumer's avatar Mirko Birbaumer
Browse files

Added output to notebooks

parent 0ac6d4aa
Pipeline #420287 passed with stage
in 38 seconds
......@@ -1871,7 +1871,7 @@
},
{
"cell_type": "code",
"execution_count": 283,
"execution_count": 5,
"metadata": {},
"outputs": [
{
......@@ -1907,7 +1907,7 @@
},
{
"cell_type": "code",
"execution_count": 296,
"execution_count": 6,
"metadata": {},
"outputs": [
{
......@@ -1973,26 +1973,26 @@
},
{
"cell_type": "code",
"execution_count": 298,
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.axis.YTick at 0x7f070290c250>,\n",
" <matplotlib.axis.YTick at 0x7f070290e810>,\n",
" <matplotlib.axis.YTick at 0x7f0703fc39d0>,\n",
" <matplotlib.axis.YTick at 0x7f07028fa710>,\n",
" <matplotlib.axis.YTick at 0x7f07028fa6d0>,\n",
" <matplotlib.axis.YTick at 0x7f07028e8350>,\n",
" <matplotlib.axis.YTick at 0x7f07028fadd0>,\n",
" <matplotlib.axis.YTick at 0x7f0702882150>,\n",
" <matplotlib.axis.YTick at 0x7f07028825d0>,\n",
" <matplotlib.axis.YTick at 0x7f0702882b90>,\n",
" <matplotlib.axis.YTick at 0x7f070288b110>]"
"[<matplotlib.axis.YTick at 0x7f096f2f5e50>,\n",
" <matplotlib.axis.YTick at 0x7f096f2f54d0>,\n",
" <matplotlib.axis.YTick at 0x7f097d868fd0>,\n",
" <matplotlib.axis.YTick at 0x7f096f26f310>,\n",
" <matplotlib.axis.YTick at 0x7f096f26f210>,\n",
" <matplotlib.axis.YTick at 0x7f096f26ff50>,\n",
" <matplotlib.axis.YTick at 0x7f096f2751d0>,\n",
" <matplotlib.axis.YTick at 0x7f096f2752d0>,\n",
" <matplotlib.axis.YTick at 0x7f096f275810>,\n",
" <matplotlib.axis.YTick at 0x7f096f27d3d0>,\n",
" <matplotlib.axis.YTick at 0x7f096f275410>]"
]
},
"execution_count": 298,
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
},
......@@ -2073,7 +2073,7 @@
},
{
"cell_type": "code",
"execution_count": 300,
"execution_count": 8,
"metadata": {},
"outputs": [
{
......@@ -2144,7 +2144,7 @@
},
{
"cell_type": "code",
"execution_count": 302,
"execution_count": 9,
"metadata": {},
"outputs": [
{
......@@ -2201,7 +2201,7 @@
},
{
"cell_type": "code",
"execution_count": 106,
"execution_count": 12,
"metadata": {},
"outputs": [
{
......@@ -2242,7 +2242,7 @@
},
{
"cell_type": "code",
"execution_count": 107,
"execution_count": 13,
"metadata": {},
"outputs": [
{
......@@ -2256,9 +2256,9 @@
"Max index: 2\n",
"\n",
"Use numpy to create a [3,3] dimension array with random number\n",
"[[0.55382541 0.36160037 0.68662274]\n",
" [0.35028249 0.09885074 0.38463975]\n",
" [0.10113939 0.74698869 0.02460112]]\n"
"[[0.48561168 0.60381055 0.21083223]\n",
" [0.13291895 0.83313963 0.32659584]\n",
" [0.797164 0.87792929 0.74653135]]\n"
]
}
],
......
%% Cell type:markdown id: tags:
# Solution to Problem 1
%% Cell type:code id: tags:
``` python
# Use the numpy library
import numpy as np
np.set_printoptions(precision=2)
######################################################
#
# MESSAGE TO STUDENTS:
#
# This file contains a solution to the coding quiz. Feel free
# to look at it when you are stuck, but try to solve the
# problem on your own first.
#
######################################################
def prepare_inputs(inputs):
# TODO: create a 2-dimensional ndarray from the given 1-dimensional list;
# assign it to input_array
input_array = np.array([inputs])
# TODO: find the minimum value in input_array and subtract that
# value from all the elements of input_array. Store the
# result in inputs_minus_min
# We can use NumPy's min function and element-wise division
inputs_minus_min = input_array - np.min(input_array)
# TODO: find the maximum value in inputs_minus_min and divide
# all of the values in inputs_minus_min by the maximum value.
# Store the results in inputs_div_max.
# We can use NumPy's max function and element-wise division
inputs_div_max = inputs_minus_min / np.max(inputs_minus_min)
return input_array, inputs_minus_min, inputs_div_max
def multiply_inputs(m1, m2):
# Check the shapes of the matrices m1 and m2.
# m1 and m2 will be ndarray objects.
#
# Return False if the shapes cannot be used for matrix
# multiplication. You may not use a transpose
if m1.shape[0] != m2.shape[1] and m1.shape[1] != m2.shape[0]:
return False
# Have not returned False, so calculate the matrix product
# of m1 and m2 and return it. Do not use a transpose,
# but you swap their order if necessary
if m1.shape[1] == m2.shape[0]:
return np.matmul(m1, m2)
else:
return np.matmul(m2, m1)
def find_mean(values):
# Return the average of the values in the given Python list
# NumPy has a lot of helpful methods like this.
return np.mean(values)
```
%% Cell type:code id: tags:
``` python
input_array, inputs_minus_min, inputs_div_max = prepare_inputs([-1,2,7])
print("Input as Array: {}".format(input_array))
print("Dimension of Input Array: {}".format(input_array.ndim))
print("Input minus min: {}".format(inputs_minus_min))
print("Input Array: {}".format(inputs_div_max))
print("Multiply 1:\n{}".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1],[2],[3],[4]]))))
print("Multiply 2:\n{}".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1],[2],[3]]))))
print("Multiply 3:\n{}".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1,2]]))))
print("Mean == {}".format(find_mean([1,3,4])))
```
%%%% Output: stream
Input as Array: [[-1 2 7]]
Dimension of Input Array: 2
Input minus min: [[0 3 8]]
Input Array: [[0. 0.38 1. ]]
Multiply 1:
False
Multiply 2:
[[14]
[32]]
Multiply 3:
[[ 9 12 15]]
Mean == 2.6666666666666665
%% Cell type:markdown id: tags:
# Solution to Problem 2 - Body Mass Index
%% Cell type:code id: tags:
``` python
# import numpy
import numpy as np
np.set_printoptions(precision=2)
def BMI(weight, length):
# Function returning the BMI of input vectors m and l
m = np.array(weight) # Create arrays from inputs
l = np.array(length)
# Calculate all BMI's simultaniously
BMI = np.divide(m, l**2)
# Or just
BMI = m/l**2
return BMI
m_example = [60, 72, 57, 90, 95, 72]
l_example = [1.75, 1.80, 1.65, 1.90, 1.74, 1.91]
print("The given weights and lengths result in BMI's: \n{}".format(BMI(m_example, l_example)))
```
%%%% Output: stream
The given weights and lengths result in BMI's:
[19.59 22.22 20.94 24.93 31.38 19.74]
%% Cell type:markdown id: tags:
# Solution to Problem 3 - Matrix Multiplication
We will apply a couple of transformations to manipulate the $x$ and $y$ coordinates of the following points which have three dimensional components of $x$, $y$ and ascii character index similar to the way an image pixel has 3 dimensional components of $x$, $y$, and frequency (or intensity).
$$
\begin{align}
a & = (0, 1, 0) \\
b & = (1, 0, 1) \\
c & = (0, -1, 2) \\
d & = (-1, 0, 3)
\end{align}
$$
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt
import numpy as np
import string
# points a, b and, c
a, b, c, d = (0, 1, 0), (1, 0, 1), (0, -1, 2), (-1, 0, 3)
# matrix with row vectors of points
A = np.array([a, b, c, d])
# 3x3 Identity transformation matrix
I = np.eye(3)
color_lut = 'rgbc'
fig = plt.figure()
ax = plt.gca()
xs = []
ys = []
for row in A:
output_row = np.matmul(I, row)
x, y, i = output_row
xs.append(x)
ys.append(y)
i = int(i) # convert float to int for indexing
c = color_lut[i]
plt.scatter(x, y, color=c)
plt.text(x + 0.15, y, f"{string.ascii_letters[i]}")
xs.append(xs[0])
ys.append(ys[0])
plt.plot(xs, ys, color="gray", linestyle='dotted')
ax.set_xticks(np.arange(-2.5, 3, 0.5))
ax.set_yticks(np.arange(-2.5, 3, 0.5))
plt.grid()
plt.show()
```
%%%% Output: display_data
![](data:image/png;base64,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)
%% Cell type:markdown id: tags:
(a) Rotate the points by 45 degrees, scale them by 1.5 and add the vector $v=(0.5, 0.5)$ to the product of these transformations.
%% Cell type:code id: tags:
``` python
# create the scaling transformation matrix
T_s = np.array([[1.5, 0, 0], [0, 1.5, 0], [0, 0, 1]])
T_r = np.array([[0.707, 0.707, 0], [-0.707, 0.707, 0], [0, 0, 1]])
v = np.array([0.5, 0.5, 0])
# create combined tranformation matrix
T = np.matmul(T_s, T_r)
fig = plt.figure()
ax = plt.gca()
xs_comb = []
ys_comb = []
for row in A:
output_row = np.matmul(T, row) + v.T
x, y, i = row
x_comb, y_comb, i_comb = output_row
xs_comb.append(x_comb)
ys_comb.append(y_comb)
i, i_comb = int(i), int(i_comb) # convert float to int for indexing
c, c_comb = color_lut[i], color_lut[i_comb] # these are the same but, its good to be explicit
letter, letter_comb = string.ascii_letters[i], string.ascii_letters[i_comb]
plt.scatter(x, y, color=c)
plt.scatter(x_comb, y_comb, color=c_comb)
plt.text(x + 0.15 , y, f"{letter}")
plt.text(x_comb + 0.15, y_comb, f"{letter_comb}'")
xs_comb.append(xs_comb[0])
ys_comb.append(ys_comb[0])
plt.plot(xs, ys, color="gray", linestyle='dotted')
plt.plot(xs_comb, ys_comb, color="gray", linestyle='dotted')
ax.set_xticks(np.arange(-2.5, 3, 0.5))
ax.set_yticks(np.arange(-2.5, 3, 0.5))
plt.grid()
plt.show()
```
%%%% Output: display_data
![](data:image/png;base64,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)
%% Cell type:markdown id: tags:
(b) Apply the relu function `x'=max(0,x)` to the 4 points after transformation as described in (a).
%% Cell type:code id: tags:
``` python
# create the scaling transformation matrix
T_s = np.array([[1.5, 0, 0], [0, 1.5, 0], [0, 0, 1]])
T_r = np.array([[0.707, 0.707, 0], [-0.707, 0.707, 0], [0, 0, 1]])
v = np.array([0.5, 0.5, 0])
# create combined tranformation matrix
T = np.matmul(T_s, T_r)
fig = plt.figure()
ax = plt.gca()
xs_comb = []
ys_comb = []
for row in A:
output_row = np.matmul(T, row) + v.T
x, y, i = row
x_comb, y_comb, i_comb = output_row
x_comb = max(0,x_comb)
y_comb = max(0,y_comb)
xs_comb.append(x_comb)
ys_comb.append(y_comb)
i, i_comb = int(i), int(i_comb) # convert float to int for indexing
c, c_comb = color_lut[i], color_lut[i_comb] # these are the same but, its good to be explicit
letter, letter_comb = string.ascii_letters[i], string.ascii_letters[i_comb]
plt.scatter(x, y, color=c)
plt.scatter(x_comb, y_comb, color=c_comb)
plt.text(x + 0.15 , y, f"{letter}")
plt.text(x_comb + 0.15, y_comb, f"{letter_comb}'")
xs_comb.append(xs_comb[0])
ys_comb.append(ys_comb[0])
plt.plot(xs, ys, color="gray", linestyle='dotted')
plt.plot(xs_comb, ys_comb, color="gray", linestyle='dotted')
ax.set_xticks(np.arange(-2.5, 3, 0.5))
ax.set_yticks(np.arange(-2.5, 3, 0.5))
plt.grid()
plt.show()
```
%%%% Output: display_data
![](data:image/png;base64,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)
%% Cell type:markdown id: tags:
# Solution to Problem 4 - Using Pandas: Weather
%% Cell type:code id: tags:
``` python
# First import Pandas
import pandas as pd
# load the database using pandas.read_csv
data = pd.read_csv("./data/weather.csv")
data
```
%%%% Output: execute_result
Luzern Basel Chur Zurich
Jan 2 5 -3 4
Feb 5 6 1 0
Mar 10 11 13 8
Apr 16 12 14 17
May 21 23 21 20
Jun 25 21 23 27
%% Cell type:markdown id: tags:
### Viewing Data using Indices:
%% Cell type:code id: tags:
``` python
t_basel = data["Basel"]
t_chur_feb = data.loc["Feb", "Chur"]
print("Temperature in Basel is:\n", t_basel, "\n")
print("Temperature in Chur in February is:\n", t_chur_feb)
```
%%%% Output: stream
Temperature in Basel is:
Jan 5
Feb 6
Mar 11
Apr 12
May 23
Jun 21
Name: Basel, dtype: int64
Temperature in Chur in February is:
1
%% Cell type:markdown id: tags:
### Changing Indices
%% Cell type:code id: tags:
``` python
# Find the name of column 3:
all_columns = data.columns
name_c3 = all_columns[3]
# Oder
name_c3 = data.columns.values[3]
print(name_c3)
# Change "Basel" to "Bern"
data.columns.values[1] = "Bern"
data
```
%%%% Output: stream
Zurich
%%%% Output: execute_result
Luzern Bern Chur Zurich
Jan 2 5 -3 4
Feb 5 6 1 0
Mar 10 11 13 8
Apr 16 12 14 17
May 21 23 21 20
Jun 25 21 23 27
%% Cell type:markdown id: tags:
### .mean() Method:
Now find :
- the average temperature in Chur (for the given Period)
- the average temperature in Spring in Switzerland (spring is Mar, Apr, May, mean of all cities)
%% Cell type:code id: tags:
``` python
t_chur_mean = data.loc[:, "Chur"].mean()
t_spring_mean = data.loc["Mar":"May", :].mean().mean()
# Hint: mean() on a DataFrame gives the result in a Serries. The axis of the function to be applied on can be set with axis={index (0), columns (1)}.
# To find the mean of the whole matrix, the mean method can be applied twice
print("Average temperature in Chur was: {}".format(t_chur_mean))
print("Average temperature in Spring was: {}".format(round(t_spring_mean, 1)))
```
%%%% Output: stream
Average temperature in Chur was: 11.5
Average temperature in Spring was: 15.5
%% Cell type:markdown id: tags:
### .sort_values() Method:
- Sort the data based on the temperature in Zürich
- Sort the data based on decreasing temperature in Basel
%% Cell type:code id: tags:
``` python
data.sort_values("Zurich")
```
%%%% Output: execute_result
Luzern Bern Chur Zurich
Feb 5 6 1 0
Jan 2 5 -3 4
Mar 10 11 13 8
Apr 16 12 14 17
May 21 23 21 20
Jun 25 21 23 27
%% Cell type:code id: tags:
``` python
data.sort_values("Basel", ascending=False)
```
%%%% Output: execute_result
Luzern Bern Chur Zurich
May 21 23 21 20
Jun 25 21 23 27
Apr 16 12 14 17
Mar 10 11 13 8
Feb 5 6 1 0
Jan 2 5 -3 4
%% Cell type:markdown id: tags:
# Solution to Problem 5: Fuel Consumption
%% Cell type:code id: tags:
``` python
# First import Pandas
import pandas as pd
# load the database using pandas.read_csv with options: sep="," and index_col=0
# data = None
data = pd.read_csv("./data/d.fuel.dat")
data
```
%%%% Output: execute_result
X weight mpg type
0 1 2560 33 Small
1 2 2345 33 Small
2 3 1845 37 Small
3 4 2260 32 Small
4 5 2440 32 Small
5 6 2285 26 Small
6 7 2275 33 Small
7 8 2350 28 Small
8 9 2295 25 Small