Генерация синтетических данных
Mikhail KolcharЗачем вообще генерировать данные?
Всем привет! :)
Как часто вам приходится генерировать какие-то данные? Бывает так, что создание синтетических данных просто необходимо. Например, для заполнения пропусков в датасете.
Кто-то скажет, что лучше удалить все пропуски и будь, что будет! Но это может привести к нежелательным последствиям.
Например, если удалять строки, то мы можем потерять большой объем данных или это может внести различного рода смещение (если пропуски не случайны). А если удалять столбцы, то мы можем потерять потенциально полезный признак для анализа.
Поэтому сначала смотрят каков процент пропусков и уже потом решают, что с ним делать. Может и действительно, легче удалить 15 строк из 10000, чем возиться с ними.
Что же делать с пропусками, которые не хочется удалять?
Самый распространенный пример - это замена пропусков статистическими показателями. Это может быть среднее значение, медиана или мода (часто встречающееся значение, обычно используется для категориальных данных).
Или можно просто заменить простой константой (например 0 или -1), предыдущим значением, или каким-нибудь образом интерполировать исходя из остальных значений.
А можно сгенерировать данные, подчиняющееся необходимым нам правилам.
Совсем немного про генерацию
Изучающие python, уверен, прекрасно знают модуль rnd для генерации. Но я, выполняя один учебный проект, наткнулся на интересную библиотеку faker, которая умеет генерировать не только числа, но и много всего интересного.
Сначала стандартная установка модуля:
pip install faker
И простейший пример его использования:
И вот, вооружившись faker-ом и random-ом, я пошёл выполнять проект по генерации чеков продуктовых магазинов =)
Если кому интересны исходники, то оставлю ссылку на гитхаб.
! Небольшое примечание: данный код, конечно же, можно улучшать как вам хочется, я просто привожу пример, как я это сделал.
Описание задачи
Представьте, что вы работаете в крупной тороговой сети и продаете товары для дома - бытовую химию, текстиль, кухонную утварь и так далее. Каждый день из кассового софта в специально созданную папку на сервере выгружается набор csv-файлов с информацией по чекам и продажам. Ваша задача - автоматизировать обработку этих данных (а также написать скрипт для их генерации, чтобы эмулировать работу кассовой программы).
Ниже приводим все пункты, которые вы должны реализовать в рамках этой работы:
- Напишите скрипт, который генерирует N (кол-во магазинов) выгрузок в формате csv в папку data/. Формат выгрузки будет указан ниже.
- Автоматизируйте этот скрипт так, чтобы он работал каждый день, кроме воскресенья. Вы можете это сделать с помощью того инструмента, который вам удобен - cron или планировщик Windows (зависит от вашей операционной системы).
- Создайте базу данных для хранения этих данных.
- Напишите скрипт, который будет забирать данные из этой папки и заносить их в базу данных. Учтите, что в папке могут находиться и лишние файлы - игнорируйте их.
- Автоматизируйте этот скрипт, чтобы он работал каждый день.
Файлы с выгрузками должны называться {{shop_num}}_{{cash_num}}.csv. Здесь {{shop_num}} - номер магазина, а {{cash_num}} - номер кассы. В одном магазине может быть много касс - у каждой своя выгрузка. Пример названия: 11_2.csv - 11 магазин, 2 касса.
Формат выгрузки:
- doc_id - численно-буквенный идентификатор чека
- item - название товара
- category - категория товара (бытовая химия, текстиль, посуда и т.д.)
- amount - кол-во товара в чеке
- price - цена одной позиции без учета скидки
- discount - сумма скидки на эту позицию (может быть 0)
Как я синтезировал данные
Не буду вдаваться в подробности всего кода, заострю внимание только на фрагментах кода, где сами данные генерируются.
Для начала я определил, что это будет продуктовые магазины со следующими категориями товаров:
Затем (признаюсь, немного костыльно, но ладно) написал функцию генерации "Уникального товара". Я немного сокращу код, но смысл должен быть понятен.
Написал отдельную функцию по генерации цены. Здесь я тоже сокращу.
Как вы заметили, я не стал использовать обычный рандом, а решил воспользоваться функцией rnd.choice(), чтобы цены были "более достоверными". И вычел из них 1 копейку, чтобы уж вообще было супер "достоверно". Так Яйцо может стоить 69.99, 89.99 или 109.99.
Так, с товарами плюс-минус разобрались, теперь сгенерируем время покупок!
Остался предпоследний шаг - генерация одного чека!
И последний шаг! Теперь берём и генерируем большущую кучу чеков на каждый (их у меня 12 штук) магазин на каждую кассу (у меня по 4 кассы в каждом магазине).
Вот итоговый результат работы всего скрипта:
Затем остаётся только обработать получившиеся csv-файлики с чеками и выгрузить их в какую-нибудь БД и что-то с ними делать.
В качестве заключения
Надеюсь, что моя статья была интересна вам для чтения. Совсем недавно я настроил выполнение этого проекта каждый день по ночам, чтобы генерировать такие данные с последующей выгрузкой их в PostgreSQL. А затем я планирую повизуализировать их в Яндекс DataLens и попробовать построить какой-нибудь дашбород.