Загрузка данных


День 06. «Смотря как посчитать»
ОБРАТНЫЙ КАНАЛ · ВХОДЯЩИЙ ПАКЕТ

отправлено 2030

принято сегодня 06:51

адресат ты.

размер 1 024 из 2 048 байт

контр. сумма 7f3a19c4 сошлась

сегмент 1 из 2 · второй в буфере приёмника

Привет! Вот и пройдены 4 голодных дня без интернета и доступа к ИИ, сдан первый экзамен… Теперь приступай к самому главному. Тебе предстоит попробовать 7 профессий из будущего.
Каждый проект — это практические задачи из жизни специалиста в профессии. «Голодные дни» закончились, теперь ты можешь пользоваться искусственным интеллектом и поиском. Хотя…

Даже удивительно сейчас вспоминать, как люди из твоего времени не умели работать с ИИ. Кто-то воспринимал все сказанное за истину… Кто-то не проверял факты и данные из чата… Кто-то брал в работу первое, что выдаст машина. Но с ним так нельзя.

Я хочу помочь. Поэтому передам тебе важнейший навык и правила работы с искусственным интеллектом из будущего.

Этот навык называется AI literacy — цифровая компетентность в сфере ИИ.

img1

Используй AI literacy и станешь специалистом вне конкуренции в любой сфере.

Всегда проясняй цель, для чего ты даешь ИИ какую-либо задачу. Пиши, что предшествовало задаче, для кого ты это делаешь, чего хочешь — ВСЕ.
Давай ИИ образцы и примеры, что ты хочешь видеть в результате. Ответ в виде презентации или документа? Какие использовать цвета? Покажи, если есть на что ориентироваться.
Никогда — слышишь! — никогда не принимай первый ответ чата с искусственным интеллектом или от ии-агента. Достойный ответ или результат появляются раза с 4, как МИНИМУМ. Вчитывайся в каждую строчку. Критикуй! Спрашивай, почему так. Спорь: «А я вижу по-другому».
Проверяй каждый факт и каждую цифру. ИИ — известный фантазер.
Пользуйся функцией Deep Research и Plan. Сначала найди все, что известно человечеству, о твоей задаче. Спланируй, как это интегрировать в то, что ты хочешь получить от ИИ. А потом уже что-то с этим делай.
Если задача повторяется больше 2-3 раз, а уж тем более, если чаще 3-х раз в месяц, не пиши ее просто в чат. Создай НАВЫК — в некоторых нейронках это называется SKILL. Навык — это алгоритм, которому ИИ должен следовать каждый раз по подобной задаче.
Если задача повторяется еще чаще и случается, что ты не у компьютера, и хочешь делать что-то со смартфона, проще создать ИИ-агента, и наделить нужным навыком его.
Некоторые модели позволяют вызывать субагентов в рамках одного чата. Если задача объемная и на нее нужно посмотреть с разных сторон, так и скажи: вызови субагентов, которые лучше всего подходят для этой задачи, сам стань приемщиком их работы, раздели между ними работу как грамотный руководитель. И посмотри, что произойдет…
Собирай контекст о своей жизни и проектах в одном месте, желательно — локально у себя на личном компьютере. Это можно делать с помощью папок. Знаешь, в будущем люди что только о себе не собирают, чем только не делятся с искусственным интеллектом. Имея отдельную папку по конкретному проекту, ты сможешь дать некоторым моделям доступ в эту папку и дать любую задачу.
Обновляй контекст о своих проектах и задачах регулярно. Можно записывать и собирать в папку новые рабочие звонки или их расшифровки, складывать туда новые файлы. Конечно, в рамках политики кибербезопасности и контура твоей компании.
Получая любой результат от ИИ, попробуй использовать 4 промта в ответ (последовательность не важна): — рассмотри эту задачу группой экспертов, которые лучше всего для этого подходят; — оцени свою работу (свой ответ) от 0 до 100 и доведи до 95; — напиши список неочевидного; — найди все возможные ошибки в своей работе, особенно ошибки с последствиями.
Убирай из работы от ИИ признаки работы ИИ. Любой документ, презентация или текст, полный признаков его работы, называется нейрослоп. Приносить коллегам нейрослоп в будущем также стыдно, как вообще не пользоваться нейросетями.
Признаки нейрослопа
Аналитики в будущем — не те, кто делают типовые отчеты и механические выгрузки… Ага! Ловушка?! Заметен нейрослоп?! Аналитики в будущем — те, кто умеют понимать: что именно нужно измерить, можно ли доверять результату, а главное, превращать неоднозначные данные в обоснованные решения. Этим и займемся. Ситуация.

💡 1 апреля на первой линии поддержки запустили базу знаний и бота. Типовые вопросы теперь закрываются автоматически и не доходят до специалистов. Прошло три месяца. Руководство хочет расширить автоматизацию на вторую линию и просит подтвердить, что решение сработало и стало лучше. Что такое «лучше», никто не уточнил.
Второй линии пока нет. Все обращения разбирает первая линия - специалисты широкого профиля. Вторую линию собираются создать для обращений, где нужны узкие знания и полномочия: юридические вопросы, жалобы, возвраты. Её никто не тестировал, и главный вопрос - кто встретит такие обращения первым: бот или человек.
Данных, кроме выгрузки из тикет-системы, нет. Выгрузку никто специально не готовил - её сделали нажатием одной кнопки и не перепроверяли. Какие там стояли фильтры, уже не узнать.
Будущий руководитель второй линии - технонигилист и не верит в пользу автоматизации. Свой вывод ты понесёшь именно ему.

Сегодня ты аналитик. Твоя задача - выяснить, что на самом деле говорят данные, и защитить свой вывод перед человеком, который в него не верит.

Старт работы

Весь SQL на сегодня
Задание 1. Кто работает на первой линии
Задание 2. Сколько людей и сколько времени
Задание 3. Паспорт выгрузки
Задание 4. Кого бы отправили на вторую линию
Задание 5. Как бот справляется с каждым блоком
Задание 6. Аналитическая записка
Задание 7. Разбор системы по модели «Айсберг»
Задание 8 Bonus. Чистка своими руками
Чек-поинт

Старт работы
🚀 Экзамен сдан. Поздравляем, ещё один этап позади!
Поделись, как всё прошло: что понравилось, а что хотелось бы улучшить.
Нажми сюда так твоя обратная связь поможет сделать экзамен лучше.

Как учиться в «Школе 21»
Как работать с проектом
Материалы
Весь SQL на сегодня
Предполагаем, что SQL ты видишь впервые. Для всех обязательных заданий хватит 6-ти конструкций и одного приёма - подробно и с примерами в materials/sql_start_rus.md:

Конструкция	Что делает	Пример
SELECT … FROM …	взять поля из таблицы	SELECT topic, priority FROM clean LIMIT 5
WHERE	оставить только подходящие строки	WHERE period = 'после' AND written = 1
ORDER BY	отсортировать	ORDER BY 2 DESC
COUNT, SUM, AVG, MIN, MAX, ROUND	посчитать	COUNT(*), COUNT(DISTINCT client_id), ROUND(AVG(handle_min), 1)
GROUP BY	посчитать отдельно по каждой группе	GROUP BY topic
HAVING	оставить только нужные группы	HAVING COUNT(*) > 100
Кто знает SQL лучше - для тех бонусное Задание 8.

Задание 1. Кто работает на первой линии
Работай со справочником data/agents.csv. Первая линия работает в 3 смены, людей в ней немного - начни с них.

Открой src/ex01.py. Там уже есть код, который создаёт таблицу agents и загружает в неё CSV - прочитай комментарии, это та же схема, по которой собирается большая таблица в src/db.py. Там же - первый запрос как пример.

Что сделать. Допиши запросы 2–5:

Первые 3 сотрудника: логин и смена (уже написан).
Количество строк в справочнике.
3 сотрудника, нанятых раньше всех: логин и дата найма.
Количество строк по каждой смене, по алфавиту названий.
Сотрудники, нанятые в 2025 году: логин и дата найма.
Ожидаемый вывод python3 src/ex01.py:

1. Первые три сотрудника
('ivan_p', 'дневная смена')
('anna_k', 'дневная смена')
('pavel_m', 'дневная смена')
2. Количество строк в справочнике
(20,)
3. Три сотрудника, нанятых раньше всех
('svetlana_l', '2021-12-01')
('yulia_c', '2022-04-25')
('sergey_d', '2022-08-22')
4. Количество строк по каждой смене
('вечерняя смена', 6)
('дневная смена', 9)
('ночная смена', 5)
5. Сотрудники, нанятые в 2025 году
('artem_f', '2025-01-20')
('igor_h', '2025-06-16')
Обрати внимание: мы пишем строк, а не сотрудников. Почему - выяснишь в Задании 2.

Результат: src/ex01.py

Задание 2. Сколько людей и сколько времени
Руководитель второй линии первым делом спросит две вещи: сколько у вас людей и сколько времени они тратят на одно обращение. На оба вопроса легко ответить неправильно — и после этого тебя уже не будут слушать.

Ещё в SQLite не хватает двух инструментов, без которых дальше не обойтись: медианы и нижнего регистра для русских букв. Их ты напишешь самостоятельно.

Работаешь в src/ex02.py. База подключается строкой con = connect(), в ней уже есть справочник agents, сырая выгрузка tickets и очищенная таблица clean.

Что сделать:

Сколько людей на первой линии. Сравни число строк в справочнике и число разных сотрудников (COUNT(*) и COUNT(DISTINCT login)). Если они разные — найди запросом строку, из-за которой так вышло. На сколько можно ошибиться, если назвать штат по числу строк?
Из каких смен некого забрать. Вторую линию будут собирать из людей первой. Покажи смены, где меньше шести человек: там уход даже одного уже заметен. Считай людей, а не строки. Понадобятся GROUP BY и HAVING.
Сколько обращений пришло через чат. Сгруппируй сырую выгрузку tickets по каналу, приведённому к нижнему регистру встроенной функцией lower(), и посмотри на результат. Потом напиши свою функцию unicode_lower, зарегистрируй её в базе и сгруппируй ещё раз. Сколько обращений в чате на самом деле? Если в поле NULL, в функцию придёт None — она должна вернуть None и не упасть.
Сколько времени люди тратят на обращение. Напиши класс Median — свою агрегатную функцию MEDIAN. Посчитай по таблице clean за время до 1 апреля (period = 'до', тогда работали только люди) среднее и медиану времени обработки handle_min. Почему они так расходятся? Какое число ты назовёшь руководителю? Ответь одной строкой в комментарии в коде.
Проверь свой инструмент. Прежде чем нести числа руководителю, убедись, что MEDIAN считает правильно. Достань те же значения запросом, посчитай медиану на Python (statistics.median) и напечатай оба числа в одной строке. Они должны совпасть.
Встроенную median() не используй, даже если она есть в твоей версии SQLite. В стандартной сборке SQLite lower() меняет только латиницу. В некоторых сборках (с расширением ICU) он работает и с кириллицей — проверь у себя. Своя функция нужна, чтобы запрос давал один и тот же результат на любой машине.

Как устроена своя агрегатная функция — в materials/sql_start_rus.md, раздел «Свои функции». В шаблоне уже есть заготовка класса: осталось дописать 2 метода.

Ожидаемый вывод python3 src/ex02.py. Заголовки можешь сформулировать по-своему. В пункте 1a запрос может выводить другие поля — главное, чтобы из вывода было видно, какая строка лишняя:

1. Строк в справочнике и людей
(20, 19)
1a. Какая строка лишняя
('1', 'ivan_p', 'дневная смена', '2024-03-12', 2)
2. Смены, где меньше 6 человек
('ночная смена', 5)
3. Каналы в сырой выгрузке: lower()
('Чат', 163)
('почта', 1635)
('телефон', 1654)
('форма', 870)
('чат', 2711)
3a. Каналы в сырой выгрузке: unicode_lower()
('почта', 1635)
('телефон', 1654)
('форма', 870)
('чат', 2874)
4. Время обработки до апреля: среднее и медиана
(29.7, 16)
5. Медиана: SQL и Python
16 16
Результат: src/ex02.py

Задание 3. Паспорт выгрузки
Прежде чем что-то доказывать, пойми, что тебе выгрузили. Твой собеседник первым делом спросит: «А вы уверены в своих данных?» - ответ должен быть готов.

У тебя две таблицы с одними и теми же обращениями:

tickets - выгрузка как есть, со всей грязью;
clean - та же выгрузка после чистки, которую сделал коллега-аналитик. Он ушёл в отпуск и ничего не объяснил. Описание полей clean - в начале src/db.py.
Твоя задача - выяснить, что было не так с выгрузкой, что коллега исправил, и не ошибся ли он сам. Все запросы - простые: посчитать и сгруппировать.

Сырые данные и чистка

1. Сколько строк в tickets, сколько в ней разных номеров обращений (COUNT(DISTINCT id)) и сколько строк в clean? Куда делись строки?

2. Сгруппируй по каналу tickets и clean. Что коллега исправил?

3. Сгруппируй по теме tickets и clean. Как в сырых данных записана пустая тема? Что сделал коллега? Всё ли он исправил?

4. Сколько строк в tickets, где дата создания записана в формате ДД.ММ.ГГГГ (WHERE created_at LIKE '__.__.____%'), и сколько в другом формате? Сколько обращений "после 1 апреля" получится, если сравнить даты в tickets как есть (WHERE created_at >= '2025-04-01'), и сколько - по полю period в clean? Почему числа разные? Какой период охватывает выгрузка?

Пустые значения

5. Сколько обращений бот закрыл сам и у скольких из них нет сотрудника (agent_id IS NULL)? Что значит пустой сотрудник? Что случилось с обращением? Что стало с остальными?

Нумерация

6. Номера обращений сквозные: каждое новое получает следующий номер. Почти.

Бот

7. В каких каналах работает бот? Сколько он закрыл сам и сколько передал человеку?

8. Какое время первого ответа (first_reply_min, медиана или среднее) было до и после апреля? Можно ли по этому числу судить о работе людей? На что опираться? На среднее или на медиану?

Возвраты

9. Сколько обращений переоткрыто (reopened) и после скольких был возврат (came_back) - тот же клиент с той же темой в течение 7 дней? Чем одно отличается от другого?

Справочник

10. Сколько обращений вёл каждый сотрудник (GROUP BY agent_id)? Сколько обращений без сотрудника? Есть ли в справочнике agents сотрудник без обращений? Как записан номер сотрудника в clean и в agents?

Промежуточный вывод. В конце ex03.md - три утверждения, которые нельзя сделать по этой выгрузке сразу, хотя очень хочется. У каждого - число, которое это показывает. Например: "первый ответ стал в сто раз быстрее" - почему так говорить нельзя?

Проверь себя: python3 src/run_sql.py src/ex03.md выполнит все запросы и напечатает результат рядом с твоим ответом. Контрольная точка: в tickets 7033 строки, в clean - 6760.

Заполняй по одному вопросу и коммить по мере продвижения.

Результат: src/ex03.md

Задание 4. Кого бы отправили на вторую линию
Второй линии нет, но обращения для неё уже приходят - сейчас их разбирает первая линия. Прежде чем смотреть, как с ними справляется бот, реши, какие обращения вообще относятся ко второй линии.

Однозначного ответа нет. Какие-то обращения - точно первая линия: их решают за несколько минут по инструкции. Какие-то - точно вторая: долго, нужны узкие знания. А часть - серая зона: можно отнести и туда, и туда. От того, куда ты её отнесёшь, будет зависеть вывод.

Смотри на данные до 1 апреля (period = 'до'): тогда все обращения разбирали люди, и видно, сколько сил на что уходит.

Посмотри на: время обработки по темам (src/ex04.md посчитай медиану (MEDIAN, или AVG, если Задание 2 не сделано) // тема и приоритет // возвраты и переоткрытия по темам

Разметка.

Открой src/razmetka.csv - таблицу-решение: 30 строк, по строке на каждое сочетание темы и приоритета. В колонке blok для каждой строки напиши первая, серая или вторая, в колонке comment - коротко почему. Можно править в любом редакторе или в LibreOffice Calc (сохраняй как CSV в UTF-8)

Размер блоков. Сколько обращений в каждом блоке до и после апреля (SELECT period, blok, COUNT(*) FROM razmetka GROUP BY period, blok). Не должно остаться не размечено.

Промежуточный вывод. В конце ex04.md: сколько обращений в месяц пришлось бы на вторую линию и сколько - на серую зону, в штуках и процентах. По какому признаку ты провёл границу и каким числом из данных до апреля это подтверждается.

Закоммить razmetka.csv и ex04.md до того, как начнёшь Задание 5, с сообщением разметка. На защите проверяющий посмотрит git log: разметка должна появиться раньше, чем результаты бота. Менять её потом можно, но тогда в записке честно напиши, что поменял и почему.

Проверка: python3 src/run_sql.py src/ex04.md.

Результат: src/ex04.md, src/razmetka.csv

Задание 5. Как бот справляется с каждым блоком
Теперь смотришь на обращения после 1 апреля в письменных каналах (period = 'после' AND written = 1) - там, где работает бот, - и сравниваешь их с теми же блоками до апреля, когда работали только люди. Все запросы - к таблице razmetka, по одному шаблону: WHERE выбирает, кого сравнивать, GROUP BY blok делит по блокам, AVG(условие) даёт долю.

Что сделать в src/ex05.md:

1. Доля закрытых ботом по блокам.

2. Решено с первого обращения по флагу. Решённым с первого раза считаем обращение, которое не переоткрыто: AVG(reopened = 0). По каждому блоку три числа: люди до апреля, все обращения после апреля, только закрытые ботом.

3. Решено с первого обращения с учётом возвратов. Решённым считаем обращение, которое не переоткрыто и после которого не было возврата: AVG(reopened = 0 AND came_back = 0). Те же три числа. Сравни с пунктом 2. Какое определение ты возьмёшь для вывода и почему? Что каждое из них видит и чего не видит?

4. Контроль. В телефоне (written = 0) бота нет. Посчитай то же для телефона до и после апреля. Зачем это сравнение?

5. Два сценария. Как бот справляется со "второй линией", если: - серую зону отнести ко второй линии: WHERE blok IN ('вторая', 'серая'); - серую зону отнести к первой: WHERE blok = 'вторая'.

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

6. Бот → бот → человек. Сколько обращений второй линии бот закрыл, а клиент вернулся в течение 7 дней (came_back = 1)? Сколько из этих возвратов бот снова закрыл (next_bot_result = 'закрыл')?

Позиция - промежуточный вывод. Выбери одну и запиши одной фразой

А. "Бот справится и со второй линией". Цепочка бот → бот → человек: бот первой линии, потом бот второй линии, человек - если оба не справились.
Б. "Бот - для первой линии, на второй - люди". Цепочка бот → человек: всё, что сложнее первой линии, бот сразу передаёт человеку.
Обе позиции можно защитить на этих данных - правильного ответа нет. Решает то, как ты определил серую зону, сможешь ли доказать, что определил её правильно, и что ты ответишь на сомнения в materials/acceptance_rus.md.

Проверка: python3 src/run_sql.py src/ex05.md.

Результат: src/ex05.md

Задание 6. Аналитическая записка
Будущий руководитель второй линии не откроет ни выгрузку, ни твои запросы. Он прочитает записку, и если вывод его не убедит, полезет в данные сам. Записка - то, чем ты защищаешь своё решение и вывод.

Что сделать в src/ex06.md - не больше 2-х страниц, разделы строго в этом порядке:

Вывод. Позиция (А или Б), одна фраза и одно число.
Как получено. На каких обращениях считал, как размечал и размер серой зоны - сколько обращений и какая это доля. Что сделал с ошибкой коллеги.
Два сценария. Таблица из задания 5: что будет с главным числом, если серую зону отнести иначе.
Что говорит против. Самое сильное возражение против твоего вывода - с числом - и твой ответ на него.
Чего не хватает. Каких данных нет и на какой вопрос они бы ответили. Что значат пропущенные номера обращений для твоего вывода.
График. Один график, который показывает именно то, на чём держится вывод. Рисовать не нужно: в src/ex06_chart.py впиши запросы, заголовок и подпись оси - скрипт нарисует сам. Картинку вставь в записку: ![график](https://git.21-school.ru/masters/D6_Dataquery.ID_1578343/-/blob/3/ex06_chart.png).
Главное число. Запрос, который дал число из раздела "Вывод", - в блоке ```sql под заголовком ### Главное число. Проверяющий запустит его так: python3 src/run_sql.py src/ex06.md "Главное число".
Если matplotlib не установлен: pip3 install --user matplotlib.

Результат: src/ex06.md, src/ex06_chart.py, src/https://git.21-school.ru/masters/D6_Dataquery.ID_1578343/-/blob/3/ex06_chart.png