2012-07-30 15 views
5

Estoy intentando escribir una función que asigne 2d-ndarray a 2d-ndarray. Las filas de la matriz de entrada se pueden procesar independientemente y habrá una correspondencia de 1 a 1 entre las filas de la entrada y las filas de la salida. Para cada fila de la entrada, se computará la expansión polinómica de un orden dado para la fila (ver docstring para un ejemplo). La implementación actual funciona; sin embargo, requiere un bucle explícito sobre las filas y la duplicación de filas en "powerMatrix"). ¿Es posible obtener el mismo resultado con una sola llamada a numpy.power? Por cierto: el orden de las entradas en las filas del resultado no me importa.2d numpy.power para la expansión polinómica

import numpy 
def polynomialFeatures(x, order): 
    """ Generate polynomial features of given order for data x. 

    For each row of ndarray x, the polynomial expansions are computed, i.e 
    for row [x1, x2] and order 2, the following row of the result matrix is 
    computed: [1, x1, x1**2, x2, x1*x2, x1**2*x2, x2**2, x1*x2**2, x1**2*x2**2] 

    Parameters 
    ---------- 
    x : array-like 
     2-D array; for each of its rows, the polynomial features are created 

    order : int 
     The order of the polynomial features 

    Returns 
    ------- 
    out : ndarray 
     2-D array of shape (x.shape[0], (order+1)**x.shape[1]) containing the 
     polynomial features computed for the rows of the array x 

    Examples 
    -------- 
    >>> polynomialFeatures([[1, 2, 3], [-1, -2, -3]], 2) 
    array([[ 1 3 9 2 6 18 4 12 36 1 3 9 2 6 18 4 12 
      36 1 3 9 2 6 18 4 12 36] 
      [ 1 -3 9 -2 6 -18 4 -12 36 -1 3 -9 2 -6 18 -4 12 
      -36 1 -3 9 -2 6 -18 4 -12 36]]) 
    """ 
    x = numpy.asarray(x) 
    # TODO: Avoid duplication of rows 
    powerMatrix = numpy.array([range(order+1)] * x.shape[1]).T 
    # TODO: Avoid explicit loop, and use numpy's broadcasting 
    F = [] 
    for i in range(x.shape[0]): 
     X = numpy.power(x[i], powerMatrix).T 
     F.append(numpy.multiply.reduce(cartesian(X), axis=1)) 

    return numpy.array(F) 

print numpy.all(polynomialFeatures([[1, 2, 3], [-1, -2, -3]], 2) == 
       numpy.array([[1, 3, 9, 2, 6, 18, 4, 12, 36, 1, 
           3, 9, 2, 6, 18, 4, 12, 36, 1, 3, 
           9, 2, 6, 18, 4, 12, 36], 
          [1, -3, 9, -2, 6, -18, 4, -12, 36, -1, 
           3, -9, 2, -6, 18, -4, 12, -36, 1, -3, 
           9, -2, 6, -18, 4, -12, 36]])) 

Gracias, Ene

EDIT: La cartesiano función que falta se define aquí: Using numpy to build an array of all combinations of two arrays

Respuesta

3

La idea básica consiste en mover la dimensión (en su caso, la dimensión 0, el número de filas) eso es irrelevante para el cálculo "fuera del camino" en una dimensión más alta y luego transmitir automáticamente sobre él.

no estoy seguro de cuál es su método cartesian está haciendo, pero aquí es una solución que utiliza np.indices para generar tuplas de indexación más de la matriz X:

import numpy as np 
def polynomial_features(x, order): 
    x = np.asarray(x).T[np.newaxis] 
    n = x.shape[1] 
    power_matrix = np.tile(np.arange(order + 1), (n, 1)).T[..., np.newaxis] 
    X = np.power(x, power_matrix) 
    I = np.indices((order + 1,) * n).reshape((n, (order + 1) ** n)).T 
    F = np.product(np.diagonal(X[I], 0, 1, 2), axis=2) 
    return F.T 
+0

+1. [Borré un comentario tonto mío - le había pasado '[1,2,3]' a su función en lugar de '[[1,2,3]]', lo que por supuesto dio resultados igualmente tontos.] – DSM

+0

Gracias a mucho, eso hizo el trabajo :-) – frisbee

+0

¡Esta es una solución realmente elegante! Me gustaría utilizarlo en un pequeño proyecto en el que estoy trabajando si no te importa: https://github.com/dreamwalkerrr/mledu. (¿Le atribuirá este algoritmo vincular a esta respuesta si está bien?). Además, ¿podría decirme cuál sería la mejor manera de excluir los términos elevados a la 0ª potencia? – dreamwalker