<jupyter_start><jupyter_text>Linear Algebra  Vectors<jupyter_code>from typing import List

Vector = List[float] 

height_weight_age = [
    70, # inches
    180, # pounds
    40, # years
]


def add_vectors(v: Vector, w: Vector) -> Vector:
    """Adds corresponding elements"""
    assert len(v) == len(w), "Vectors must have same length"
    
    return [v_i + w_i for v_i, w_i in zip(v, w)]

assert add_vectors([1, 2, 3], [4, 5, 6]) == [5, 7, 9]

def substract_vectors(v: Vector, w: Vector) -> Vector:
    """Substracts corresponding elements"""
    assert len(v) == len(w), "Vectors must have same length"
    
    return [v_i - w_i for v_i, w_i in zip(v, w)]

assert substract_vectors([5, 7, 9], [4, 5, 6]) == [1, 2, 3]

def vector_sum(vectors: List[Vector]) -> Vector:
    """Sums all corresponding elements"""
    # check vectors not empty
    assert vectors, "no vectors provided"
    
    # check vectors are all the same size
    num_elements = len(vectors[0])
    assert all(len(v) == num_elements for v in vectors), "different sizes"
    
    return [sum(vector[i] for vector in vectors)
               for i in range(num_elements)]

assert vector_sum([[1, 2], [3, 4], [5, 6], [7, 8]]) == [16, 20]

def scalar_multiply(c: float, v: Vector) -> Vector:
    """Multiplies every element with c"""
    return [c * v_i for v_i in v]

assert scalar_multiply(2, [1, 2 ,3]) == [2, 4, 6]

def vector_mean(vectors: List[Vector]) -> Vector:
    """Computes the element-wise average"""
    n = len(vectors)
    return scalar_multiply(1/n, vector_sum(vectors))

assert vector_mean([[1, 2], [3, 4], [5, 6]]) == [3, 4]

def dot(v: Vector, w: Vector) -> float:
    """Computes v_1 * w_1 + ... + v_n * w_n"""
    assert len(v) == len(w), "vectors must be same length"
    
    return sum(v_i * w_i for v_i, w_i in zip(v, w))

assert dot([1, 2, 3], [4, 5, 6]) == 32 # 1 * 4 + 2 * 5 + 3 * 6

def sum_of_squares(v: Vector) -> float:
    """Returns v_1 * v_1 + ... + v_n * v_n"""
    
    return dot(v, v)

import math

def magnitude(v: Vector) -> float:
    """Returns the magnitude (or length) of v"""

    return math.sqrt(sum_of_squares(v)) # math.sqrt is square root function

assert magnitude([3, 4]) == 5

def squared_distance(v: Vector, w: Vector) -> float:
    """Computes (v_1 - w_1) ** 2 + ... + (v_n - w_n) ** 2"""
    return sum_of_squares(subtract(v, w))

def distance(v: Vector, w: Vector) -> float:
    """Computes the distance between v and w"""
    return math.sqrt(squared_distance(v, w))
    # magnitude(substract(v, w))<jupyter_output><empty_output><jupyter_text>Matrices<jupyter_code>Matrix = List[List[float]]

A = [
    [1, 2, 3],
    [4, 5, 6]
] # 2 rows, 3 columns

B = [
    [1, 2],
    [3, 4],
    [5, 6]
] # 3 rows, 2 columns

from typing import Tuple

def shape(A: Matrix) -> Tuple[int, int]:
    """Returns (# of rows of A, # of columns of A)"""
    
    num_rows = len(A)
    num_cols = len(A[0]) if A else 0 # number of elements in first row
    
    return num_rows, num_cols
    
assert shape([
    [1, 2, 3],
    [4, 5, 6]
]) == (2, 3)

def get_row(A: Matrix, i: int) -> Vector:
    """Returns the i-th row of A (as a Vector)"""
    return A[i]

def get_column(A: Matrix, j: int) -> Vector:
    """Returns the j-th col of A (as a Vector)"""
    return [A_i[j] for A_i in A]

from typing import Callable

def make_matrix(
    num_rows: int, 
    num_cols: int, 
    entry_fn: Callable[[int, int], float]
) -> Matrix:
    """
    Returns a num_rows x num_cols matrix
    whose(i, j)-th entry is entry_fn(i, j)
    """
    return [
        [entry_fn(i, j) for j in range(num_cols)] for i in range(num_rows)
    ]

def identity_matix(n: int) -> Matrix:
    """Returns the n x n identity matrix"""
    return make_matrix(n, n, lambda i, j: 1 if i == j else 0)

assert identity_matix(5) == [
    [1, 0, 0, 0, 0],
    [0, 1, 0, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 0, 1, 0],
    [0, 0, 0, 0, 1],
]

# instance (row) = [weight_kg, height_cm, age]
data = [
    [70, 170, 40],
    [65, 120, 26],
    [77, 250, 19]
]

# n x k matrix can be used to represent a linear function that maps k-dimensional vectors to n-dimensional vectors

# represent binary relationships
friendships = [(0, 1), (0, 2), (1, 2), (1, 3)]

# user 0, 1, 2, 3
friend_matrix = [
    [0, 1, 1, 0], # user 0
    [1, 0, 1, 1], # user 1
    [1, 1, 0, 0], # user 2
    [1, 0, 0, 0], # user 3
]

# check for friends
assert friend_matrix[0][1] == 1 # user 0 and user 1 are friends
assert friend_matrix[0][3] == 0 # user 0 and user 3 are not friends

# find all friends
friends_of_1 = [i for i, is_friend in enumerate(friend_matrix[1]) if is_friend == 1]
assert friends_of_1 == [0, 2, 3]

friends_of_0 = [i for i, is_friend in enumerate(friend_matrix[0]) if is_friend == 1]
assert friends_of_0 == [1, 2]<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16247662580511116, 'fraction_numerical': 0.043424059837938914, 'mean_word_length': 3.0796610169491525, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '170009', 'license': 'MIT', 'n_tokens_mistral': 2007, 'n_tokens_neox': 1842, 'n_words': 629, 'path': 'data_science_from_scratch/004_linear_algebra.ipynb', 'repo_name': 'AndonisPavlidis/portfolio', 'size': '4813'}