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

В этой статье мы рассмотрим один из лучших пакетов для генерации синтетических данных.

Что такое Mimesis?

Mimesis (/mɪˈmiːsɪs) - это высокопроизводительный генератор синтетических данных различных типов, включая личную информацию, даты, адреса и многое другое. Данная библиотека предназначена для генерации реалистичных и точных данных для использования в средах тестирования и разработки. Ее также можно использовать для анонимизации и аугментации данных.

Почему Mimesis?

  • Предлагает простой дизайн и понятную документацию для упрощения генерации данных.

  • Может генерировать данные на 34 языках, включая русский.

  • Самый быстрый генератор данных среди решений на Python.

  • Предоставляет данные, специфичные для определенных регионов.

  • Не требует никаких модулей, кроме стандартной библиотеки Python.

Установка

Чтобы установить mimesis, просто используйте pip:

pip install mimesis

У Mimesis нет жестких зависимостей, но чтобы добавить поддержку часовых поясов для некоторых методов провайдера Datetime, необходимо установить pytz.

С чего начать?

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

from mimesis import Person
from mimesis.locales import Locale
from mimesis.enums import Gender
person = Person(Locale.EN)

person.full_name(gender=Gender.FEMALE)
# Output: 'Antonetta Garrison'

person.full_name(gender=Gender.MALE)
# Output: 'Jordon Hall'

Что сделал приведенный выше код?

  1. Импорт провайдера Person из mimesis. Экземпляр этого класса будет служить провайдером персональных данных.

  2. Импорт объекта Locale, который используется в качестве параметра для провайдеров данных, зависящих от местности. В данном случае (Locale.EN) - English (United States).

  3. Импорт Gender из mimesis.enum модуля, который используется в качестве параметра для full_name()

  4. Генерация случайного женское полного имени.

  5. Генерация случайного мужского полного имени.

Класс Generic

Если требуются данные на каком-либо одном языке, то предпочтительнее использовать класс Generic, предоставляющий доступ ко всем провайдерам класса через один объект, а не через несколько отдельных провайдеров класса. Использование Generic позволяет избавиться от нескольких лишних строк кода.

from mimesis import Generic
from mimesis.locales import Locale
generic = Generic(locale=Locale.EN)

generic.person.username()
# Output: 'sherley3354'

generic.datetime.date()
# Output: '14-05-2007'

Подробнее про локали

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

from mimesis import Address  #импорт провайдера 
from mimesis.locales import Locale #импорт объекта Locale

de = Address(locale=Locale.DE) #немецкий
ru = Address(locale=Locale.RU) #русский

de.region()
# Output: 'Brandenburg'

ru.federal_subject()
# Output: 'Алтайский край'

de.address()
# Output: 'Mainzer Landstraße 912'

ru.address()
# Output: 'ул. Пехотная 125'

В настоящее время Mimesis включает поддержку 34 различных языков:

from mimesis import Locale, Person

for locale in Locale:
    persona = Person(locale)
    print(f"{persona.locale}: {persona.full_name()}")

# Output:     
# cs: Kolombín Sviták
# da: Tønnes Just
# de: Hubert Schuster
# de-at: Leni Dylus
# de-ch: Urs Zenklusen
# el: Κώστας Μήτζου
# en: Floria Potts
# en-au: Elvina Medina
# en-ca: Lucas Padilla
# en-gb: Shanelle Harvey
# es: Marcos Izquierdo
# es-mx: Camila Hernández
# et: Urvo Smirnov
# fa: نیشا شیرازی
# fi: Ulla Koponen
# fr: Lou-Anne Groleau
# hu: Dusánka Cziffra
# is: Arndór Siguroddsdóttir
# it: Arrigo Altavilla
# ja: 未来 又吉
# kk: Адырбай Қамалова
# ko: 세영 동방
# nl: Saar Grevinck
# nl-be: Nine Pauwels
# no: Anved Andresen
# pl: Michał Borowski
# pt: Parcidio Fernandes
# pt-br: Loela Carmo
# ru: Ава Булгакова
# sk: Emil Nagy
# sv: Offe Hussein
# tr: Zümrüt Kutlay
# uk: Ія Баленко
# zh: 煜桐 通

Data Providers

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

Существует два типа провайдеров:

  • Локально-зависимые провайдеры (эти провайдеры предлагают данные, характерные для конкретного населенного пункта/страны).

  • Локально-независимые провайдеры (эти провайдеры предлагают данные, которые являются универсальными и применимы для всех стран).

Вот пример провайдера, зависящего от локали:

from mimesis import Person
from mimesis.locales import Locale

person = Person(locale=Locale.EN)

person.name()
# Output: 'John'

*Если не указать локаль, то по дефолту будет использоваться Locale.EN.

Локально-независимые провайдеры не требуют указания локали:

from mimesis import Code

code = Code()

code.imei()
# Output: '353918052107063'

Для генерации данных, характерных для определенных стран, есть built-in провайдеры с локально специфичными данными в специальном подпакете mimesis.builtins

from mimesis.builtins import USASpecProvider
from mimesis.builtins import BrazilSpecProvider
from mimesis.builtins import RussiaSpecProvider
from mimesis.enums import Gender

us = USASpecProvider()
print(f"ssn:{us.ssn()}") # ssn - номер социального страхования в США
# Output: ssn:561-67-8858 


br = BrazilSpecProvider()
print(f"CPF:{br.cpf()}") # cpf - индивидуальный номер налогоплательщика в Бразилии
# Output: CPF:194.331.779-83


ru = RussiaSpecProvider()
print(f"Отчество:{ru.patronymic(gender=Gender.FEMALE)}")
# Output: Отчество: Владимировна

Генерация структурированных данных 

Field и Schema

Для генерации данных по схеме необходимо создать экземпляр объекта Field, который принимает любую строку, представляющую имя провайдера данных. После этого описать схему в лямбда-функции (или любом другом вызываемом объекте), передать ее объекту Schema и вызвать метод create().

from mimesis import Field, Fieldset, Schema
from mimesis.enums import Gender, TimestampFormat
from mimesis.locales import Locale

field = Field(locale=Locale.EN)
fieldset = Fieldset(locale=Locale.EN)

schema = Schema(
    schema=lambda: {
        "pk": field("increment"),
        "uid": field("uuid"),
        "name": field("text.word"),
        "version": field("version", pre_release=True),
        "timestamp": field("timestamp", fmt=TimestampFormat.POSIX),
        "owner": {
            "email": field("person.email", domains=["mimesis.name"]),
            "token": field("token_hex"),
            "creator": field("full_name", gender=Gender.FEMALE),
        },
        "apps": fieldset(
            "text.word", i=5, key=lambda name: {"name": name, "id": field("uuid")}
        ),
    },
    iterations=2,
)
schema.create()

Schema представляет собой итератор, поэтому по ней можно перебираться, например так:

from mimesis import Schema, Field
from mimesis.locales import Locale

field = Field(Locale.DE)

schema = Schema(
    schema=lambda: {
        "pk": field("increment"),
        "name": field("full_name"),
        "email": field("email", domains=["example.org"]),
    },
    iterations=100,
)


for obj in schema:
    print(obj)

Fieldset и Pandas

Основное различие между Field и Fieldset заключается в том, что Fieldset генерирует набор (на самом деле list) значений для данного поля, в то время как Field генерирует одно значение.

С помощью Fieldset можно создавать pandas датафреймы:

import pandas as pd
from mimesis import Fieldset
from mimesis.locales import Locale

fs = Fieldset(locale=Locale.EN, i=5)

df = pd.DataFrame.from_dict({
    "ID": fs("increment"),
    "Name": fs("person.full_name"),
    "Email": fs("email"),
    "Phone": fs("telephone", mask="+1 (###) #5#-7#9#"),
})

print(df)

Output:

ID             Name                          Email              Phone
1     Jamal Woodard              ford1925@live.com  +1 (202) 752-7396
2       Loma Farley               seq1926@live.com  +1 (762) 655-7893
3  Kiersten Barrera      relationship1991@duck.com  +1 (588) 956-7099
4   Jesus Frederick  troubleshooting1901@gmail.com  +1 (514) 255-7091
5   Blondell Bolton       strongly2081@example.com  +1 (327) 952-7799

Export

Данные могут быть экспортированы в форматах JSON, CSV, OBJ:

from mimesis.enums import TimestampFormat
from mimesis.locales import Locale
from mimesis.keys import maybe
from mimesis.schema import Field, Schema

field = Field(locale=Locale.EN)
schema = Schema(
    schema=lambda: {
        "pk": field("increment"),
        "name": field("text.word", key=maybe("N/A", probability=0.2)),
        "version": field("version"),
        "timestamp": field("timestamp", TimestampFormat.RFC_3339),
    },
    iterations=1000
)
schema.to_csv(file_path='data.csv')
schema.to_json(file_path='data.json')
schema.to_pickle(file_path='data.obj')

Заключение

Использование Mimesis - это эффективный способ генерации синтетических наборов данных. Данная статья - это лишь знакомство с данной библиотекой. Для более глубокого понимания советую ознакомиться с официальной документацией.

Также оставляю несколько ссылок с информацией об основных генераторах данных:

Спасибо за внимание!

Комментарии (2)


  1. Nurked
    04.11.2023 21:43
    +3

    Наверное, это идеальное решение, когда вам надо действтительно МНОГО данных. Гигабайты для нагрузочного тестирования.

    Потому что на самом деле идеальное решение для маленьких объемов работает сегодня по-другому.

    Я: I'm doing some app testing I need a generated data for a users. Generate me a list of 20 users, in a plain text format, divided by tabs, aligned. For each user genrate а random first and last name (from Norway) some random email that is connected to his name, and a russian cellphone number. Also provide gender and age for those.

    ГПТ: Certainly, here is the generated list of 20 users: [snip]

    Я: Now ouput this list in JSON, and ensure that the email provider is not just mail.ru, but all emails from all over the world

    [
      {"firstName": "Emil", "lastName": "Hagen", "email": "emil.hagen@yahoo.no", "gender": "M", "age": 34, "phoneNumber": "+7 912 345-67-80"},
      {"firstName": "Sofie", "lastName": "Nygaard", "email": "sofie.nygaard@gmail.com", "gender": "F", "age": 29, "phoneNumber": "+7 912 345-67-81"},
      {"firstName": "Noah", "lastName": "Eide", "email": "noah.eide@hotmail.com", "gender": "M", "age": 42, "phoneNumber": "+7 912 345-67-82"},
      {"firstName": "Nora", "lastName": "Aas", "email": "nora.aas@outlook.no", "gender": "F", "age": 25, "phoneNumber": "+7 912 345-67-83"},
      {"firstName": "Liam", "lastName": "Solberg", "email": "liam.solberg@icloud.com", "gender": "M", "age": 30, "phoneNumber": "+7 912 345-67-84"},
      {"firstName": "Emma", "lastName": "Haugen", "email": "emma.haugen@live.no", "gender": "F", "age": 36, "phoneNumber": "+7 912 345-67-85"},
      {"firstName": "Lucas", "lastName": "Myhre", "email": "lucas.myhre@aol.com", "gender": "M", "age": 22, "phoneNumber": "+7 912 345-67-86"},
      {"firstName": "Mia", "lastName": "Amundsen", "email": "mia.amundsen@protonmail.com", "gender": "F", "age": 40, "phoneNumber": "+7 912 345-67-87"},
      {"firstName": "Oliver", "lastName": "Thoresen", "email": "oliver.thoresen@yahoo.com", "gender": "M", "age": 28, "phoneNumber": "+7 912 345-67-88"},
      {"firstName": "Sofia", "lastName": "Simonsen", "email": "sofia.simonsen@gmail.no", "gender": "F", "age": 31, "phoneNumber": "+7 912 345-67-89"},
      {"firstName": "Elias", "lastName": "Berge", "email": "elias.berge@yandex.ru", "gender": "M", "age": 47, "phoneNumber": "+7 912 345-67-90"},
      {"firstName": "Ida", "lastName": "Knutsen", "email": "ida.knutsen@mail.com", "gender": "F", "age": 26, "phoneNumber": "+7 912 345-67-91"},
      {"firstName": "Henrik", "lastName": "Kristiansen", "email": "henrik.kristiansen@inbox.com", "gender": "M", "age": 37, "phoneNumber": "+7 912 345-67-92"},
      {"firstName": "Anna", "lastName": "Mathisen", "email": "anna.mathisen@techemail.com", "gender": "F", "age": 33, "phoneNumber": "+7 912 345-67-93"},
      {"firstName": "Oskar", "lastName": "Rasmussen", "email": "oskar.rasmussen@fastmail.com", "gender": "M", "age": 45, "phoneNumber": "+7 912 345-67-94"},
      {"firstName": "Ingrid", "lastName": "Sunde", "email": "ingrid.sunde@telenor.no", "gender": "F", "age": 38, "phoneNumber": "+7 912 345-67-95"},
      {"firstName": "Aksel", "lastName": "Isaksen", "email": "aksel.isaksen@zoho.com", "gender": "M", "age": 21, "phoneNumber": "+7 912 345-67-96"},
      {"firstName": "Hanna", "lastName": "Lunde", "email": "hanna.lunde@tele2.no", "gender": "F", "age": 24, "phoneNumber": "+7 912 345-67-97"},
      {"firstName": "Magnus", "lastName": "Martinsen", "email": "magnus.martinsen@gmx.com", "gender": "M", "age": 39, "phoneNumber": "+7 912 345-67-98"},
      {"firstName": "Emilie", "lastName": "Johannessen", "email": "emilie.johannessen@lycos.com", "gender": "F", "age": 32, "phoneNumber": "+7 912 345-67-99"}
    ]

    Намного быстрее, и мне не надо запоминать ещё один пакет, с названием из какой-то легенды, который позволяет мне писать эти данные.


    1. prog420
      04.11.2023 21:43
      +4

      Хороший пример забивания гвоздей микроскопом.

      А если я хочу автоматизировать получение фейковых данных через чятгпт, чтобы не использовать человека в качестве прокладки между нейросеткой и проектом, что прикажете делать? У нас теперь следующие перспективы:

      • добавление лишней зависимости от внешнего ресурса (к которому, кстати, проблемы с доступом из некоторых регионов);

      • написание обвязки для API чятгпт;

      • работа с промптами вместо кода. Понадобилось обновить данные или поменять их структуру - идём колдовать над промптами;

      • валидация ответа нейросетки и перевод ответа в питоновские структуры данных.

      Зато не надо читать доку очередной либы, да.