---
title: Лайфкодинг ML
seo:
  title: Лайфкодинг ML — Data Scientist
  description: Тема «Лайфкодинг ML» для собеседования Data Scientist. Задача №1. Задача №2.
---

[Все темы Data Scientist](/data-scientist)

### ⌨️ Задачи

---

## <strong>Задача №1</strong> [#q-14bee738d69b8161845bef9ea10c92e3]

```text
Ручные признаки для анализа изображений
Помимо использования глубокого обучения, часто для решения задач приходится самому придумывать признаки.
На вход Вам дана черно-белая картинка в виде матрицы, где 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), который позволит нам найти все связанные черные пиксели в матрице. Мы будем проходить по каждому пикселю в матрице и, если встречаем черный пиксель, начнем обходить все смежные черные пиксели, чтобы образовать один кластер.

```python
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
```

---

## <strong>Задача №2</strong> [#q-14bee738d69b815eaa3bf3428c9b1dc3]

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

Для оценки средних значений precision и recall для наивной модели, предполагающей, что вероятность случайного выбора дефолтного наблюдения составляет <strong>60%</strong>, мы можем использовать следующие формулы&#58;

$$
Precision = \frac{TP} {(TP + FP)}
$$

$$
Recall = \frac{TP} {(TP + FN)}
$$

Где&#58;

- <code>TP &#40;True Positives&#41;</code> - количество дефолтных наблюдений,
  которые были правильно классифицированы как дефолтные.

- <code>FP &#40;False Positives&#41;</code> - количество не-дефолтных
  наблюдений, которые были ошибочно классифицированы как дефолтные.

- <code>FN &#40;False Negatives&#41;</code> - количество дефолтных наблюдений,
  которые были ошибочно классифицированы как не-дефолтные.

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

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

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

---

## <strong>Задача №3</strong> [#q-14bee738d69b81d28df6dbc45f24eca4]

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

<strong>Решение&#58;</strong>

```python
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())
```

---

## <strong>Задача №4</strong> [#q-14bee738d69b812ea660eef0c30d071c]

```python
Дано: датасет N нулей, M единиц.
Нужно минимизировать логлосс: - sum_i(t_i * log(p) + (1-t_i) * log(1-p)) по отношению к p.
```

<strong>Решение&#58;</strong>

```python
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)
```

---

## <strong>Задача №5</strong> [#q-14bee738d69b810fab3cc5b171b3e9ef]

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

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

<strong>Решение&#58;</strong>

Для решения этой задачи мы можем воспользоваться формулой Байеса. Пусть событие <InlineMath tex={"C"} /> - это выбор картинки с котиком, а событие <InlineMath tex={"A"} /> - это ответ разметчика о том, что на картинке изображен котик.

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

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

Где&#58;

- <InlineMath tex={"P(C|A)"} /> - вероятность того, что выбрана картика с
  котиком при условии, что разметчик ответил, что это котик (искомая нами
  вероятность).

- <InlineMath tex={"P(A|C)"} /> - вероятность того, что разметчик ответил, что
  на картинке котик, при условии, что на самом деле на картинке котик. По
  условию задачи, это равно навыку разметчика, то есть
  <InlineMath tex={"P(A|C) = 0.9"} />.

- <InlineMath tex={"P(C)"} /> - вероятность того, что на случайно выбранной
  картинке изображен котик. По условию задачи, котиков в наборе данных всего
  <strong>10%</strong>, то есть <InlineMath tex={"P(C) = 0.1"} />.

- <InlineMath tex={"P(A)"} /> - общая вероятность того, что разметчик ответил,
  что на картинке котик. Это сумма вероятности того, что разметчик ответил, что
  на картинке котик, при условии того, что на самом деле там котик, и
  вероятности того, что разметчик ответил, что на картинке котик, при условии
  того, что на самом деле там собачка, то есть
  <InlineMath
    tex={
      "P(A) = P(A|C) \\cdot P(C) + P(A|\\overline{C}) \\cdot P(\\overline{C})"
    }
  />
  , где <InlineMath tex={"\\overline{C}"} /> обозначает событие "на картинке
  собачка".

Теперь мы можем вычислить вероятность <InlineMath tex={"P(C|A):"} />

$$
P(A)=0.9⋅0.1+0.1⋅0.9=0.09+0.09=0.18
$$

$$
P(C∣A)= \frac{P(A∣C)⋅P(C)}{P(A)}
$$

$$
P(C∣A)=\frac{0.09}{0.18}=0.5
$$

<strong>Ответ&#58; 0.5.</strong>

---

## <strong>Задача №6</strong> [#q-14bee738d69b8187b4f3eb160755e879]

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

<strong>Решение&#58;</strong>

```python
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)  # Вернуть класс с наибольшим количеством голосов
```

---

## <strong>Задача №7</strong> [#q-14bee738d69b81009ba7c0d1148a76a3]

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

<strong>Решение&#58;</strong>

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

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

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

---

## <strong>Задача №8</strong> [#q-14bee738d69b8104b1c8f0857d548fc1]

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

<strong>Решение&#58;</strong>

<code>ALS</code> <code>&#40;Alternative Least Squares&#41;</code> - это метод
коллаборативной фильтрации, используемый для рекомендаций. Он основан на
разложении матрицы пользовательских предпочтений на две более низкоранговые
матрицы.

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

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

<code>Автокодировщики</code> <code>&#40;Autoencoders&#41;</code> могут быть
использованы для восстановления матрицы пользовательских предпочтений,
преобразовав ее в пространство более низкой размерности и затем обратно в
исходное пространство. Это позволяет сжать информацию о предпочтениях
пользователей, сохраняя при этом их суть.

---

## <strong>Задача №9</strong> [#q-14bee738d69b81758460d421ddcf6306]

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

<strong>Решение&#58;</strong>

Для вычисления скалярного произведения двух векторов в записи вида <code>RLE &#40;Run&#45;Length Encoding&#41;</code> нужно учитывать только элементы с одинаковыми индексами и их частоты в каждом из векторов.

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

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

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

<strong>Пример&#58;</strong>

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

1. Преобразуем векторы в обычный список&#58; <code>&#91;2&#44; 2&#44; 5&#44; 7&#44; 7&#93;</code> и <code>&#91;2&#44; 2&#44; 5&#44; 5&#44; 7&#93;</code>.

1. Выполним попарное умножение&#58; <code>&#91;4&#44; 4&#44; 25&#44; 35&#44; 49&#93;</code>.

1. Суммируем результаты&#58; <InlineMath tex={"4 + 4 + 25 + 35 + 49 = 117"} />.

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

---

## <strong>Задача №10</strong> [#q-14bee738d69b8101b1b0e0e7bd54397d]

```python
с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

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

<strong>Решение&#58;</strong>

```python
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)
```

---

## <strong>Задача №11</strong> [#q-14bee738d69b81d4a960ce3cd6bb01d0]

```text
Мы продаем пиццу и компания хочет организовать акцию, продавать пиццы с 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       |
```

<strong>Решение&#58;</strong>

```python
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("+--------------------------------+------------+")
```

---

## <strong>Задача №12</strong> [#q-14bee738d69b81eaa444edbb2d882d79]

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

<strong>Решение&#58;</strong>
Для оценки того, какая модель <code>LLM</code> даст лучшее качество, следует
провести сравнительный анализ, возможно, на тестовых данных, чтобы оценить их
производительность и эффективность. Важно учитывать не только размер словаря, но
и различные гиперпараметры моделей, такие как количество слоев, размерность
векторного представления, архитектура сети и т. д.

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

---

## <strong>Задача №13</strong> [#q-14bee738d69b818983c8fe309e637a52]

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

<strong>Решение&#58;</strong>
Для решения задачи определения цветов кубика Рубика можно использовать методы
машинного обучения и компьютерного зрения. Вот несколько подходов&#58;

1. <strong>Цветовая сегментация</strong>&#58; Можно использовать алгоритмы
   цветовой сегментации, такие как <code>k&#45;средних</code> или методы на
   основе порогового значения, чтобы выделить области определенного цвета на
   изображении. Затем можно использовать классификацию для определения цвета
   каждой области.

1. <strong>Нейронные сети</strong>&#58; Можно обучить сверточную нейронную сеть
   <code>&#40;CNN&#41;</code> на большом наборе данных изображений кубика
   Рубика, чтобы классифицировать цвета. <code>CNN</code> может обнаруживать и
   классифицировать цвета на изображениях с высокой точностью.

1. <strong>Цветовая модель</strong>&#58; Можно использовать стандартные цветовые
   модели, такие как <code>RGB</code> или <code>HSV</code>, чтобы преобразовать
   цвета пикселей изображения в числовые значения. Затем можно использовать
   алгоритмы кластеризации, такие как <code>k&#45;средних</code>, для
   кластеризации пикселей и определения цветов кубика.

1. <strong>Использование дополнительных признаков</strong>&#58; Помимо цветовых
   характеристик, можно использовать другие признаки, такие как форма или
   текстура кубика Рубика, чтобы более точно определить его цвета.

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

---

## <strong>Задача №14</strong> [#q-14bee738d69b81ba861cddf29ec90484]

```text
Есть КПП в Армению. В Армении N городов, в которых [k1, k2, k3, ..., kN] жителей.
Написать функцию, которая вызывается каждый раз, когда айтишник из России приходит на КПП,
задача функции отправлять айтишников в города так, чтобы изначальное распределение жителей сохранялось.
Число айтишников наперед неизвестно.
```

<strong>Решение&#58;</strong>

```python
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() для каждого нового человека, результат есть индекс города.
# Точные доли после каждого прихода невозможны из-за целочисленности.
```

---

## <strong>Задача №15</strong> [#q-14bee738d69b81f5922affae1e2fa078]

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

Таблица B:
sku (id товара) | weight (масса, кг)
```

<strong>Решение&#58;</strong>

```sql
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;
```

---

## <strong>Задача №16</strong> [#q-14bee738d69b8102a1c3c11a7167c419]

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

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

<strong>Решение&#58;</strong>
Чтобы посчитать <code>TF&#45;IDF</code> для второго предложения, нужно сначала
разделить текст на отдельные слова, затем вычислить <code>TF</code> (term
frequency) и <code>IDF</code> (inverse document frequency) для каждого слова, а
затем перемножить их. Например, <code>TF</code> можно посчитать как количество
вхождений слова "Мама" во втором предложении, деленное на общее количество слов
во втором предложении. <code>IDF</code> вычисляется по формуле, которая
учитывает количество предложений и количество предложений, в которых встречается
данное слово. После этого <code>TF</code> и <code>IDF</code> перемножаются.

Таким образом, для второго предложения "Мама любит Анну"&#58;

- <code>TF</code> для слова "Мама" равен 1/3

- <code>TF</code> для слова "любит" равен 1/3

- <code>TF</code> для слова "Анну" равен 1/3

Для вычисления <code>IDF</code> нужно знать общее количество предложений (3) и количество предложений, в которых встречается каждое слово&#58;

- <code>IDF</code> для слова "Мама" равен log(3/2)

- <code>IDF</code> для слова "любит" равен log(3/1)

- <code>IDF</code> для слова "Анну" равен log(3/1)

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

- <code>TF&#45;IDF</code> для слова "Мама" = (1/3) \* log(3/2)

- <code>TF&#45;IDF</code> для слова "любит" = (1/3) \* log(3/1)

- <code>TF&#45;IDF</code> для слова "Анну" = (1/3) \* log(3/1)

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