Рубрики
Без рубрики

Генерация синтетических данных с помощью Numpy и Scikit-Learn

В этой статье мы рассмотрим, как генерировать синтетические данные с помощью Python, Numpy и Scikit Learn. Мы будем генерировать 1D-данные, мульти-метки, мультиклассовую классификацию и регрессионные данные.

Автор оригинала: Mehreen Saeed.

Вступление

В этом уроке мы обсудим детали создания различных синтетических наборов данных с использованием библиотек Numpy и Scikit-learn . Мы увидим, как различные выборки могут быть сгенерированы из различных распределений с известными параметрами.

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

Потребность в синтетических данных

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

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

Есть много других случаев, когда могут потребоваться синтетические данные. Например, реальные данные могут быть трудными или дорогими для получения, или они могут иметь слишком мало точек данных. Другая причина-конфиденциальность, когда реальные данные не могут быть раскрыты другим.

установка

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

import numpy as np

# Needed for plotting
import matplotlib.colors
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Needed for generating classification, regression and clustering datasets
import sklearn.datasets as dt

# Needed for generating data from an existing dataset
from sklearn.neighbors import KernelDensity
from sklearn.model_selection import GridSearchCV

Тогда у нас будет несколько полезных переменных в начале:

# Define the seed so that results can be reproduced
seed = 11
rand_state = 11

# Define the color maps for plots
color_map = plt.cm.get_cmap('RdYlBu')
color_map_discrete = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","cyan","magenta","blue"])

Генерация 1D выборок из известных распределений

Теперь мы поговорим о генерации выборочных точек из известных распределений в 1D.

Модуль random от numpy предлагает широкий спектр способов генерации случайных чисел, отобранных из известного распределения с фиксированным набором параметров. Для целей воспроизведения мы передадим семя в Случайное состояние вызов, и пока мы используем то же самое семя, мы получим те же самые числа.

Давайте определим список распределения, такой как uniform , normal , exponential и т. Д. , Список параметров и список цветов, Чтобы мы могли визуально различать их:

rand = np.random.RandomState(seed)    

dist_list = ['uniform','normal','exponential','lognormal','chisquare','beta']
param_list = ['-1,1','0,1','1','0,1','2','0.5,0.9']
colors_list = ['green','blue','yellow','cyan','magenta','pink']

Теперь мы упакуем их в подзаголовки Рисунка для визуализации и сгенерируем синтетические данные на основе этих распределений, параметров и назначим им соответствующие цвета.

Это делается с помощью функции eval () , которую мы используем для генерации выражения Python. Например, мы можем использовать rand.exponential(1, 5000) для генерации выборок из экспоненциального распределения масштаба 1 и размер 5000 .

Здесь мы будем использовать наши dist_list , param_list и color_list для генерации этих вызовов:

fig,ax = plt.subplots(nrows=2, ncols=3,figsize=(12,7))
plt_ind_list = np.arange(6)+231

for dist, plt_ind, param, colors in zip(dist_list, plt_ind_list, param_list, colors_list):
    x = eval('rand.'+dist+'('+param+',5000)') 
    
    plt.subplot(plt_ind)
    plt.hist(x,bins=50,color=colors)
    plt.title(dist)

fig.subplots_adjust(hspace=0.4,wspace=.3) 
plt.suptitle('Sampling from Various Distributions',fontsize=20)
plt.show()

Это приводит к:

генерация 1d сэмплов с помощью numpy

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

Пакет sklearn.datasets имеет функции для генерации синтетических наборов данных для регрессии. Здесь мы обсуждаем линейные и нелинейные данные для регрессии.

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

  1. n_features – количество измерений/признаков сгенерированных данных
  2. шум – стандартное отклонение гауссовского шума
  3. n_samples – количество выборок

Переменная отклика представляет собой линейную комбинацию сгенерированного входного набора.

Переменная ответа-это нечто, зависящее от других переменных, в данном конкретном случае-целевой объект, который мы пытаемся предсказать, используя все остальные входные объекты.

В приведенном ниже коде синтетические данные были сгенерированы для различных уровней шума и состоят из двух входных признаков и одной целевой переменной. Изменение цвета входных точек показывает изменение целевого значения, соответствующего точке данных. Данные генерируются в 2D для лучшей визуализации, но высокомерные данные могут быть созданы с помощью параметра n_features :

map_colors = plt.cm.get_cmap('RdYlBu')
fig,ax = plt.subplots(nrows=2, ncols=3,figsize=(16,7))
plt_ind_list = np.arange(6)+231

for noise,plt_ind in zip([0,0.1,1,10,100,1000],plt_ind_list): 
    x,y = dt.make_regression(n_samples=1000,
                             n_features=2,
                             noise=noise,
                             random_state=rand_state) 
    
    plt.subplot(plt_ind)
    my_scatter_plot = plt.scatter(x[:,0],
                                  x[:,1],
                                  c=y,
                                  vmin=min(y),
                                  vmax=max(y),
                                  s=35,
                                  cmap=color_map)
    
    plt.title('noise: '+str(noise))
    plt.colorbar(my_scatter_plot)
    
fig.subplots_adjust(hspace=0.3,wspace=.3)
plt.suptitle('make_regression() With Different Noise Levels',fontsize=20)
plt.show()

Здесь мы создали пул из 1000 образцов с двумя входными переменными (функциями). В зависимости от уровня шума ( 0..1000 ), мы можем видеть, как сгенерированные данные значительно отличаются на точечной диаграмме:

генерация синтетических данных для регрессии

Семейство функций make_friedman

Существует три версии make_friedman?() функция (заменить ? со значением из {1,2,3} ).

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

  • make_friedman 1() : Аргумент n_features этой функции должен быть не менее 5, следовательно, генерируется минимальное количество 5 входных измерений. Здесь цель задается следующим образом: $$ * \sin(\pi x_0 x_1) + 20(x_2 – 0.5)^2 + 10x_3 + 5x_4 + \text{noise} $$

  • make_friedman 2() : Сгенерированные данные имеют 4 входных измерения. Переменная ответа задается формулой:

$$ y(x) = \sqrt{(x_0^2+x_1 x_2 – \frac{1}{(x_1 x_3)^2})} + \text{noise} $$

  • make_friedman 3() : Сгенерированные данные в этом случае также имеют 4 измерения. Выходная переменная задается:

$$ y(x) = \arctan(\frac{x_1 x_2 -\frac{1}{(x_1 x_3)}}{x_0})+\text{noise} $$

Приведенный ниже код генерирует наборы данных с помощью этих функций и строит первые три объекта в 3D, причем цвета изменяются в зависимости от целевой переменной:

fig = plt.figure(figsize=(18,5))

x,y = dt.make_friedman1(n_samples=1000,n_features=5,random_state=rand_state)
ax = fig.add_subplot(131, projection='3d')
my_scatter_plot = ax.scatter(x[:,0], x[:,1],x[:,2], c=y, cmap=color_map)
fig.colorbar(my_scatter_plot)
plt.title('make_friedman1')

x,y = dt.make_friedman2(n_samples=1000,random_state=rand_state)
ax = fig.add_subplot(132, projection='3d')
my_scatter_plot = ax.scatter(x[:,0], x[:,1],x[:,2], c=y, cmap=color_map)
fig.colorbar(my_scatter_plot)
plt.title('make_friedman2')

x,y = dt.make_friedman3(n_samples=1000,random_state=rand_state)
ax = fig.add_subplot(133, projection='3d')
my_scatter_plot = ax.scatter(x[:,0], x[:,1],x[:,2], c=y, cmap=color_map)
fig.colorbar(my_scatter_plot)
plt.suptitle('make_friedman?() for Non-Linear Data',fontsize=20)
plt.title('make_friedman3')

plt.show()
составьте семейство функций Фридмана

Синтетические данные для классификации

Scikit-learn имеет простые и удобные в использовании функции для генерации наборов данных для классификации в модуле sklearn.dataset . Давайте рассмотрим несколько примеров.

make_classification() для задач классификации n-классов

Для задач классификации n-класса функция make_classification() имеет несколько вариантов:

  1. class_sep : Указывает, должны ли различные классы быть более разбросанными и легче различимыми
  2. n_features : Количество функций
  3. n_redundant : Количество избыточных функций
  4. n_repeated : Количество повторяющихся функций
  5. n_classes : Общее количество классов

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

fig,ax = plt.subplots(nrows=1, ncols=3,figsize=(16,5))
plt_ind_list = np.arange(3)+131

for class_sep,plt_ind in zip([0.1,1,10],plt_ind_list):
    x,y = dt.make_classification(n_samples=1000,
                                 n_features=2,
                                 n_repeated=0,
                                 class_sep=class_sep,
                                 n_redundant=0,
                                 random_state=rand_state)
    
    plt.subplot(plt_ind)
    my_scatter_plot = plt.scatter(x[:,0],
                                  x[:,1],
                                  c=y,
                                  vmin=min(y),
                                  vmax=max(y),
                                  s=35,
                                  cmap=color_map_discrete)
    plt.title('class_sep: '+str(class_sep))

fig.subplots_adjust(hspace=0.3,wspace=.3)
plt.suptitle('make_classification() With Different class_sep Values',fontsize=20)
plt.show()
сделайте классификацию для n-классов

make_multi label_classification() для задач классификации с несколькими метками

функция make_multilabel_classification() генерирует данные для задач классификации с несколькими метками. Он имеет различные опции, из которых наиболее заметной является n_label , которая устанавливает среднее количество меток на точку данных.

Рассмотрим 4-классовую задачу с несколькими метками, в которой целевой вектор меток преобразуется в одно значение для визуализации. Точки окрашиваются в соответствии с десятичным представлением вектора двоичной метки. Код поможет вам увидеть , как использование другого значения для n_label изменяет классификацию сгенерированной точки данных:

fig,ax = plt.subplots(nrows=1, ncols=3,figsize=(16,5))
plt_ind_list = np.arange(3)+131

for label,plt_ind in zip([2,3,4],plt_ind_list):
    x,y = dt.make_multilabel_classification(n_samples=1000,
                                            n_features=2,
                                            n_labels=label,
                                            n_classes=4,
                                            random_state=rand_state)
    target = np.sum(y*[8,4,2,1],axis=1)
    
    plt.subplot(plt_ind)
    my_scatter_plot = plt.scatter(x[:,0],
                                  x[:,1],
                                  c=target,
                                  vmin=min(target),
                                  vmax=max(target),
                                  cmap=color_map)
    plt.title('n_labels: '+str(label))

fig.subplots_adjust(hspace=0.3,wspace=.3)
plt.suptitle('make_multilabel_classification() With Different n_labels Values',fontsize=20)
plt.show()
многоуровневая классификация

Синтетические данные для кластеризации

Для кластеризации файл sklearn.datasets предоставляет несколько вариантов. Здесь мы рассмотрим функции make_blobs() и make_circles () .

make_blobs()

Функция make_blobs() генерирует данные из изотропных гауссовых распределений. В качестве аргумента можно указать количество объектов, количество центров и стандартное отклонение каждого кластера.

Здесь мы проиллюстрируем эту функцию в 2D и покажем, как меняются точки данных при различных значениях параметра cluster_std :

fig,ax = plt.subplots(nrows=1, ncols=3,figsize=(16,5))
plt_ind_list = np.arange(3)+131

for std,plt_ind in zip([0.5,1,10],plt_ind_list):
    x, label = dt.make_blobs(n_features=2,
                             centers=4,
                             cluster_std=std,
                             random_state=rand_state)
    
    plt.subplot(plt_ind)    
    my_scatter_plot = plt.scatter(x[:,0],
                                  x[:,1],
                                  c=label,
                                  vmin=min(label),
                                  vmax=max(label),
                                  cmap=color_map_discrete)
    plt.title('cluster_std: '+str(std))

fig.subplots_adjust(hspace=0.3,wspace=.3)
plt.suptitle('make_blobs() With Different cluster_std Values',fontsize=20)
plt.show()
синтетические данные для кластеризации

make_circles()

Функция make_circles() генерирует два концентрических круга с одинаковым центром, один внутри другого.

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

fig,ax = plt.subplots(nrows=1, ncols=3,figsize=(16,5))
plt_ind_list = np.arange(3)+131

for noise,plt_ind in zip([0,0.1,1],plt_ind_list):
    x, label = dt.make_circles(noise=noise,random_state=rand_state)
    
    plt.subplot(plt_ind)    
    my_scatter_plot = plt.scatter(x[:,0],
                                  x[:,1],
                                  c=label,
                                  vmin=min(label),
                                  vmax=max(label),
                                  cmap=color_map_discrete)
    plt.title('noise: '+str(noise))

fig.subplots_adjust(hspace=0.3,wspace=.3)
plt.suptitle('make_circles() With Different Noise Levels',fontsize=20)
plt.show()
сделайте синтетические круги данных

Генерация выборок, полученных из входного набора данных

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

Чтобы визуализировать вновь сгенерированные образцы, давайте посмотрим на набор данных Olivetti faces, извлекаемый через sklearn.datasets.fetch_olivetti_faces() . Набор данных содержит 10 различных изображений лиц 40 разных людей.

Вот что мы будем делать:

  1. Получить данные о лицах
  2. Сгенерируйте модель плотности ядра из данных
  3. Используйте плотность ядра для генерации новых выборок данных
  4. Отображение оригинальных и синтетических граней.
# Fetch the dataset and store in X
faces = dt.fetch_olivetti_faces()
X= faces.data

# Fit a kernel density model using GridSearchCV to determine the best parameter for bandwidth
bandwidth_params = {'bandwidth': np.arange(0.01,1,0.05)}
grid_search = GridSearchCV(KernelDensity(), bandwidth_params)
grid_search.fit(X)
kde = grid_search.best_estimator_

# Generate/sample 8 new faces from this dataset
new_faces = kde.sample(8, random_state=rand_state)

# Show a sample of 8 original face images and 8 generated faces derived from the faces dataset
fig,ax = plt.subplots(nrows=2, ncols=8,figsize=(18,6),subplot_kw=dict(xticks=[], yticks=[]))
for i in np.arange(8):
    ax[0,i].imshow(X[10*i,:].reshape(64,64),cmap=plt.cm.gray)   
    ax[1,i].imshow(new_faces[i,:].reshape(64,64),cmap=plt.cm.gray)    
ax[0,3].set_title('Original Data',fontsize=20)
ax[1,3].set_title('Synthetic Data',fontsize=20)
fig.subplots_adjust(wspace=.1)
plt.show()
генерация синтетических данных на основе входных данных

Исходные грани, показанные здесь, представляют собой выборку из 8 граней, выбранных из 400 изображений, чтобы получить представление о том, как выглядит исходный набор данных. Мы можем генерировать столько новых точек данных, сколько нам нравится, используя функцию sample () .

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

Выводы

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

Python обладает широким спектром функций, которые могут быть использованы для искусственного генерирования данных. Важно понимать, какие функции и API могут быть использованы для ваших конкретных требований.