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

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

Мои соц:
Дзен- dzen.ru/py3000
Download Telegram
Океей, говорите, вам очень хочется что-то с олимпиадной прогой. Ладно, но я все равно буду её чередовать с чем-то полезным).
Ну окей, поскольку канал про 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 как стохастический.

Вот так)
Я даже не знаю, так как единственное, что у меня сейчвс двигется плюс минус стабильно - это проект по информатике, иногда сюда будет чтото поститься
Please open Telegram to view this post
VIEW IN TELEGRAM
Interfaces.md
4 KB
тут лежат основные механики, но, очевидно, это не все, что, как думаете, стоит еще добавить?
Interfaces.md
8.8 KB
Продуктивненько сегодня поработал)
work_process.png
12.4 KB
бездельник я, бездельник. Знаете, для чего делали ИИ, чтобы я не реализовывал этот интерфейс, а то я точно не вывезу)
Отмена, фотка не та)
👍1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Это теория как с занятий, так и чтото добавил я