CodeLab
145 subscribers
538 photos
20 videos
159 links
Говорим просто о сложном

Обсуждение, новости, материал и сплетни — все здесь https://t.me/CodeLabMLChat
Download Telegram
Soon 👨‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
2
👨‍💻Всем привет, продолжаем прошлый пост:

3⃣ Дальше нужно найти b (у нас уже найден k):

🟰 y = kx + b 🟰

🟰 b = y - kx 🟰

🟰 b = 6 - (-9/13 * (-5) = 6 - 45/13 = (78-45)/13 = 33/13 🟰 — берем любую точку и подставляем координаты, мы взяли точку (-5, 6)

🟰 y = 33/13 - 9/13*x 🟰 — получаем уравнение и умножаем | * 13

🟰 w = [-33, 9, 13] 🟰— отсюда получаем коэффициенты

4⃣ Вектор весов:

w = np.array([-33, 9, 13]) # [свободный член, вес при x1, вес при x2]


5⃣ Далее функция. тут надо внимательно: она считает точку с помощью формулы и относит к классу -1 ромбов (если результат < 0) или к квадратам +1 (если результат >= 0)

a_sign = lambda x, w: -1 if np.dot(x, w) < 0 else 1


6⃣ Добавим единицу к каждой точке из 🟰x_test🟰

x_test_new = np.array([[1, x1, x2] for x1, x2 in x_test])


🔵Поскольку у нас есть w₀, нам нужна была единица, например:

🔵Было (5, -3) ➡️ стало (1, 5, -3)

7⃣ Теперь для каждый точки (у них уже стоит единица, если что) применяем функцию 🟰a_sign🟰 и по итогу получаем список предсказаний (у нас может быть либо -1, либо 1), то есть, на выходе получаем список предсказаний 🟰 [-1, 1, 1, -1, 1, -1, -1]🟰

predict = [a_sign(x, w) for x in x_test_new]


💤 Подумаю, как можно усовершенствовать код с помощью библиотек, всем пака
Please open Telegram to view this post
VIEW IN TELEGRAM
321
🪷🔤🔤🔤🔤🌷🔤🔤 🌹🔤🔤🌹🔤🔤🔤🔤🔤🔤

👨‍💻 Итак, немного отойдем от Бинарной Классификации и вычислений векторов, тут, тут и даже тут мы уже рассматривали что-то подобное.

0⃣⚙️ Начнем с того, что логистическая регрессия — это не регрессия вовсе. Да, звучит сомнительно, но это алгоритм классификации. То есть, моделька логистической регрессии будет предсказывать вероятность принадлежности объекта к одному из двух классов (мы подобной темкой занимались в последних постах).

1⃣🛍 Если вы хорошо вспомните, мы как то рассматривали базовую нейронку, которая угадывала пол по входным признакам, Алгоритм отчасти похож:

🧑‍💻‼️ Для понимания, представьте обычную линейную комбинацию признаков:

🔵z = w₁ * x₁ + w₂ * x₂ + b

🧑‍💻 Далее, мы прогоняем нашу линейную зависимость через сигмоиду:

🔵σ(z) = 1 / 1 + e⁻ ᶻ

🧑‍💻 Считаем функцию потерь (НО НЕ MSE, мы бы использовали логарифмическую функцию потерь, так как MSE, MAE это для регрессий).

🧑‍💻 Далее обновляем веса с помощью любимого градиентного спуска и минимизируем Loss

Почему именно сигмоида? Как минимум, она переводит число в диапазон (0, 1)


2⃣ Начнем с кода, завтра продолжим:

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix
Please open Telegram to view this post
VIEW IN TELEGRAM
521
542
👨‍💻Йоу воссап друзья, продолжаем писать пост

📰 В прошлом посте (он тут кстати), мы импортировали вот эту библиотеку:

from sklearn.datasets import load_breast_cancer


3⃣⚙️ Так вот, загружаем наш датасет по диагностике рака груди:

data = load_breast_cancer() 
# Функцмя возвращает Bunch объект (типа словаря). Этот объект содержит data.data — признаки (массив NumPy), data.target — метки (0 или 1), data.feature_names — названия признаков (столбцов)


4⃣🛍 Создадим таблицу X из фичей (как раз тут используем pandas)

X = pd.DataFrame(data.data, columns = data.feature_names)
y = pd.Series(data.target)


🧑‍💻 Мы преобразуем массив data.data в объект DataFrame.

🧑‍💻 В columns мы задаем названия столбцов соответствующе признакам

🧑‍💻 Что касаемо второй строки, мы преобразуем data.target в объект Series, который представляет собой одномерный массив меток классов

📊 На данном этапе мы имеем X и y:

🔵 X — это таблица признаков (вида n × m, здесь n — количество образцов, m — количество признаков)

🔵y — вектор меток классов (n)

5⃣📊 Разделяем данные на обучающую и тестовую выборки:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = 1)


🧑‍💻 Функция train_test_split случайным образом разделяет данные на две части (тестовая 20% и обучающая 80%). ⚙️ Кароч, если возьмем X, то эта таблица делится на 2 части (X_train, X_test).

6⃣📊 Мы в прошлом посте импортировали StandardScaler. Мало ли данные разнятся, вот и применим масштабирование, а именно Z-core. У нас был огромный разбор аж двух видов нормализации, все есть на канале!

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)


🧑‍💻 Первая строка это просто объект стандартизации

🧑‍💻 fit_transform(X_train) — Вычисляем среднее (μ) и стандартное отклонение (σ) для каждого признака на обучающих данных. В общем, мы трансформируем и обучаем scaler и применяем его к X_train данные

🧑‍💻 transform(X_test) — А здесь мы просто применяем трансформацию к scaler и применяем к X_test данным. Почему не fit? Потому что наши тестовые данные должны быть независимыми от тренировочных данных. Тем более, scaler уже обучен (на обучающих данных), и он применяет ту же формулу Z-score

Картиночку скоро повторим 💤
Please open Telegram to view this post
VIEW IN TELEGRAM
5431
822
👨‍💻 Всем ку! Продолжаем разбирать 📈 логистическую регрессию. Намутил для вас классный дизайн для поста, а вот кстати прошлый пост

7⃣📊 Мы остановились на стандартизации (создали объект 🟰Z-score🟰 и обучили + применили стандартизацию).

⚙️ Теперь создадим модель логистической регрессии:

model = LogisticRegression(max_iter = 1000)


🛍 По умолчанию стоит L2 регуляризация, а max_iter отвечает за число итераций для градиентного спуска. (Про регуляризацию мы поговорим попозже, тоже очень важная тема).

👨‍💻 Вам нужно понимать одно: регуляризация штука интересная, нужна для 'защиты от переобучения модельки', и ,грубо говоря, она 'штрафует большие веса модели' — это все про L2, еще есть L1 (но обо всем потом)


📊8⃣ Обучаем модель:

model.fit(X_train_scaled, y_train)


📉Кароч ну тут мы по сути ищем такие веса (w), чтобы минимизировать 🟰log loss🟰 (это метрика для логистической регрессии) предсказаниями и 🟰y_train🟰

🧑‍💻 Чтобы вам понять, что делает model.fit():

🔵Получает X_train_scaled и y_train (наши обучающие данные и соответствующие метки, предсказания)

🔵Начинает с рандомных весов w

🔵Делает предсказания ŷ (вероятности через функцию сигмоиды)

🔵Сравнивает их с 🟰y_train🟰 с помощью 🟰log loss🟰

🔵Считает ошибку (loss)

🔵Обновляет веса, чтобы ошибка стала меньше

🔵Повторяет это до сходимости (или до max_iter)

➡️0⃣ Получаем предсказания y_pred:

y_pred = model.predict(X_test_scaled) #выдаст 0 или 1


1⃣0⃣ Выводим метрики качества:

print("Classification Report:\n", classification_report(y_test, y_pred))


🧑‍💻 classification_report — это функция для оценки эффективности алгоритмов классификации (в нем сразу содержится несколько + метрик качества) — тут тоже нужен отдельный пост, на выводе покажу что получится.

print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))


🧑‍💻 Выдает матрицу ошибок (показывает, где модель ошиблась, а где угадала )

🧑‍💻 Вот такой получится вывод для двух функций сверху

precision recall f1-score support

0 0.98 0.95 0.96 43
1 0.97 0.99 0.98 71

accuracy 0.97 114
macro avg 0.97 0.97 0.97 114
weighted avg 0.97 0.97 0.97 114


⚙️ Остается визуал:

sns.heatmap(confusion_matrix(y_test, y_pred), annot=True, fmt='d', cmap='Blues')
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.title("Confusion Matrix")
plt.show()


🧑‍💻 sns.heatmap(confusion_matrix...)как раз отвечает за цветную таблицу в выводе (в прошлом посте я ее кидал, в этом будет в комментах). В функцию мы передали матрицу ошибок.

🧑‍💻 annot = True аргумент вписывает числа внутрь ячеек.

Что мы видим на графике

🔵 41 — модель правильно предсказала класс 0 (у пациента рак)

🔵 70 — правильно предсказала класс 1 (у пациента рака нет)

🔵 1, 2 это ошибки модели в каждой из 2 ситуаций
Please open Telegram to view this post
VIEW IN TELEGRAM
5221
🧑‍💻 Сегодня крутецкий пост
Please open Telegram to view this post
VIEW IN TELEGRAM
722
👨‍💻 Йоу, воссап друзья, предлагаю продолжить бинарную классификацию, тем более, вы ничего не можете предложить.

import numpy as np

x_test = [(5, -3), (-3, 8), (3, 6), (0,0), (5, 3), (-3, -1), (-3, 3)]

w = np.array([-33, 9, 13])
a_sign = lambda x, w: -1 if np.dot(x, w) < 0 else 1
x_test_new = np.array([[1, x1, x2] for x1, x2 in x_test])
predict = [a_sign(x, w) for x in x_test_new]


⚙️ Мы разобрали код выше ТУТ и ТУТ, теперь можно попробовать его улучшить.

📇 Напоминаю, нам нужно было найти вектор параметров w 🟰w = [w₀, w₁, w₂]🟰 для разделяющей линии в соответствии с выражением: 🟰w * x₁ + w₂ * x₂ + w₀ = 0 🟰

📊 В прошлом посте ТУТ мы нашли этот самый вектор параметров 🟰 w = [-33, 9, 13] 🟰и получили такое уравнение прямой: 🟰9 * x₁ +13 * x₂ − 33 = 0🟰

📊 Но, но, помимо вектора параметров нам также нужно было сформировать список 🟰predict из значений меток {-1, +1}🟰 (поскольку у нас как раз 2 класса — C₁ = +1, C₂ = -1). То есть, если

wᵀ * x ≥ 0
📐 +1

wᵀ * x < 0
📐 -1

🧠 Эти самые метки мы искали по формуле 🟰 a(x) = sign(wᵀ * x) 🟰, здесь x = [1, x₁, x₂] — вектор признаков (координат) объекта выборки, дополненный первой единицей для параметра w₀.

📈 Короче, чтобы вам было проще, давайте на примере:

Мы уже имеем метки по ТЗ:

x_test = [(5, -3), (-3, 8), (3, 6), (0, 0), (5, 3), (-3, -1), (-3, 3)]


🟰 x = [1, 5, −3] 🟰— добавляем 1, чтобы учесть смещение w (со всеми примерами также)

🟰 wᵀ = [-33, 9, 13] 🟰

🟰 wᵀ * x 🟰

🟰 wᵀ * x = −33 * 1 + 9 * 5 + 13 * (−3) = −33 + 45 − 39 = −27 🟰Получаем wᵀ * x < 0, следовательно метка -1

🔜 Можете сами посчитать остальные метки, получаем такую штуку:

predict=[−1, +1, +1, −1, +1, −1, −1]


🧑‍💻 Позже продолжим
Please open Telegram to view this post
VIEW IN TELEGRAM
15542
3221
Друзья, у админа сессия, так что пока держите мем 👨‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
6321
CodeLab
Друзья, у админа сессия, так что пока держите мем 👨‍💻
Media is too big
VIEW IN TELEGRAM
👨‍💻Всем ку, решаем задачку с margin (это у нас так отступ называется). Кстати, уже задачки с отступами были, можете поискать через поиск канала, не менее интересные 👍

Фотка задания в комментах ⬇️

0⃣📱 Итак, условие не отличается от прошлых заданий: у нас есть разделяющая линия, она определяется параметрами

🟰w = [w₀, w₁, w₂]🟰

⚙️ Значения параметров также известны:

🟰w = [15/7, -9/7, -1]🟰

1⃣ Параметры задают положение линии в соответствие с выражением:

🟰w * x₁ + w₂ * x₂ + w₀ = 0 🟰

🔤🔤🌹🔤🔤🔤

2⃣ Так, теперь про отступ, что это и зачем оно нужно

Отступ
(или margin или γ или M) — все это, так или иначе, относится к отступу.

🔵Показывает margin насколько уверенно модель классифицировала точку а также, с какой стороны от разделяющей прямой она находится.


Формулы:

🟰Q(a, X) = Σ[a(x) ≠ y]🟰 — Число неверных классификаций

🟰[a(x) ≠ y]🟰 — нотация Айверсона, важная формула, вощвращает 1 или 0, щас поясню:

🟰y🟰 в нашей скобе это целевое значение, исходя из прошлых задач на бинарную классицикацию, y может быть -1 и +1 (номер класса)

‼️ Так вот, если модель a(x) в скобках [a(x) ≠ y] относит объект не к тому классу, [a(x) ≠ y] — выдает True. В соответствие с нотацией Айверсона 🟰[a(x) ≠ y]🟰 1 (True), 0 (False)

‼️🟰Q(a, X)🟰 — получается, этот функционал подсчитывает число неверных классификаций (сколько раз модель ошиблась)

🟰y ∈{-1, +1} 🟰— как раз, наши целевые

🟰Q(a, X) = Σ[ y * a(x) < 0]🟰 — немного переписываем число неверных классификаций теперь добавили y - целевые {-1, +1} и умножили их на ответ модели a(x) — это тоже, либо -1, либо +1. Если это произведение будет отрицательным — значит, мы неверно классифицируем X. Если y и a(X) будут совпадать (оба по -1; +1)получаем положительные значения.

‼️ Добрались до сути — 🟰M = a(X) * y — отступ (margin)🟰

🟰a(X) = {w, x}🟰 — если мы оставим только скалярное произведение, то 🟰a(X) = {w, x}🟰 будет давать нам не только {+1; -1}, но и величину, на которую отстоит наш образ X от разделяющей прямой (если отступ положительный, образ классифицируется верно)

🟰a(X) = sign(wᵀ * x)🟰— классификация в линейных моделях. В линейных моделях классификатор просто смотрит, с какой стороны от границы находится точка. Если результат положительный — класс +1, если отрицательный — -1
Please open Telegram to view this post
VIEW IN TELEGRAM
3111
3⃣📊 Хотел еще добавить формулу:

🟰γᵢ = yᵢ ⋅ Mᵢ = yᵢ ⋅ (wᵀ * xᵢ)🟰 — это у нас формула для отступа (margin)

🧑‍💻 Mᵢ = wᵀ * xᵢ — скалярное произведение весов и признаков

🧑‍💻 yᵢ ∈ {−1, +1} — целевые метки

🧑‍💻 Умножаем y * M и получаем отступ (насколько правильно мы классифицировали, если y > 0, модель предсказала правильно образ X

👨‍💻 Теперь, что касаемо кода:

4⃣ Импортируем numpy и прописываем веса модели:

import numpy as np

w = np.array([15/7, -9/7, -1]) # [w0, w1, w2]


5⃣ Теперь определяем корды (надо ток добавить единицу для w₀)

x_test = np.array([
(1, -8, -4),
(1, -2, 2),
(1, 4, 8),
(1, 6, 3)
])


6⃣ Теперь нам нужно как-нибудь определить метки (или знаки +1, -1), для этого воспользуемся функцией 🟰np.sign()🟰

y_test = np.sign(x_test @ w.T)


🧑‍💻 Умножаем матрицу из 4 векторов-образов (X) на вектор w, получаем вектор из 4 скалярных произведений:

🔵 x₁ * w ... x₄ * w

🔵w — вектор весов: w = [w₀, w₁, w₂]

🔵xᵢ — вектор признаков: xᵢ = [1, x₁, x₂]

🔵w * xᵢ — это то, насколько объект далеко от прямой


🟰M = a(X) * y🟰

🟰M = {w, x} * y🟰

7⃣ Самое главное, margin:

margin = x_test @ w.T * y_test #Все по формуле


import numpy as np

w = np.array([15/7, -9/7, -1])

x_test = np.array([
(1, -8, -4),
(1, -2, 2),
(1, 4, 8),
(1, 6, 3),
])

y_test = np.sign(x_test @ w.T)

margin = x_test @ w.T * y_test
Please open Telegram to view this post
VIEW IN TELEGRAM
422
🤔 Как вам последние посты? Все ли понятно?
Please open Telegram to view this post
VIEW IN TELEGRAM
522
👨‍💻 Друзья, новое задание! Оно не сильно отличается от прошлого, но разобрать стоит:

📈Снова имеем разделяющую прямую, а также два признака — x₁, x₂, определяется параметрами🟰w = [w₀, w₁, w₂]🟰

⚙️ Только в отличие от прошлого задания, эти параметры нам неизвестны.

0⃣‼️ А вычислить нам нужно значения отступов (напоминаю, margin) для образов 1-6 и сохранить в список 🟰margin = []🟰

1⃣ Начнем с параметров, пример вычисления смотримтут

Скажу сразу, что получилось у меня:

🔵Точки — (-4, 0) ; (5, 4)

🔵k (угловой коэффициент) = y₂ - y₁/ x₂ - x₁ (у меня получилось 4/9)

🔵b (коэффициент смещения, просто подставляем одну из точек и угловой коэффициент) (16/9)

🔵y = 16/9 + 4/9 * x — получили уравнение

🔵Переносим y и вычисляем коэффициенты

🔵-16 -4 * x + 9 = 0 ➡️получили [-16, -4, 9]

2⃣ Теперь прописываем это в коде + пишем корды точек (добавляем единицу для w₀)

import numpy as np
w = np.array([-16, -4, 9])

x_test = np.array([
[1, -5, 2],
[1, -4, 6],
[1, 3, 2],
[1, 3, -3],
[1, 5, 6],
[1, 9, 2]
])


3⃣ Метки классов определяем тоже сами:

y_test = np.array([1, 1, 1, -1, -1])


Вообще, тут у меня возник вопрос, вроде визуально понятно, что точки 1, 2 и 5 выше разделющей прямой, но они идут не по порядку. Если вычислять через np.sign, то получаем

y_test = np.sign(x_test @ w.T)

#y_test = np.array([1, 1, -1, -1, 1]) — А такой ответ не подойдет


4⃣ Вычисляем отступ:

margin = x_test @ w * y_test #Скалярное произведение
print(margin)


‼️ Чем больше отступ, тем увереннее классификация.

🔵В нашем случае, в точках 3 и 5 наша модель опростоволосилась


‼️ Сама формула 🟰margin — Mᵢ = wᵀ * xᵢ🟰 — это просто скалярное произведение между весами (это наши параметры в начале кода) и x-объектами (это и есть наши 6 точек).

🔵 y_test — целевые значения. Говорит нам о том, каким должен быть знак margin, если классификация верная.


‼️ Вот как работает главная формула нашего кода:

w = np.array([-16, -4, 9])
x_test[0] = [1, -5, 2]

M₁ = (-16) * 1 + (-4) * (-5) + 9 * 2 = -16 + 20 + 18 = 22
y₁ = 1

margin₁ = 22 * 1 = 22



5⃣🧑‍💻 Наш код:

import numpy as np

w = np.array([-16, -4, 9])

x_test = np.array([
[1, -5, 2],
[1, -4, 6],
[1, 3, 2],
[1, 3, -3],
[1, 5, 6],
[1, 9, 2]
])


y_test = np.array([1, 1, 1, -1, -1, -1])
# y_test = np.sign(x_test @ w.T)

# print(y_test)

margin = x_test @ w * y_test


🔗 Ссылка на курс 🔗
Please open Telegram to view this post
VIEW IN TELEGRAM
3321
Сегодня крутецкий пост 🧑‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
4221
👨‍💻 Итак, новое задание:

0⃣ Че у нас есть? Мы имеем тестовую выборку в виде набора образов с двумя признаками (x₁ и x₂) — первый элемент это значение x₁, второй — x₂. ‼️ Также мы имеем метки двух классов — (+1, -1)

🔵Вектор параметров у нас тоже имеется — [-8/3, -2/3, 1]

‼️ А вычислить нам нужно Q (это такой показатель качества, который вычисляется как сумма нотации Айверсона (M) для всех точек тестовой выборки). ⚙️ Проще говоря, найденный Q даст нам понять, сколько точек в тестовой выборке имеют отступ.

🟰 Qᵢ = Σ[Mᵢ < 0] 🟰, где 🟰 Mᵢ = y * {w, xᵢ} 🟰

🟰 [Mᵢ < 0] 🟰функция нотации Айверсона (возвращает 1, если Mᵢ < 0, и 0б если Mᵢ ≥ 0).

import numpy as np

x_test = np.array([(-5, 2), (-4, 6), (3, 2), (3, -3), (5, 5), (5, 2), (-1, 3)])
y_test = np.array([1, 1, 1, -1, -1, -1, -1])
w = np.array([-8/3, -2/3, 1])


1⃣⚙️ Для начала, добавляем столбец из единиц:

X = np.column_stack((np.ones(len(x_test)), x_test))


📊 Теперь наш вывод X будет выглядеть как-то так:

[[ 1. -5.  2.] 
[ 1. -4. 6.]
[ 1. 3. 2.]
...


2⃣🧠 Вычисляем отступы по привычной формуле:

🟰 Mᵢ = wᵀ * xᵢ 🟰 скалярное произведение ⟨w,xᵢ)

margin = y_test * (X @ w)


3⃣‼️ Самое главное — считаем количество M [Mᵢ < 0]

Q = np.sum(margin < 0)
print(int(Q))


Q = 2 ➡️ следовательно модель допустила 2 ошибки в выборке из 7 точек (покатит)
Please open Telegram to view this post
VIEW IN TELEGRAM
5332
🤝
Please open Telegram to view this post
VIEW IN TELEGRAM
6331
Постараюсь выкатить пост завтра 🧑‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
5321