Python3000
36 subscribers
3 photos
4 files
6 links
Задачи, решения,библиотеки,и т.д.

В комментариях нельзя спамить,флудить,выкладывать рекламу,оскорблять кого либо в комментариях,сдать стикеры плохого характера.За нарушение - сначала предупреждение, потом бан.

Мои соц:
Дзен- dzen.ru/py3000
Download Telegram
Я хочу сделать курс с просто 0 порогом входа, хотите?
Anonymous Poll
81%
Да, я буду читать, даже делать иногда
19%
Нуууу, нет наверно
Чтош... Начнем наш быстрый экскурс по одному из самых известных фреймворков для создания сайтов на python. Django, прошу любить и жаловать. Если вы выберете его, то вы сразу получаете кучу плюсов, а один из самых важных - есть документация. Вы не дружите с английским? Есть на русском.

Хорошо, что мы сделаем(я надеюсь) за это время? Мы напишем небольшой сайт, что-то типа Интернет магазина, список товаров, у каждого есть отзывы и оценка. Конечно, это будет простой монолит с базой данных на основе SQLite. Если вам интересно, какие архитектуры сейчас используются и как они устроены(и почему спор монолит vs микросервисы больше не актуален), то напишите об этом в комментариях.

Хорошо, что-то я вам много наобещал, а мы так и ничего не сделали. Начнем, как и любую библиотеку, нам нужно её установить, пишем:
pip install django

Успех, теперь создадим сам проект, напишем ещё:
django-admin startproject name_of_your_project

Логично, туда нужно подставить название вашего проекта.

После этого у вас создастся папка с названием вашего проекта, а внутри ещё одна и файлик manage.py. Он нам понадобится ещё много раз, например, прямо сейчас.
python manage.py runserver

После выполнения запуститься локальный сервер(это ещё один плюс Джанго), перейдите на адрес, который он вам дал(обычно это localhost:8000). Вы должны увидеть сообщение приветствия. У нас хорошая статистика, пока 0 строчек кода.

На этом пока что хватит, в этом курсе я не буду давать ДЗ, вы можете просто написать, что мол у меня получилось или у меня ошибка.
🔥3
Продолжим, мы создали проект, давайте посмотрим что у нас есть. В файле settings.py, логично, настройки, есть настройки языка, дебаг, настройки каталогов, файл urls.py отвечает за различные страницы сайта. Хорошо, любой сайт состоит из apps(приложений), например, мы можем создать приложение каталога товаров, оформления заказов и панели администратора. Создадим первое приложение.
python manage.py startapp shop

Теперь у вас появилась папка приложения, но мне не очень нравится её расположение, я бы хотел, чтобы она лежала в парке apps, внутри проекта. Перенесем её туда, зайдем в settings.py и создадим переменную
PROJECT_ROOT = os.path.dirname(__file__) 
sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))

Вторая строчка просто нужна для расширения среды, не забудьте импортировать sys. Можете запустить сервер и проверить, что никаких ошибок не возникает(кстати, если вы меняете какие-то файлы, то сервер можно не перезапускать, он сам применит изменения).

Отлично, заходим в папку приложения и видим:
1. Папку migrations - папка необходимая для работы с БД.
2. Файл models.py - один из самых важных файлов, про него чуть позже.
3. Файл views.py - тоже очень важно, будет нужен для выдачи ответов.
4. Ещё несколько файлов, которые я пока оставлю без комментариев.

Хорошо, для того, чтобы продолжить маленькая справка по тому, как взаимодействуют хостинг(сайт) и компьютер пользователя. Идете вы, например, смотреть Ютуб, ваш компьютер делает http запрос на сервер, он хочет получить страничку. Такой тип запросов называется GET-запрос. Сервер ищет, что он будет выдавать на этот запрос, а потом отправляет страницу. После нескольких итераций получения всех файлов(например само видео будет передаваться отдельно, как и таблицы стилей). За обработку запроса отвечает как раз файл urls.py. А вот за генерацию ответа - views.py. Давайте научимся отдавать простейшие ответы при заходе в каталог.

Сначала напишем как мы хотим отвечать на запрос. Для этого заходим во views.py, стираем всё и записываем:
from django.http import HttpResponse

def index(request):
return HttpResponse("Тук-тук-тук")

Здесь мы инициализировали просто функции, которые отдают ответ в виде строки.
Но нам также нужно сопоставить путям, которые запрашивает сайт(например https://mysite/page/comments), ответы. Для этого и существует urls.py. Поскольку одна из страниц относится к нашему приложению, то давайте и привязку будем делать в нём.
Создаем в парке приложения файл urls.py и пишем:
from django.urls import path
from . import views

urlpatterns = [
path('', views.index, name = "index")
]

Этим мы сказали, что начальная страница нашего приложения (именно его, мы создадим путь до него, адрес у этой страницы будет типа http://site.ru/shop/) будет возвращать ответ в соответствии с функцией index во views.py.

Осталось только настроить привязки в самом проекте, поэтому находим такой же файл в папке проекта и добавляем:
... 
urlpatterns=[
path("shop/", include("shop.urls")),
#тут строка с админкой
]
...

Не забудьте в импорте кроме path импортировать ещё и include.
В этом фрагменте мы все привязки из приложения shop поставили после пути http://site.ru/shop/. То есть мы как бы задали то, откуда начинается наше приложение.

Теперь, если вы откроете в адресной строке этот путь то вы увидите текст.

Оставлю вас пока с этим, удачи!
А чисто теоретически, это кто-то читает?
👍7
Я вернулся, продолжим.
Теперь, давайте разберемся с базой данных.

Джанго поддерживает практически все существующие базы данных, по умолчанию там стоит файловая SQLite, которую сейчас особо не используют в серозных проектах. Но для нашей цели её пока хватает, но если что, в настройках всегда можно подключить что-то другое.
Вся структура базы данных строится на моделях. Модель - некоторый объект с определенными свойствами. Например может быть модель с именем "товар", что нам от неё нужно? Название товара, стоимость, наличие на складе, фото и Мб что-то еще, но я ограничусь этим. В Джанго для моделей существует файл, который так и называется models.py. Давайте создадим нашу модель.
Открываем файл и пишем:
from django.db import models

class Item(models.Model):
name = models.CharField(max_length=20)
cost = models.IntegerField()
isSold = models.BooleanField()
image = models.FileField()

Здесь мы объявили класс Item(все модели принято называть с большой буквы в единственном числе), который описывает наш товар, у этой модели есть четыре поля: имя, цена, распродан ли и фото(да, есть специальное поле ImageField, но оно требует установку pillow) . У каждого поля есть тип, который определяет что туда можно написать, подробнее о них можно прочесть в документации.

Ну хорошо, вот мы вроде создали модель, а дальше что? Теперь надо создать табличку в самой бд. Открываем консоль:
python manage.py makemigrations
Эта команда
1. Создаст карту миграции,которую мы потом применим.
2. Создаст файл в папочке migrations, можете его открыть, там примерно описано, что за таблицу мы создаем и что с ней делать.
Окей, но пока таблица не создалась, нам нужно ещë чучуть написать
python manage.py migrate

Мы применили миграцию, теперь бд в сборе и мы можем туда что-то добавить. А как? Есть два способа: через код и через админ панель. Разберемся с обоими.
Для начала как это делать через код. Есть большое количество методов, которые позволяют делать что угодно, я покажу несколько.
1. create()
doshik = Item.objects.create(name = "doshik", cost = 999, isSold = True, image = ...) 

Теперь в переменной с соответствующим названием лежит наш новый продукт, все просто.
Если вдруг что, вы можете разить это на две строчки. Создайте экземпляр класса и примените посже к нему метод save(). На этом методов записи нам хватит, так-то их много.
2. get()
doshik = Item.objects.get(cost = 999) 

Он позволяет получить объект по условию, но, важно понимать, что если количество таких объектов, что соответствуют условию, отлично от единицы, то вас пошлют с ошибкой, поэтому лучшее применение - поиск по айди.
3.get_or_create()
Не думаю, что тут нужны пояснения, просто получит из таблички, если нету, то создаст.
Но тут важно, что эта команда вернет кортеж из двух элементов, первый - объект, второй - был ли он создан.
4. filter()
Даст все элементы, которые соответствуют условиям.
notSold = Item.objects.filter(isSold = False) 

Все продукты в наличии.

Хорошо, предпоследнее здесь будет то, что позволит редактировать бд прямо в браузере. В Джанго есть встроенная админ-панель.
Команда:
python manage.py createsuperuser

После этого вам предложат придумать пароль, зайдите на сайте по пути /admin. Вам нужно зайти в пользователя, вы открыли админ панель, но пока там почти ничего нет, нужно её настроить. Для этого есть admin.py
from django.contrib import admin
from .models import Item

admin.site.register(Item)

И всё, теперь можно ручками добавлять продукты.

Последнее - это создание отзывов. Модель отзыва должна содержать текст, автора, оценку, а главное, к какому товару он относится. Когда модели может быть сопоставлено несколько других это называется отношение один ко многим. То есть к одному продукту мы можем написать сколько угодно отзывов, но важно, что отзым относится только к одному продукту. Также существует отношение многие ко многим и один к одному.
Вот моя модель отзывов.
class Review(models.Model):
item = models.ForeignKey(
'Item',
on_delete=models.CASCADE,
related_name='reviews',
verbose_name='Товар'
)
author = models.CharField(
max_length=100,
verbose_name='Имя автора'
)
text = models.TextField(
verbose_name='Текст отзыва'
)
rating = models.IntegerField()

ForeignKey как раз отвечает за то, что каждому отзыву сопоставляется продукт, к которому он относится.

Пока так, в следующий раз сделаем уже что-то красивое.
Штош, как я и обещал, что-то красивое.
Давайте добавим сам сайт. Для гибкой настройки того, что отправляется пользователю, есть система шаблонов, которые мы будем использовать. И да, мы будем использовать язык разметки HTML, таблицы стилей и JavaScript пока не трогаю, но если вы хотите в рамках курса гайд по ним, я могу сделать, заодно мы получим красивую страничку. Пишите в комментарии!

Так вот, давайте создадим папочку templates в папку нашего проекта, там мы будем размещать все наши шаблоны. Но, чтобы это сработало, нам нужно сходить в файл настроек и добавить одну строчку.
TEMPLATES = [
{
#...
'DIRS': [
os.path.join(PROJECT_ROOT,'templates')
],
#...
},

]

Супер, теперь, давайте создадим стандартный шаблон, то есть такой, какой ляжет в основу всех страниц. Например там может быть стандартный вид сайта, хеддер(это менюшка сверху для навигации по сайту), подвал(там где пишут телефон техподдержки и ссылки на доки). Назовем файл base.html и положим в папку шаблонов.
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Shop{% endblock %}</title>
</head>
<body>
Здесь вы можете разместить,например,хеддер
{% block content %}{% endblock %}
</body>
</html>

Так вот, это конструкции шаблонизатора, мы можем в отдельном шаблоне задать то, что Джанго поставит вместо каждого блока, поэтому, если мы хотим сделать страницу товара и каталога, нам бы не пришлось копировать код во все файлы, а если вы захотели подправить хеддер, то его не придется менять везде, он изменится автоматически. Давайте напишем страницу-каталог. Создадим в папке шаблонов папку с названием нашего приложения. Там мы и будем хранить шаблоны нашего приложения. Создадим файл shop.html
{% extends 'base.html' %}
{% block title %}Каталог товаров{% endblock %}

{% block content %}
Lorem Ipsum...
{% endblock %}

Пока тут просто заглушки, но давайте сделаем, чтобы мы их видели при загрузке.
Для этого нам потребуется уже известный views.py. Откроем, и изменим код
from django.shortcuts import render

def index(request):
return render(request,'shop/shop.html')

Вот, теперь если мы запустим сервер, то увидим то, что у нас отображается наша заглушка в виде текста. А что, собственно произошло? Джанго render нашёл по пути шаблон, он ссылается на базовый шаблон, в базовом шаблоне два блока. Шаблонизатор заменяет блоки на то, что написано в шаблоне, который мы написали последним. Успех, осталось всего лишь то отобразить список. Кстати, если что, в исходном коде страницы нет и следа того, что мы использовали шаблоны.

Ну, хорошо, нам нужно же из базы данных получить все это добро и на страницу вывести. Давайте это и сделаем, для этого идем во views.py
from django.shortcuts import render
from .models import Item

def index(request):
products_list = Item.objects.order_by('-cost')
return render(request,'shop/shop.html', {'items': products_list})

Во-первых появился order_by, он, логично, сортирует наши элементы, знак "-" перед параметром означает, что я буду сортировать в обратном порядке. И третий аргумент render. Он указывает контекст, то есть то, что мы даем шаблонизатору, сейчас мы это используем.
Возвращаемся к нашему шаблону
{% extends 'base.html' %}
{% block title %}Каталог товаров{% endblock %}

{% block content %}
{% for a in items %}
<a href = "#">{{a.name}}</a>
{% endfor %}
{% endblock %}

Вот, теперь у нас есть список продуктов сверху вниз. И, пока я на этом закончу, жду ваших комментариев, хотите ли вы отдельный урок по языку разметки и таблицам стилей, а то пока наш сайт всё ещё выглядит грустным.
Да, а вам нужен отдельный урок по HTML, CSS, для создания красивых страниц?
Anonymous Poll
93%
Да
7%
Нет
Супер, я вернулся. Вы хотели увидеть как кодить красивые страницы. Этот урок будет посвящён HTML и CSS. Это самая база, так как, конечно, сейчас появилось куча языков, которые типо лучше чем эти и они компилируются прямо в них, например SCSS. А кроме того есть еще третий язык - JavaScript, но про него стоит делать отдельный пост. Поэтому в этом уроке будет самая база.

Начнем с языка разметки HTML. Он нужен для того, чтобы создавать кнопки, надписи, таблицы и тп. Его синтаксис строится на тегах, теги бывают двух видов:парные и одиночные. Парные теги выглядят в общем случае вот так:
<...></...>

Вместо многоточия стоит название тега. Часть тега без слэша называется открывающая, а вторая, соответственно, закрывающая. Одиночный тег пишется только открывающейся частью. У тегов могут быть параметры, они указываются в открывающейся части. Например:
<a href="google.com">Текст ссылки</a>

Это тег ссылки, он имеет один параметр - адрес ссылки. Между первой и второй частями идет текст ссылки. Вот несколько тегов, которые стоит знать:
<h1>Текст заголовка</h1> - заголовок,чембольше цифра в имеги тега,тем меньше текст.
<p>Текст параграфа</p> - тег параграфа.
<div>Другие теги</div> - один из важнейших тегов, может содержать в себе другие,используетсякак контейнер.
<b>Текст</b> - делает текст жирным.
<em>Текст</em> - курсив.
<html>Теги</html> - обязательный тег,который содержит в себе все теги страницы.
<head></head> - обязательный тег,которыйсодержит в основном мета информацию о странице.
<body></body> - обязательный тег,который содержит в себе элементы,которыеотображаются на страгице.
<img src = ""> - вставляет картинку.

Окей, допустим, пока хватит, давайте напишем первую страничку. В файле index.html можем написать:
<!DOCTYPE html> <!-- обязательный тег,обьявляеттип документа -->
<html>
<head>
<title>Имя страницы</title>
</head>
<body>
<h1>Первая страница!</h1>
</body>
</html>

Вот, если вы откроете этот файл в браузере, то вы увидите надпись, Ура!)
Теперь вы можете просто добавлять любые теги в тело(тег body) и они будут появляться у вас на сайте. Окей, но пока всё выглядит, мягко говоря, уныло, просто элементы в столбик, на сайт apple это не похоже. Для этого нам понадобится таблица стилей.
Допишем в тег head указание на таблицу стилей.
<link rel="stylesheet" href="">

В href напишите путь к файлу с расширением css. Например, можем создать файл style.css.
Синтаксис этого языка выглядит так: указатель на объект, в фигурных скобках через точки с запятой названия стилей, и через двоеточие значение. Пример:
h1{
color: red;
font-family: arial;
}

Тут я для всех тегов h1 сказал, что их писать красным цветом с таким шрифтом. Но, допустим, что я не хочу задавать всем заголовкам один и тот же стиль. Тогда есть две идеи, во-первых, если мне нужно одному конкретному элементу задать стиль, например кнопке. Тогда есть атрибут id у каждого тега. Задав его можно стиль задать для объекта с помощью решётки, после неё должнен стоять id и дальше по стандарту
#firth{
color: red;
font-family: arial;
}

Также есть класс, один и тот же класс можно задать к большому числу объектов, и также как с айди, только вместо решётки нужно поставить точку, можно задавать стили.

Стилей очень много, так что вот основные, но их все можно на гуглить, потом найдете сами.
width - ширина элемента,можноуказывать в px
height - высота
color - цвет,длятекста это обычно цвет самого текста
background-color - цвет заднего фона
font-size - размер текста
margin - отступ снаружи
padding - отступ изнутри

Ну вот, часто вообще из названия сразу очевидно о чем это, так что так, я могу сделать еще одну часть, где я разберу это подробнее или рассказать также коротко про JavaScript. Кроме того мне может быть интересно посмотреть что сделаете вы, так что маленькая задачка, творческая, оформите страничку нашего сайта магазина и пришлите результат, тут важно не чтобы было красиво, а чтобы вы показали, что можете сделать сами, я могу чего-то подсказать. В любом случае через время Яя сам в комментариях пришлю свой вариант с кодом. Удачи всем!
😁1
Хмм, слушайте, я вот думаю, начало учебного года равносильно паре часов доп времени в день, есть ли у кого-то невероятные идеи, что вы хотите тут прочитать, лучше, конечно, примерно по теме)
Если что, если их не будет, я просто буду выпускать небольшие посты примерно на одну тему на пост (т.е. я не буду пытаться делать курс или что-то подобное)
Океей, говорите, вам очень хочется что-то с олимпиадной прогой. Ладно, но я все равно буду её чередовать с чем-то полезным).
Ну окей, поскольку канал про python, будем учится на нём. И я хочу как можно более полно рассказать о хеш-таблицах или словарях.
Начнем с их устройства. Хэш-таблицы - это такая структура данных, которая сопоставляет каждому ключу из списка ключей значения из некоторого другого списка. Причем она должна поддерживать несколько операций:
1) За О(1) она должна уметь добавлять, изменять или убирать любой элемент по ключу.
2) За О(1) можно получить любой элемент по ключу.
3) За О(n), где n - кол-во элементов таблицы, мы можем проитерироваться по всем парам ключ - значение.
Окей, внутри она устроена так, что есть некая функция, которая умеет превращать любой наш key в хэш, т.е. такое число, что для разных изначальных keys она должна в идеале получать разные значения. Почему в идеале? Ну, например, если мы попробуем хэшировать строки, то можем посчитать, с каким их количеством имеем дело. Чисел(это то, что мы сопоставляем строкам) у нас максимум 2^64, а вот строк в общем то сколько угодно. В разумных пределах строка может достигать любой длины, а разнообразие символов превратит это в степень, основание у которой - количество символов, которые мы можем использовать на некотором месте в строке. Как упражнение даю вам посчитать, строку из скольки русских маленьких и пробельных символов можно точно идеально закодировать(т.е. потенциально существует алгоритм, который всегда сможет сопоставить строке уникальное число).
В действительности все проще, мы просто хотим сделать вероятность случайного совпадения предельно маленькой. Поэтому мы можем, к примеру высчитывать значение какого нибудь полинома с коэффициентами из номеров символов в соответствующей таблице символов. Далее эти хэши мы используем для индексации в новом массиве и так получаем все, что нам нужно)

Теперь про код. В python все как всегда очень просто, создать словарь можно способами:
python

#like this
d = dict()
#or like this
d = {}

А также вот как выглядят базовые команды:
python

#set an element by a key
d["apple"] = "fruit"
#replace an element
d["apple"] = "green"
#get an element, raises error if unable to get
print(d["apple"]) #green
#get an element or set a default value
print(d.get("banana", "yellow")) #yellow, d["banana"] → yellow

Мы можем несколькими способами итерироваться по словарям
d = {"apple": 120, "banana": 150, "orange": 100}

for fruit, mass in d.items():
print(mass)
#or you can get pairs (key, value)
for fruit in d.items():
print(fruit) #("apple", 120) ...

#if you want to have only keys
for fruit in d.keys():
print(fruit)
#and only values
for mass in d.values():
print(mass)

Важно помнить, что d.keys() и d.values() возвращают объекты-итераторы, и чтобы превратить их в список нужно отдельно воспользоваться list(). Последнее в этом блоке, это то, что не каждый объект можно захэшировать. Например, любой изменяемый тип данных как правило не хэшируется, не считая строк. Чтобы превратить, к примеру, список в хэшируемый объект, можно превратить его в кортеж, после этого он станет неизменяемым.

Теперь расскажу кое-что сложнее.
Поскольку наш любимый язык с батарейками в комплекте, то мы имеем кучу стандартных модулей, один из таких - модуль itertools. В нём есть несколько важных функций для работы в том числе со списками.
1. itertools.islice
Позволяет работать со срезами в словарях, так как обычные нет.
import itertools

count_dict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}

# Get the first 2 items of the dictionary
first_two = dict(itertools.islice(count_dict.items(), 2))

print(first_two)# {'one': 1, 'two': 2}
2. Можно группировать элементы в зависимости от значений в словаре
import itertools

users = [
{"name": "Alice", "role": "Admin"},
{"name": "Bob", "role": "User"},
{"name": "Charlie", "role": "Admin"}
]

# Sort by the grouping key first (required by groupby)
users.sort(key=lambda x: x["role"])
# Group by role
for role, group in itertools.groupby(users, key=lambda x: x["role"]):
print(f"Role: {role}")
for user in group:
print(f" - {user['name']}")

Да, тут мы использовали lambda-функцию, она отличается от обычной лишь тем, что не имеет названия и состоит из одной строки. Тут за значение группировки взяли прямо значение по ключу, но мы можем и произвести с ним вычисления, например, если бы это было число и нам нужно было бы сгруппировать их по модулю этого числа, то мы могли возводить просто его в квадрат(ну или в качестве аргумента передавать функцию модуля).

В модуле itertools есть еще много хороших инструментов, но на этом я, пожалуй, остановлюсь, если вам станет интересно, можете написать, и я напишу подробнее.

Также, если вы хотите, я могу кинуть задачку на использование хэш таблиц)
Ребят, у меня образовался новый кружек по ИИ, вы хотите тут видеть какую-то сжатую теорию с него?
Окей, сегодня была первая лекция, вам нужен линал? Я буду рассказывать его примерно также, как и у нас, а то расписывать все все аксиомы с 0 я в восьмой раз не хочу, наверное. Короче, если у вас есть желание это прочитать (я постараюсь сделать это легким), то пишите, лайкните или каким либо другим способом скажите...
❤9
Супер, есть реакция, тогда сегодня/завтра утром ждите)
❤2
Окей, как я и обещал.
Я расскажу ровно то, что рассказывали нам и то, что может потребоваться для ML.
Как и всегда, начнем с определение линейного пространства.
Опр Линейным пространством называют множество с заданными операциями сложения элемента и умножение на любое действительное число. Причем они(операции) должны удовлетворять некоторым свойствам.
1. Должен быть такой элемент 0, что для любого a из л.п.(линейного пространства) a + 0 = 0 + a = a.
2. Сложение должно обладать набором "хороших" свойств(типа ассоциативность, дистрибутивность и тп)
3. Умножение также должно быть "хорошим".
Про "хорошие" свойства, может быть, мы поговорим позднее, но пока, считайте, что это нормальное сложение и умножение.
Конечно, элементами л.п. являются векторы. Также, хочется привести пример л.п. с которым мы будем работать почти всегда, это пространство R^n, состоит из столбцов из n чисел с поэлементным сложением и умножением. Вы можете сами доказать, что все свойства есть.
Теперь поговорим о матрицах. Матрица - табличка вещественных чисел, сложение и умножение на число определены поэлементно(т.е. складываются соответствующие элементы матриц). Вот, а умножение матрицы на вектор сделано по-другому. Тут есть хороший пример, пусть матрица - строчки - очередной клиент магазина, а столбцы - разные товары, на пересечении строки и столбца стоит количество продукта, который купил данный покупатель. А вектор - стоимость за штучку товара. Тогда количество столбцев матрицы должно совпадать с размерностью вектора. Тогда в итоговом векторе будет сумма, которую заплатил каждый посетитель. Или как-то так.
(1 2 3) (1) (1 + 4 + 15)
(5 0 6) × (2) = (5 + 0 + 12)
(4 3 1) (5) (4 + 6 + 5)
Вот так. Последнее, это решение систем линейных уравнений.
Идея такая, систему можно записать в виде умножения матрицы коэффициентов на столбец переменных, т.е. нам нужно найти такой вектор, чтобы при умножении матрицы на него получался данный вектор. Существует метод Гаусса, который задает несколько операций с матрицей, к которой присоединила вектор ответа. Можно поменять строки местами, можно всю строку умножить на число и тп. И такими операциями по возможности можно привести матрицу к ступенчатому виду, т.е. такому, чтобы в каждой новой строке было меньше ненулевых коэффициентов, т.е. в последней строке должен быть только один ненулевой коэффициент, а значит мы можем все переменные выразить.

Вот, тут не очень много, но это ровно то, что нам рассказали...
Такс, сегодня нам рассказали про линейную регрессию, вам это нужно?
Окей, ребятки, я разобью это на набор кусочков, а то уместить час(за который мы не успели) теории в один пост будет сложно.
Сегодня мы будем смотреть на задачу регрессии, т.е. задачу предсказания числа по набору каких-то других. При этом перед этим мы имеем n примеров, пар вида набор чисел - число. Окей, количество чисел во всех наборах одно и то же, пусть d. Тогда все наши примеры можно представить точками в многомерном пространстве, а задачу, как попытку провести поверхность через наши данные, чтобы она как-то хорошо их аппроксимировала. Ну, для простоты, давайте проводить плоскость (то, что задаётся уравнением ax + by + ... = 0). Осталось понять, а как считать, плоскость хорошая или плохая. Для этого есть разные функции ошибок, например:
MAE: самая простая, считает средний модуль ошибки, т.е. складывает модули разности предсказания модели и реального значения и делит это на их количество. Проблема её, например, в том, что модуль не везде дифференцируем.
MSE: то же самое, только вместо модуля берется квадрат.
Это две самые основные, про остальные поговорим в одной из следующих частей.
Хорошо, тогда заметим, что если все наши примеры сделать строками матрицы, то при умножении её на вектор весов, мы получим вектор предсказаний модели, а потом(советую написать это) можно вычесть вектор правильных ответов, а тогда, если найти квадрат его длины и поделить на размер - это и будет MSE. Окей, если мы хотим найти минимум этой штуки, то это можно сделать аналитически. Ищем производную, приравниваем к 0 и готово, используя вторую производную можно доказать, что это минимум, супер. Так вот, у вас есть два задания(если хочется, кидайте решения в комменты) :
1. Выведите общее решение математически.
2. Закодите его(воспользуйтесь numpy)

Не волнуйтесь, код тоже будет, но потом)
Продолжим.
У подхода из предыдущей теории есть пара проблем
1. Все примеру нам нужно единовременно хранить в памяти, а их может быть очень много.
2. Обращение матрицы стоит дорого по операциям, поэтому слишком много обучающих примеров мы взять не можем.
А для их решения есть итеративные методы обучения, сегодня разберем градиентный спуск.
Градиентный спуск - алгоритм, который позволяет находить минимум произвольной дифференцируемой функции. Его работа заключается в вычислении производной по каждому параметру функции(вектор частных производных функции называется градиентом и направлен он в сторону наибольшего возрастания функции) и двигает точку в сторону, обратную той, что указывает градиент. Так мы двигаемся всегда вниз по функции, и если снижению придет конец, то мы нашли наш минимум. У этого алгоритма есть два параметра, которые мы задаем перед обучением(так называемых гиперпараметра):
1. lr, learning rate - параметр, показывающий, на сколько нужно умножить градиент, чтобы получить вектор смещения нашей точки, т.е. чем он больше, тем быстрее мы спускаемся, но при этом в узкий минимум можем не попасть, а если возьмем слишком маленький, то будем очень долго идти.
2. p0 - начальная точка, от неё зависит, куда мы попадем в конце, ведь наш спуск ищет локальный минимум, поэтому, если у нас их несколько, то мы можем попасть не в глобальный.
Тут снова есть две проблемы:
1. Как я уже сказал, не факт, что у нас получится найти нужный нам минимум.
2. Вычисление функции ошибки требует n операций(кол-во примеров), нахождение, например, численно производную по каждому аргументу требует отдельно пошевелить каждый из параметров. Короче, хотя и быстрее, но с учетом того, что это итеративный алгоритм, может быть долго. Для этого придумали две разновидности такого алгоритма.
1. Mini-batched. Это вид градиентного спуска, в котором мы каждую итерацию обучаемся не на конкретном наборе данных, а на неком рандомном его подмножестве, это быстрее, хотя и шумнее иногда.
2. Стохастический градиентный спуск. Это тоже самое, что и первое, только выборка состоит из одного элемента. Также часто из объединяют и просто называют mini-batched как стохастический.

Вот так)