Generaci贸n de datos sint茅ticos con Numpy y Scikit-Learn

    Introducci贸n

    En este tutorial, discutiremos los detalles de la generaci贸n de diferentes conjuntos de datos sint茅ticos usando las bibliotecas Numpy y Scikit-learn. Veremos c贸mo se pueden generar diferentes muestras a partir de varias distribuciones con par谩metros conocidos.

    Tambi茅n discutiremos la generaci贸n de conjuntos de datos para diferentes prop贸sitos, como regresi贸n, clasificaci贸n y agrupamiento. Al final, veremos c贸mo podemos generar un conjunto de datos que imite la distribuci贸n de un conjunto de datos existente.

    La necesidad de datos sint茅ticos

    En la ciencia de datos, los datos sint茅ticos juegan un papel muy importante. Nos permite probar un nuevo algoritmo en condiciones controladas. En otras palabras, podemos generar datos que prueben una propiedad o comportamiento muy espec铆fico de nuestro algoritmo.

    Por ejemplo, podemos probar su desempe帽o en conjuntos de datos balanceados vs. desequilibrados, o podemos evaluar su desempe帽o bajo diferentes niveles de ruido. Al hacer esto, podemos establecer una l铆nea de base del rendimiento de nuestro algoritmo en varios escenarios.

    Hay muchos otros casos en los que se pueden necesitar datos sint茅ticos. Por ejemplo, los datos reales pueden ser dif铆ciles o costosos de adquirir, o pueden tener muy pocos puntos de datos. Otra raz贸n es la privacidad, donde los datos reales no se pueden revelar a otros.

    Configuraci贸n

    Antes de escribir c贸digo para la generaci贸n de datos sint茅ticos, importemos las bibliotecas necesarias:

    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
    

    Entonces, tendremos algunas variables 煤tiles al principio:

    # 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"])
    

    Generaci贸n de muestras 1D a partir de distribuciones conocidas

    Ahora, hablaremos sobre la generaci贸n de puntos de muestra a partir de distribuciones conocidas en 1D.

    los random m贸dulo de numpy ofrece una amplia gama de formas de generar n煤meros aleatorios muestreados a partir de una distribuci贸n conocida con un conjunto fijo de par谩metros. Para fines de reproducci贸n, pasaremos el seed al RandomState call y siempre que usemos esa misma semilla, obtendremos los mismos n煤meros.

    Definamos una lista de distribuci贸n, como uniform, normal, exponential, etc., una lista de par谩metros y una lista de colores para que podamos discernir visualmente entre estos:

    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']
    

    Ahora, los empaquetaremos en subtramas de un Figure para su visualizaci贸n y generar datos sint茅ticos en base a estas distribuciones, par谩metros y asignarles colores adecuados.

    Esto se hace a trav茅s del eval() funci贸n, que usamos para generar una expresi贸n de Python. Por ejemplo, podemos usar rand.exponential(1, 5000) para generar muestras a partir de una distribuci贸n exponencial de escala 1 y el tama帽o de 5000.

    Aqu铆, usaremos nuestro dist_list, param_list y color_list para generar estas llamadas:

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

    Esto resulta en:

    Datos sint茅ticos para regresi贸n

    los paquete sklearn.datasets tiene funciones para generar conjuntos de datos sint茅ticos para regresi贸n. Aqu铆, discutimos datos lineales y no lineales para regresi贸n.

    los make_regression() La funci贸n devuelve un conjunto de puntos de datos de entrada (regresores) junto con su salida (objetivo). Esta funci贸n se puede ajustar con los siguientes par谩metros:

    • n_features – n煤mero de dimensiones / caracter铆sticas de los datos generados
    • noise – desviaci贸n est谩ndar del ruido gaussiano
    • n_samples – n煤mero de muestras

    La variable de respuesta es una combinaci贸n lineal del conjunto de entrada generado.

    Una variable de respuesta es algo que depende de otras variables, en este caso particular, una caracter铆stica de destino que estamos tratando de predecir utilizando todas las dem谩s caracter铆sticas de entrada.

    En el siguiente c贸digo, se han generado datos sint茅ticos para diferentes niveles de ruido y consta de dos caracter铆sticas de entrada y una variable de destino. El color cambiante de los puntos de entrada muestra la variaci贸n en el valor del objetivo, correspondiente al punto de datos. Los datos se generan en 2D para una mejor visualizaci贸n, pero se pueden crear datos de alta dimensi贸n utilizando el n_features par谩metro:

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

    Aqu铆, hemos creado un grupo de 1000 muestras, con dos variables de entrada (caracter铆sticas). Seg煤n el nivel de ruido (0..1000), podemos ver c贸mo los datos generados difieren significativamente en el diagrama de dispersi贸n:

    los make_friedman Familia de funciones

    Hay tres versiones del make_friedman?() funci贸n (reemplazar el ? con un valor de {1,2,3}).

    Estas funciones generan la variable de destino utilizando una combinaci贸n no lineal de las variables de entrada, como se detalla a continuaci贸n:

    • make_friedman1(): Los n_features El argumento de esta funci贸n debe ser al menos 5, por lo que se genera un n煤mero m铆nimo de 5 dimensiones de entrada. Aqu铆 el objetivo viene dado por:
      $$
      y (x) = 10 * sin ( pi x_0 x_1) + 20 (x_2 – 0.5) ^ 2 + 10x_3 + 5x_4 + text {ruido}
      $$
    • make_friedman2(): Los datos generados tienen 4 dimensiones de entrada. La variable de respuesta viene dada por:

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

    • make_friedman3(): Los datos generados en este caso tambi茅n tienen 4 dimensiones. La variable de salida viene dada por:

    $$
    y (x) = arctan ( frac {x_1 x_2 – frac {1} {(x_1 x_3)}} {x_0}) + text {ruido}
    $$

    El siguiente c贸digo genera los conjuntos de datos utilizando estas funciones y traza las tres primeras caracter铆sticas en 3D, con colores que var铆an seg煤n la variable de destino:

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

    Datos sint茅ticos para clasificaci贸n

    Scikit-learn tiene funciones simples y f谩ciles de usar para generar conjuntos de datos para la clasificaci贸n en el sklearn.dataset m贸dulo. Repasemos un par de ejemplos.

    make_classification() para problemas de clasificaci贸n de clase n

    Para problemas de clasificaci贸n de clase n, el make_classification() La funci贸n tiene varias opciones:

    • class_sep: Especifica si las diferentes clases deben estar m谩s dispersas y ser m谩s f谩ciles de discriminar
    • n_features: N煤mero de funciones
    • n_redundant: N煤mero de funciones redundantes
    • n_repeated: N煤mero de funciones repetidas
    • n_classes: N煤mero total de clases

    Hagamos un conjunto de datos de clasificaci贸n para datos de entrada bidimensionales. Tendremos diferentes valores de class_sep para un problema de clasificaci贸n binaria. Los puntos del mismo color pertenecen a la misma clase. Vale la pena se帽alar que esta funci贸n tambi茅n puede generar clases desequilibradas:

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

    make_multilabel_classification() para problemas de clasificaci贸n de etiquetas m煤ltiples

    make_multilabel_classification() La funci贸n genera datos para problemas de clasificaci贸n de etiquetas m煤ltiples. Tiene varias opciones, de las cuales la m谩s destacable es n_label, que establece el n煤mero medio de etiquetas por punto de datos.

    Consideremos un problema de etiquetas m煤ltiples de 4 clases, con el vector de etiquetas de destino convertido a un valor 煤nico para la visualizaci贸n. Los puntos se colorean de acuerdo con la representaci贸n decimal del vector de etiqueta binaria. El c贸digo le ayudar谩 a ver c贸mo usar un valor diferente para n_label, cambia la clasificaci贸n de un punto de datos generado:

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

    Datos sint茅ticos para la agrupaci贸n en cl煤steres

    Para la agrupaci贸n, el sklearn.datasets proporciona varias opciones. Aqu铆, cubriremos el make_blobs() y make_circles() funciones.

    make_blobs()

    los make_blobs() La funci贸n genera datos a partir de distribuciones gaussianas isotr贸picas. El n煤mero de caracter铆sticas, el n煤mero de centros y la desviaci贸n est谩ndar de cada grupo se pueden especificar como un argumento.

    Aqu铆, ilustramos esta funci贸n en 2D y mostramos c贸mo los puntos de datos cambian con diferentes valores de cluster_std par谩metro:

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

    los make_circles() La funci贸n genera dos c铆rculos conc茅ntricos con el mismo centro, uno dentro del otro.

    Usando el par谩metro de ruido, se puede agregar distorsi贸n a los datos generados. Este tipo de datos es 煤til para evaluar algoritmos de agrupaci贸n en cl煤steres basados 鈥嬧媏n afinidad. El siguiente c贸digo muestra los datos sint茅ticos generados a diferentes niveles de ruido:

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

    Generar muestras derivadas de un conjunto de datos de entrada

    Hay muchas formas de generar muestras de datos adicionales a partir de un conjunto de datos existente. Aqu铆, ilustramos un m茅todo muy simple que primero estima la densidad del kernel de datos usando un kernel gaussiano y luego genera muestras adicionales de esta distribuci贸n.

    Para visualizar las muestras reci茅n generadas, veamos el conjunto de datos de caras de Olivetti, recuperable a trav茅s de sklearn.datasets.fetch_olivetti_faces(). El conjunto de datos tiene 10 im谩genes faciales diferentes de 40 personas diferentes.

    Esto es lo que haremos:

    • Obtener los datos de las caras
    • Genere el modelo de densidad del kernel a partir de datos
    • Utilice la densidad del kernel para generar nuevas muestras de datos
    • Muestre las caras originales y sint茅ticas.
    # 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()
    

    Las caras originales que se muestran aqu铆 son una muestra de 8 caras elegidas de 400 im谩genes, para tener una idea de c贸mo se ve el conjunto de datos original. Podemos generar tantos puntos de datos nuevos como queramos usando el sample() funci贸n.

    En este ejemplo, se generaron 8 nuevas muestras. Tenga en cuenta que las caras sint茅ticas que se muestran aqu铆 no se corresponden necesariamente con la cara de la persona que se muestra arriba.

    Conclusiones

    En este art铆culo, conocimos algunos m茅todos para generar conjuntos de datos sint茅ticos para varios problemas. Los conjuntos de datos sint茅ticos nos ayudan a evaluar nuestros algoritmos en condiciones controladas y establecen una l铆nea de base para las medidas de rendimiento.

    Python tiene una amplia gama de funciones que se pueden utilizar para la generaci贸n de datos artificiales. Es importante comprender qu茅 funciones y API se pueden utilizar para sus requisitos espec铆ficos.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *