Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Лайфкодинг ML

Все темы Data Scientist

⌨️ Задачи


Задача №1

Ручные признаки для анализа изображений
Помимо использования глубокого обучения, часто для решения задач приходится самому придумывать признаки.
На вход Вам дана черно-белая картинка в виде матрицы, где 1 — черный пиксель, 0 — белый. Назовем
кластером группу горизонтально или вертикально связанных черных пикселей, которые горизонтально
и вертикально окружены белым.

Входные данные: Матрица где каждый элемент “1” или “0”

Задача: Для заданной матрицы найти количество черных кластеров.

Пример:
[["1","1","1","1","0"],["1","1","0","1","0"], ["1","1","0","0","0"],["0","0","0","0","0"]]

Ответ: 1

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

def count_clusters(matrix):
    def dfs(matrix, i, j):
        # Проверяем граничные условия и наличие черного пикселя
        if i < 0 or i >= len(matrix) or j < 0 or j >= len(matrix[0]) or matrix[i][j] == "0":
            return
        # Отмечаем текущий пиксель как посещенный
        matrix[i][j] = "0"
        # Рекурсивно вызываем DFS для всех смежных пикселей
        dfs(matrix, i+1, j)
        dfs(matrix, i-1, j)
        dfs(matrix, i, j+1)
        dfs(matrix, i, j-1)

    count = 0
    # Проходим по каждому пикселю в матрице
    for i in range(len(matrix)):
        for j in range(len(matrix[0])):
            # Если встречаем черный пиксель, увеличиваем счетчик кластеров и запускаем DFS
            if matrix[i][j] == "1":
                count += 1
                dfs(matrix, i, j)
    return count

# Пример использования
matrix = [["1", "1", "1", "1", "0"],
          ["1", "1", "0", "1", "0"],
          ["1", "1", "0", "0", "0"],
          ["0", "0", "0", "0", "0"]]
print(count_clusters(matrix))  # 1

Задача №2

Представлено 100 наблюдений, из которых 60 дефолтных.
Наивная модель предполагает, что вероятность случайного выбора дефолтного наблюдения составляет 60%.
Для такой модели, каково среднее значение precision и recall?

Для оценки средних значений precision и recall для наивной модели, предполагающей, что вероятность случайного выбора дефолтного наблюдения составляет 60%, мы можем использовать следующие формулы:

Precision=TP(TP+FP)Precision = \frac{TP} {(TP + FP)}
Recall=TP(TP+FN)Recall = \frac{TP} {(TP + FN)}

Где:

  • TP (True Positives) - количество дефолтных наблюдений, которые были правильно классифицированы как дефолтные.

  • FP (False Positives) - количество не-дефолтных наблюдений, которые были ошибочно классифицированы как дефолтные.

  • FN (False Negatives) - количество дефолтных наблюдений, которые были ошибочно классифицированы как не-дефолтные.

Условие не уточняет правило превращения вероятности в метку класса. Если модель выдаёт всем вероятность дефолта 0,6 и применяется порог 0,5, все 100 наблюдений классифицируются как дефолтные. Тогда TP=60,FP=40,FN=0TP=60,\quad FP=40,\quad FN=0 и precision=6060+40=0.6\mathrm{precision}=\frac{60}{60+40}=0.6.

Для этого же правила модель находит все дефолтные наблюдения, поэтому recall=TPTP+FN=6060+0=1\mathrm{recall}=\frac{TP}{TP+FN}=\frac{60}{60+0}=1. Recall равен 100%, а не 60%.

Если имеется в виду другой алгоритм — независимо предсказывать дефолт с вероятностью 0,6 для каждого наблюдения, — ожидаемый recall равен 0,6. Ожидаемый precision также равен 0,6 при условии, что предсказан хотя бы один дефолт. При отсутствии положительных предсказаний precision не определён; способ обработки этого случая нужно оговорить. Постоянная вероятность с порогом и случайная выдача меток — разные модели.


Задача №3

Дана функция rnd2, возвращающая равновероятно 0 или 1.
Используя rnd2, написать функцию rnd3, которая равновероятно возвращает 0, 1 или 2.
Решение:
import random

def rnd2():
    return random.randint(0, 1)

def rnd3():
    while True:
        # Генерируем два случайных бита с помощью rnd2
        bit1 = rnd2()
        bit2 = rnd2()

        # Преобразуем два бита в число от 0 до 3
        num = bit1 * 2 + bit2

        # Если число меньше 3, возвращаем его
        if num < 3:
            return num

print(rnd3())

Задача №4

Дано: датасет N нулей, M единиц.
Нужно минимизировать логлосс: - sum_i(t_i * log(p) + (1-t_i) * log(1-p)) по отношению к p.
Решение:
from scipy.optimize import minimize_scalar
import numpy as np

def log_loss(p, t):
    loss = -np.sum(t * np.log(p) + (1 - t) * np.log(1 - p))
    return loss

def minimize_log_loss(N, M):
    t = np.concatenate([np.zeros(N), np.ones(M)])  # Создаем вектор меток t
    result = minimize_scalar(log_loss, args=(t,), bounds=(0, 1), method='bounded')
    return result.x

# Пример использования
N = 50  # Количество нулей
M = 30  # Количество единиц
optimal_p = minimize_log_loss(N, M)
print("Optimal p:", optimal_p)

Задача №5

Предположим, что у нас есть разметчик, который имеет навык 90, то есть мы считаем,
что независимо от задачи, он отвечает правильно с вероятностью 90 %. Пусть он размечает картинки на котиков и собачек,
причем наш набор данных сильно несбалансированный: котиков в нем всего 10 %.

На случайно выбранную картинку разметчик отвечает, что это котик. Какова вероятность, что была выбрана картинка с котиком?
Решение:

Для решения этой задачи мы можем воспользоваться формулой Байеса. Пусть событие CC - это выбор картинки с котиком, а событие AA - это ответ разметчика о том, что на картинке изображен котик.

Тогда мы хотим найти вероятность того, что на картинке действительно изображен котик при условии того, что разметчик ответил, что это котик:

P(CA)=P(AC)P(C)P(A)P(C|A) = \frac{P(A|C) \cdot P(C)}{P(A)}

Где:

  • P(CA)P(C|A) - вероятность того, что выбрана картика с котиком при условии, что разметчик ответил, что это котик (искомая нами вероятность).

  • P(AC)P(A|C) - вероятность того, что разметчик ответил, что на картинке котик, при условии, что на самом деле на картинке котик. По условию задачи, это равно навыку разметчика, то есть P(AC)=0.9P(A|C) = 0.9.

  • P(C)P(C) - вероятность того, что на случайно выбранной картинке изображен котик. По условию задачи, котиков в наборе данных всего 10%, то есть P(C)=0.1P(C) = 0.1.

  • P(A)P(A) - общая вероятность того, что разметчик ответил, что на картинке котик. Это сумма вероятности того, что разметчик ответил, что на картинке котик, при условии того, что на самом деле там котик, и вероятности того, что разметчик ответил, что на картинке котик, при условии того, что на самом деле там собачка, то есть

    P(A)=P(AC)P(C)+P(AC)P(C)P(A) = P(A|C) \cdot P(C) + P(A|\overline{C}) \cdot P(\overline{C})

    , где C\overline{C} обозначает событие “на картинке собачка”.

Теперь мы можем вычислить вероятность P(CA):P(C|A):

P(A)=0.90.1+0.10.9=0.09+0.09=0.18P(A)=0.9⋅0.1+0.1⋅0.9=0.09+0.09=0.18
P(CA)=P(AC)P(C)P(A)P(C∣A)= \frac{P(A∣C)⋅P(C)}{P(A)}
P(CA)=0.090.18=0.5P(C∣A)=\frac{0.09}{0.18}=0.5
Ответ: 0.5.

Задача №6

Написать реализацию метода ближайших соседей (KNN) с использованием только стандартной библиотеки Python,
без использования библиотек типа NumPy, scikit-learn и тому подобных.
Решение:
import math

class KNN:
    def __init__(self, k):
        # Конструктор класса KNN, принимает параметр k - количество соседей для учитывания
        self.k = k

    def fit(self, X_train, y_train):
        # Метод для обучения модели, принимает обучающие данные X_train и метки классов y_train
        self.X_train = X_train  # Обучающие данные
        self.y_train = y_train  # Метки классов для обучающих данных

    def predict(self, X_test):
        # Метод для предсказания меток классов для тестовых данных X_test
        predictions = []  # Инициализация списка предсказанных меток
        for x in X_test:
            # Для каждого тестового примера
            neighbors = self.get_neighbors(x)  # Получаем k ближайших соседей
            predicted_label = self.vote(neighbors)  # Проголосовать за класс среди соседей
            predictions.append(predicted_label)  # Добавить предсказанную метку в список
        return predictions  # Вернуть список предсказанных меток

    def euclidean_distance(self, x1, x2):
        # Метод для вычисления евклидова расстояния между двумя точками x1 и x2
        distance = 0  # Начальное значение расстояния
        for i in range(len(x1)):
            # Для каждой компоненты точек
            distance += (x1[i] - x2[i]) ** 2  # Добавить квадрат разности к расстоянию
        return math.sqrt(distance)  # Вернуть корень из суммы квадратов

    def get_neighbors(self, x):
        # Метод для получения k ближайших соседей для точки x
        distances = []  # Инициализация списка расстояний до соседей
        for i in range(len(self.X_train)):
            # Для каждой точки в обучающих данных
            dist = self.euclidean_distance(x, self.X_train[i])  # Вычислить расстояние до точки x
            distances.append((self.X_train[i], self.y_train[i], dist))  # Добавить расстояние в список
        distances.sort(key=lambda x: x[2])  # Отсортировать список по расстояниям
        neighbors = [distances[i] for i in range(self.k)]  # Выбрать k ближайших соседей
        return neighbors  # Вернуть список ближайших соседей

    def vote(self, neighbors):
        # Метод для проголосовать за класс среди ближайших соседей
        votes = {}  # Словарь для подсчета голосов за каждый класс
        for neighbor in neighbors:
            # Для каждого соседа
            label = neighbor[1]  # Метка класса соседа
            if label in votes:
                votes[label] += 1  # Увеличить счетчик голосов
            else:
                votes[label] = 1  # Инициализировать счетчик голосов
        return max(votes, key=votes.get)  # Вернуть класс с наибольшим количеством голосов

Задача №7

Как обучить сетку так, чтобы на батче из 32 объектов она обучалась так же, как на батче из 2000?
Решение:

Для имитации большого батча используют накопление градиентов: последовательно выполняют forward и backward на микробатчах, а optimizer.step() вызывают после суммарных 2000 объектов. Можно взять 62 микробатча по 32 объекта и один из 16.

Если loss микробатча усреднён, перед backward умножайте его на отношение размера микробатча к 2000. Градиенты обнуляйте перед всей группой и обновляйте веса один раз после её обработки.

Совпадение с одним большим батчем возможно при одинаковых примерах и суммируемой по объектам функции потерь. BatchNorm считает статистики отдельно на микробатчах, поэтому нарушает точную эквивалентность; также учитывайте случайные операции и порядок вычислений.


Задача №8

Als, как считается? Как заполнить таблицы в случае ютуба, когда мы хотим увеличить среднее время просмотра?
Что делать, если пользователь просмотрит 99% ролика - он ему понравился или нет?
Как учесть различные факторы - комментарий под видео, лайк, просмотр. (Похоже, сумма факторов с весами.)
Как можно восстановить матрицу с помощью автокодировщиков?
Решение:

ALS (Alternative Least Squares) - это метод коллаборативной фильтрации, используемый для рекомендаций. Он основан на разложении матрицы пользовательских предпочтений на две более низкоранговые матрицы.

Чтобы заполнить таблицы для рекомендаций на YouTube, вам нужно собрать данные о поведении пользователей, такие как просмотры видео, лайки, комментарии и т. д. Если вы хотите увеличить среднее время просмотра, можете использовать различные методы стимулирования пользователей смотреть видео дольше, например, рекомендуя им похожие или продолжающие тему видео, создавая увлекательный контент и т. д.

Когда пользователь просматривает 99% ролика, это может означать, что ему ролик понравился, но это не всегда так. Вам нужно анализировать дополнительные факторы, такие как время просмотра, взаимодействие с другими видео на канале, отзывы и т. д., чтобы сделать более точные предположения о пользовательском опыте.

Автокодировщики (Autoencoders) могут быть использованы для восстановления матрицы пользовательских предпочтений, преобразовав ее в пространство более низкой размерности и затем обратно в исходное пространство. Это позволяет сжать информацию о предпочтениях пользователей, сохраняя при этом их суть.


Задача №9

Есть два вектора в записи вида RLE. Нужно найти скалярное произведение двух векторов.
Решение:

Для вычисления скалярного произведения двух векторов в записи вида RLE (Run-Length Encoding) нужно учитывать только элементы с одинаковыми индексами и их частоты в каждом из векторов.

  1. Преобразуйте векторы из RLE в обычный список, заменяя повторяющиеся элементы и их частоты на соответствующие числа.

  2. Выполните попарное умножение элементов полученных списков.

  3. Произведите суммирование результатов пункта 2.

Пример:

В формате (значение, число повторений) возьмём RLE-векторы [(2, 2), (5, 1), (7, 2)] и [(2, 2), (5, 2), (7, 1)].

  1. Преобразуем векторы в обычный список: [2, 2, 5, 7, 7] и [2, 2, 5, 5, 7].

  2. Выполним попарное умножение: [4, 4, 25, 35, 49].

  3. Суммируем результаты: 4+4+25+35+49=1174 + 4 + 25 + 35 + 49 = 117.

Таким образом, скалярное произведение данных двух векторов равно 117.


Задача №10

сlient_id    sum    day
1    30    2020-04-01
1    12    2020-04-03
1    6    2020-04-04
2    30    2020-04-02
2    15    2020-04-03
2    120    2020-04-04
3    0    2020-04-03
3    3    2020-04-04
3    12    2020-04-05

Сделать в таблице колонку со средней суммой продаж для клиента за три дня:
день в записи, предыдущий и следующий.
Решение:
import pandas as pd

# Входные данные
data = {
    'client_id': [1, 1, 1, 2, 2, 2, 3, 3, 3],
    'sum': [30, 12, 6, 30, 15, 120, 0, 3, 12],
    'day': ['2020-04-01', '2020-04-03', '2020-04-04',
            '2020-04-02', '2020-04-03', '2020-04-04',
            '2020-04-03', '2020-04-04', '2020-04-05']
}

# Преобразование в DataFrame
df = pd.DataFrame(data)

# Преобразование столбца 'day' в тип datetime
df['day'] = pd.to_datetime(df['day'])

# Сортировка данных по 'client_id' и 'day'
df = df.sort_values(by=['client_id', 'day']).reset_index(drop=True)

# Вычисление средней суммы продаж за три дня для каждого клиента
# Усредняем имеющиеся наблюдения от предыдущего до следующего календарного дня.
# В исходной таблице один ряд на клиента и день.
df['rolling_avg'] = [
    df.loc[(df['client_id'] == row.client_id) &
           (df['day'] >= row.day - pd.Timedelta(days=1)) &
           (df['day'] <= row.day + pd.Timedelta(days=1)), 'sum'].mean()
    for row in df.itertuples(index=False)
]

# Вывод результата
print(df)

Задача №11

Мы продаем пиццу и компания хочет организовать акцию, продавать пиццы с 3 начинками по единой цене.
Нам надо рассчитать экономику акции и собрать все варианты начинок с ценой. В одной пицце не может быть 2 одинаковых начинок.
Вывод надо отсортировать по цене (по убыванию) и начинкам в алфавитном порядке. Ингридиенты хранятся в табличке pizza_toppings

+--------------+-----------------+
| topping_name | ingredient_cost |
+--------------+-----------------+
| Pepperoni    | 0.50            |
+--------------+-----------------+
| Mushrooms    | 0.70            |
+--------------+-----------------+
| Chicken      | 0.55            |
+--------------+-----------------+
| Extra Cheese | 0.40            |

Формат вывода

+--------------------------------+------------+
| pizza                          | total_cost |
+--------------------------------+------------+
| Chicken,Pepperoni,Sausage      | 1.75       |
+--------------------------------+------------+
| Chicken,Extra Cheese,Sausage   | 1.65       |
+--------------------------------+------------+
| Extra Cheese,Pepperoni,Sausage | 1.60       |
+--------------------------------+------------+
| Chicken,Extra Cheese,Pepperoni | 1.45       |
Решение:
import itertools
import pandas as pd

# Входные данные
pizza_toppings = {
    'topping_name': ['Pepperoni', 'Mushrooms', 'Chicken', 'Extra Cheese'],
    'ingredient_cost': [0.50, 0.70, 0.55, 0.40]
}

# Преобразование в DataFrame
df_toppings = pd.DataFrame(pizza_toppings)

# Создание всех возможных комбинаций начинок
combinations = list(itertools.combinations(df_toppings['topping_name'], 3))

# Расчет общей стоимости для каждой комбинации
pizza_prices = []
for combo in combinations:
    total_cost = sum(df_toppings[df_toppings['topping_name'] == topping]['ingredient_cost'].values[0] for topping in combo)
    pizza_prices.append((sorted(combo), total_cost))

# Сортировка по убыванию общей стоимости и начинкам в алфавитном порядке
pizza_prices.sort(key=lambda x: (-x[1], x[0]))

# Вывод результатов
print("+--------------------------------+------------+")
print("| pizza                          | total_cost |")
print("+--------------------------------+------------+")
for pizza, total_cost in pizza_prices:
    print(f"| {','.join(pizza):<30} | {total_cost:<10.2f} |")
print("+--------------------------------+------------+")

Задача №12

Даны для LLM, одна на 100к токенов, вторая на 200к
На вход подается один и тот же текст, предобработанный одинаково
Железо для моделей одинаковое
Какая модель даст лучшее качество?
В каком случае вторая модель отработает быстрее первой и почему?

Решение: Для оценки того, какая модель LLM даст лучшее качество, следует провести сравнительный анализ, возможно, на тестовых данных, чтобы оценить их производительность и эффективность. Важно учитывать не только размер словаря, но и различные гиперпараметры моделей, такие как количество слоев, размерность векторного представления, архитектура сети и т. д.

Сначала уточните, что означает 100k и 200k: размер словаря или контекстное окно. Одного этого числа недостаточно для сравнения качества и скорости. При большем словаре токенизатор иногда даёт более короткую последовательность, что может ускорить обработку, но выходной слой становится дороже. Это проверяют измерением на одном тексте и оборудовании.


Задача №13

Есть кубик Рубик разобранный. Кубики разного цвета , размещены в сцене , и нужно определить цвета.
Какими методами мл можно решить задачу . Что делать если есть еще посторонние предметы такого же цвета.

Решение: Для решения задачи определения цветов кубика Рубика можно использовать методы машинного обучения и компьютерного зрения. Вот несколько подходов:

  1. Цветовая сегментация: Можно использовать алгоритмы цветовой сегментации, такие как k-средних или методы на основе порогового значения, чтобы выделить области определенного цвета на изображении. Затем можно использовать классификацию для определения цвета каждой области.

  2. Нейронные сети: Можно обучить сверточную нейронную сеть (CNN) на большом наборе данных изображений кубика Рубика, чтобы классифицировать цвета. CNN может обнаруживать и классифицировать цвета на изображениях с высокой точностью.

  3. Цветовая модель: Можно использовать стандартные цветовые модели, такие как RGB или HSV, чтобы преобразовать цвета пикселей изображения в числовые значения. Затем можно использовать алгоритмы кластеризации, такие как k-средних, для кластеризации пикселей и определения цветов кубика.

  4. Использование дополнительных признаков: Помимо цветовых характеристик, можно использовать другие признаки, такие как форма или текстура кубика Рубика, чтобы более точно определить его цвета.

Что касается посторонних предметов такого же цвета, можно использовать дополнительные признаки или алгоритмы для разделения кубика Рубика и посторонних предметов на изображении. Например, можно использовать алгоритмы сегментации для выделения только кубика Рубика на изображении перед определением его цветов.


Задача №14

Есть КПП в Армению. В Армении N городов, в которых [k1, k2, k3, ..., kN] жителей.
Написать функцию, которая вызывается каждый раз, когда айтишник из России приходит на КПП,
задача функции отправлять айтишников в города так, чтобы изначальное распределение жителей сохранялось.
Число айтишников наперед неизвестно.
Решение:
def make_allocator(population):
    if not population or any(p < 0 for p in population) or sum(population) == 0:
        raise ValueError("population must be non-negative with a positive total")
    assigned = [0] * len(population)
    total = sum(population)
    arrivals = 0

    def allocate():
        nonlocal arrivals
        arrivals += 1
        city = max(range(len(population)),
                   key=lambda i: arrivals * population[i] - total * assigned[i])
        assigned[city] += 1
        return city

    return allocate

# Создайте allocate = make_allocator(population) один раз.
# Вызывайте allocate() для каждого нового человека, результат есть индекс города.
# Точные доли после каждого прихода невозможны из-за целочисленности.

Задача №15

Найти пользователей, которые купили за последний месяц больше 10 кг товаров в совокупностиТаблица A:
user_id | sku (id товара) | dt (дата) | cnt (количество едниц)

Таблица B:
sku (id товара) | weight (масса, кг)
Решение:
SELECT user_id
FROM A
INNER JOIN B ON A.sku = B.sku
WHERE dt >= CURRENT_DATE - INTERVAL '1 month'
GROUP BY user_id
HAVING SUM(cnt * weight) > 10;

Задача №16

Дан текст
"Мама мыла раму"
"Мама любит Анну"
"Анна играет гамму"

Посчитать tf-idf второго предложения.

Решение: Чтобы посчитать TF-IDF для второго предложения, нужно сначала разделить текст на отдельные слова, затем вычислить TF (term frequency) и IDF (inverse document frequency) для каждого слова, а затем перемножить их. Например, TF можно посчитать как количество вхождений слова “Мама” во втором предложении, деленное на общее количество слов во втором предложении. IDF вычисляется по формуле, которая учитывает количество предложений и количество предложений, в которых встречается данное слово. После этого TF и IDF перемножаются.

Таким образом, для второго предложения “Мама любит Анну”:

  • TF для слова “Мама” равен 1/3

  • TF для слова “любит” равен 1/3

  • TF для слова “Анну” равен 1/3

Для вычисления IDF нужно знать общее количество предложений (3) и количество предложений, в которых встречается каждое слово:

  • IDF для слова “Мама” равен log(3/2)

  • IDF для слова “любит” равен log(3/1)

  • IDF для слова “Анну” равен log(3/1)

Затем TF и IDF перемножаются отдельно для каждого термина:

  • TF-IDF для слова “Мама” = (1/3) * log(3/2)

  • TF-IDF для слова “любит” = (1/3) * log(3/1)

  • TF-IDF для слова “Анну” = (1/3) * log(3/1)

Результат для предложения представляет вектор весов терминов. Суммирование весов в один скаляр не является стандартным TF-IDF-представлением документа.

Эта страница была полезной?