Main content is currently provided solely as interactive live discussion.
We look at a few of more commonly used mathematical concepts in Data Science, such as vector spaces, probability & distributions, frequency domain, and differential calculus. Specifically, we look at those form the perspective of Data Science, and how they can be used in practice to and how we can think of them in a more intuitive way.
This notebook is primarily for running the visualizations and the exercises.
To keep track of the topics suggested for the discussion, in this notebook is also given this list of topics:
linear algebra (with DL in mind) - vector space:
vectors - linearity, basis, “good” basis, freedom of parametrization,
dot products - length and direction, mse
projection
matrices as list of vectors, mat mul, rotation
(O) basis change, pca
metric space - MSE
tensors
Interactive Demo¶
import numpy as np
import dash
from dash import dcc, html, Output, Input, State, ctx
import plotly.graph_objs as go
app = dash.Dash(__name__)
def vector_endpoint(angle_deg, length):
rad = np.deg2rad(angle_deg)
return length * np.cos(rad), length * np.sin(rad)
def create_figure(v1x, v1y, v2x, v2y):
limit = 4
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[0, v1x], y=[0, v1y],
mode='lines+markers', name='v1',
line=dict(color='red', width=4),
marker=dict(size=[0, 12], color='red')#, symbol='arrow-bar-up')
))
fig.add_trace(go.Scatter(
x=[0, v2x], y=[0, v2y],
mode='lines+markers', name='v2',
line=dict(color='blue', width=4),
marker=dict(size=[0, 12], color='blue')
))
fig.add_trace(go.Scatter(
x=[v2x, v1x+v2x], y=[v2y, v1y+v2y],
mode='lines+markers', name='v1 at v2',
line=dict(color='red', width=4),
marker=dict(size=[0, 12], color='red'),
opacity=0.2
))
fig.add_trace(go.Scatter(
x=[v1x, v1x+v2x], y=[v1y, v1y+v2y],
mode='lines+markers', name='v2 at v1',
line=dict(color='blue', width=4),
marker=dict(size=[0, 12], color='blue'),
opacity=0.2
))
fig.add_trace(go.Scatter(
x=[0, v1x+v2x], y=[0, v1y+v2y],
mode='lines+markers', name='v1 + v2',
line=dict(color='green', width=4),
marker=dict(size=[0, 12], color='green')
))
fig.update_layout(
width=600, height=600,
xaxis=dict(range=[-limit, limit], zeroline=True, constrain='domain'),
yaxis=dict(range=[-limit, limit], zeroline=True, scaleanchor='x', scaleratio=1),
#title=f"v1: angle {angle1}°, length {len1} | v2: angle {angle2}°, length {len2}",
margin=dict(l=0, r=0, t=40, b=0),
showlegend=True
)
return fig
def get_vector_controls(vec_id: str) -> html.Div:
div = html.Div([
html.Div([
f"{vec_id}",
], style={'width': '15%', 'height': '100%', 'display': 'flex',
'alignItems': 'center', 'verticalAlignItems': 'middle',
'textAlign': 'center', 'verticalTextAlign': 'middle',
'align': 'center', 'verticalAlign': 'middle',
#'fontWeight': 'bold',
'fontSize': '36px',
}),
html.Div([
html.Div([
"R (au): ",
html.Div([
dcc.Slider(id=f'sl_rt_r_{vec_id}', min=0, max=2, value=1, marks=None, tooltip={"placement": "bottom", "always_visible": True}),
], style={'width': '70%', 'display': 'inline-block'})
], style={'width': '90%', 'display': 'flex'}),
html.Div([
dcc.Markdown(children="""$$
\\Theta \\,(°):\\, $$
""", mathjax=True),
html.Div([
dcc.Slider(id=f'sl_rt_t_{vec_id}', min=0, max=360, step=1, value=90, marks=None, tooltip={"placement": "bottom", "always_visible": True}),
], style={'width': '70%', 'display': 'inline-block'})
], style={'width': '90%', 'display': 'flex'}),
], style={'width': '40%', 'display': 'inline-block'}),
html.Div([
html.Div([
"X (au): ",
html.Div([
dcc.Slider(id=f'sl_xy_x_{vec_id}', min=-2, max=2, value=0, marks=None, tooltip={"placement": "bottom", "always_visible": True}),
], style={'width': '70%', 'display': 'inline-block'})
], style={'width': '90%', 'display': 'flex'}),
html.Div([
"Y (au): ",
html.Div([
dcc.Slider(id=f'sl_xy_y_{vec_id}', min=-2, max=2, value=1, marks=None, tooltip={"placement": "bottom", "always_visible": True}),
], style={'width': '70%', 'display': 'inline-block'})
], style={'width': '90%', 'display': 'flex'}),
], style={'width': '40%', 'display': 'inline-block'}),
], style={'display': 'flex', 'justifyContent': 'space-between'})
return div
app.layout = html.Div([
html.Div([ dcc.Graph(id='vector-graph', figure=create_figure(0, 1, 0, 1)),
],
),
html.Div([
get_vector_controls(v_id) for v_id in ['v1', 'v2']
], style={'width': '50%', 'marginTop': '50px', 'marginBottom': '20px'})
], style={'width': '100%vw', 'height': '100%vh', 'display': 'flex', 'backgroundColor': 'white'}
)
def rt_to_xy(r, t):
"""Convert polar coordinates (r, t) to Cartesian coordinates (x, y)."""
angle_rad = np.deg2rad(t)
x = r * np.cos(angle_rad)
y = r * np.sin(angle_rad)
return x, y
def xy_to_rt(x, y):
"""Convert Cartesian coordinates (x, y) to polar coordinates (r, t)."""
r = np.sqrt(x**2 + y**2)
t = np.rad2deg(np.arctan2(y, x)) % 360 # Ensure angle is in [0, 360)
return r, t # Return angle first for consistency with RT sliders
@app.callback(
Output('sl_rt_r_v1', 'value'),
Output('sl_rt_t_v1', 'value'),
Output('sl_xy_x_v1', 'value'),
Output('sl_xy_y_v1', 'value'),
Output('vector-graph', 'figure', allow_duplicate=True),
Input('sl_rt_r_v1', 'value'),
Input('sl_rt_t_v1', 'value'),
Input('sl_xy_x_v1', 'value'),
Input('sl_xy_y_v1', 'value'),
State('sl_xy_x_v2', 'value'),
State('sl_xy_y_v2', 'value'),
prevent_initial_call=True
)
def update_all(r, t, x, y, x2, y2):
triggered = ctx.triggered_id
r_new, t_new, x_new, y_new = r, t, x, y
if triggered is not None:
if triggered.startswith('sl_rt_'):
# Update XY based on RT
x_new, y_new = rt_to_xy(r, t)
elif triggered.startswith('sl_xy_'):
# Update RT based on XY
r_new, t_new = xy_to_rt(x, y)
fig = create_figure(x_new, y_new, x2, y2)
return r_new, t_new, x_new, y_new, fig
@app.callback(
Output('sl_rt_r_v2', 'value'),
Output('sl_rt_t_v2', 'value'),
Output('sl_xy_x_v2', 'value'),
Output('sl_xy_y_v2', 'value'),
Output('vector-graph', 'figure', allow_duplicate=True),
Input('sl_rt_r_v2', 'value'),
Input('sl_rt_t_v2', 'value'),
Input('sl_xy_x_v2', 'value'),
Input('sl_xy_y_v2', 'value'),
State('sl_xy_x_v1', 'value'),
State('sl_xy_y_v1', 'value'),
prevent_initial_call=True
)
def update_all(r, t, x, y, x2, y2):
triggered = ctx.triggered_id
r_new, t_new, x_new, y_new = r, t, x, y
if triggered is not None:
if triggered.startswith('sl_rt_'):
# Update XY based on RT
x_new, y_new = rt_to_xy(r, t)
elif triggered.startswith('sl_xy_'):
# Update RT based on XY
r_new, t_new = xy_to_rt(x, y)
fig = create_figure(x_new, y_new, x2, y2)
return r_new, t_new, x_new, y_new, fig
app.run(debug=True)
Exercise:¶
Preparation
Calculate the projection of vector v3 onto vectors v1 and v2.
For any given vector v3, represent it in the basis of v1 and v2.
Basis vectors usually have norm 1. Do they have to have same norm? well, not really, but it is convenient. Same length - allows for meaningful comparison of vector magnitudes relative basis; Basis length 1 - allows for meaningful comparison of vector magnitudes relative to a defined unit length (e.g. 1. meter)
Affine transformation: using a matrix and vector, apply a transformation to v3.
Implement in code to play and gain intuition.
Get the summary of the code structure and understand it.
Implement the projection of v3 onto v1 and v2.
Implement the representation of v3 in the basis of v1 and v2.
Implement the affine transformation of v3 using a matrix and vector.