2012-04-17 23 views
10

Si la memoria me sirve, en R hay un tipo de datos llamado factor que cuando se utiliza dentro de un DataFrame se puede desempaquetar automáticamente en las columnas necesarias de una matriz de diseño de regresión. Por ejemplo, un factor que contiene Verdadero Falso Tal vez los valores// se transformaría en:Python Pandas: ¿cómo convertir un DataFrame con "factores" en una matriz de diseño para la regresión lineal?

1 0 0 
0 1 0 
or 
0 0 1 

para el propósito de utilizar el código de regresión nivel inferior. ¿Hay alguna manera de lograr algo similar usando la biblioteca de pandas? Veo que hay algo de apoyo de regresión dentro de Pandas, pero dado que tengo mis propias rutinas de regresión personalizadas, estoy realmente interesado en la construcción de la matriz de diseño (una matriz nude 2d o matriz) a partir de datos heterogéneos con soporte para mapeo y fortaleza entre columnas del objeto numpy y el Pandas DataFrame del cual se deriva.

Actualización: Aquí es un ejemplo de una matriz de datos con datos heterogéneos del tipo que estoy pensando en (el ejemplo viene del manual de pandas):

>>> df2 = DataFrame({'a' : ['one', 'one', 'two', 'three', 'two', 'one', 'six'],'b' : ['x', 'y', 'y', 'x', 'y', 'x', 'x'],'c' : np.random.randn(7)}) 
>>> df2 
     a b   c 
0 one x 0.000343 
1 one y -0.055651 
2 two y 0.249194 
3 three x -1.486462 
4 two y -0.406930 
5 one x -0.223973 
6 six x -0.189001 
>>> 

La 'a' columna debe ser convertido en 4 columnas de coma flotante (a pesar del significado, solo hay cuatro átomos únicos), la columna 'b' se puede convertir a una sola columna de coma flotante y la columna 'c' debe ser una columna final no modificada en la matriz de diseño .

Gracias,

setjmp

+0

No está claro qué quiere decir con "La 'a' columna debe ser convertida en 4 columnas flotantes puntos" ... ¿Quiere decir 4 valores de punto flotante? No veo cómo dividir las primeras columnas en columnas múltiples permitirá una matriz de diseño. Mi entendimiento es que las primeras dos columnas aquí son variables categóricas. ¿Quiere decir que quiere 4 variables binarias, que son iguales a 1 solo si esa fila de datos tiene ese número categórico de primera columna? – ely

+0

Convertir un factor con k niveles en k columnas/variables distintas se denomina ** discretización **. – smci

Respuesta

7

Hay un nuevo módulo llamado patsy que resuelve este problema. El inicio rápido vinculado a continuación resuelve exactamente el problema descrito anteriormente en un par de líneas de código.

Aquí es un ejemplo de uso:

import pandas 
import patsy 

dataFrame = pandas.io.parsers.read_csv("salary2.txt") 
#salary2.txt is a re-formatted data set from the textbook 
#Introductory Econometrics: A Modern Approach 
#by Jeffrey Wooldridge 
y,X = patsy.dmatrices("sl ~ 1+sx+rk+yr+dg+yd",dataFrame) 
#X.design_info provides the meta data behind the X columns 
print X.design_info 

genera:

> DesignInfo(['Intercept', 
>    'sx[T.male]', 
>    'rk[T.associate]', 
>    'rk[T.full]', 
>    'dg[T.masters]', 
>    'yr', 
>    'yd'], 
>   term_slices=OrderedDict([(Term([]), slice(0, 1, None)), (Term([EvalFactor('sx')]), slice(1, 2, None)), 
> (Term([EvalFactor('rk')]), slice(2, 4, None)), 
> (Term([EvalFactor('dg')]), slice(4, 5, None)), 
> (Term([EvalFactor('yr')]), slice(5, 6, None)), 
> (Term([EvalFactor('yd')]), slice(6, 7, None))]), 
>   builder=<patsy.build.DesignMatrixBuilder at 0x10f169510>) 
+0

pasty es excelente cuando se trata de transformar valores continuos en discretos. –

2
import pandas 
import numpy as np 

num_rows = 7; 
df2 = pandas.DataFrame(
         { 
         'a' : ['one', 'one', 'two', 'three', 'two', 'one', 'six'], 
         'b' : ['x', 'y', 'y', 'x', 'y', 'x', 'x'], 
         'c' : np.random.randn(num_rows) 
         } 
        ) 

a_attribute_list = ['one', 'two', 'three', 'six']; #Or use list(set(df2['a'].values)), but that doesn't guarantee ordering. 
b_attribute_list = ['x','y'] 

a_membership = [ np.reshape(np.array(df2['a'].values == elem).astype(np.float64), (num_rows,1)) for elem in a_attribute_list ] 
b_membership = [ np.reshape((df2['b'].values == elem).astype(np.float64), (num_rows,1)) for elem in b_attribute_list ] 
c_column = np.reshape(df2['c'].values, (num_rows,1)) 


design_matrix_a = np.hstack(tuple(a_membership)) 
design_matrix_b = np.hstack(tuple(b_membership)) 
design_matrix = np.hstack((design_matrix_a, design_matrix_b, c_column)) 

# Print out the design matrix to see that it's what you want. 
for row in design_matrix: 
    print row 

que reciben esta salida:

[ 1.   0.   0.   0.   1.   0.   0.36444463] 
[ 1.   0.   0.   0.   0.   1.   -0.63610264] 
[ 0.   1.   0.   0.   0.   1.   1.27876991] 
[ 0.   0.   1.   0.   1.   0.   0.69048607] 
[ 0.   1.   0.   0.   0.   1.   0.34243241] 
[ 1.   0.   0.   0.   1.   0.   -1.17370649] 
[ 0.   0.   0.   1.   1.   0.   -0.52271636] 

Así, la primera columna es un indicador de los lugares trama de datos que eran 'uno', el segundo la columna es un indicador de las ubicaciones del DataFrame que fueron 'dos', y así sucesivamente. Las columnas 4 y 5 son indicadores de ubicaciones de DataFrame que fueron 'x' e 'y', respectivamente, y la columna final es solo los datos aleatorios.

+0

El atributo de valores devuelve ndarray anidados donde la matriz más interna contiene dtype = object. Los factores se convierten en cadenas y los datos flotantes son flotantes dentro de esta matriz interna. – SetJmp

+0

No funciona así para mí. Edité la pregunta anterior para ilustrar. – ely

+0

Funciona para usted porque en su ejemplo todos los datos pasan a ser de tipo flotante. Sin embargo, con los datos de cadena presentes, obtengo una estructura diferente como tipo de devolución. Lo que busco es un mapeo lógico que transforme el marco de datos en un 2d ndarray de flotantes que luego podría ponerse en un solucionador de bajo nivel esperando la matriz de diseño X y las variables dependientes y. En el nivel bajo, me refiero a un código de espionaje inverso que solo sabe cómo trabajar en las ndarrays flotantes 2d (no en las reenvases). Esta codificación de nivel inferior es lo que se conoce como una "matriz de diseño" en las referencias de estadísticas. – SetJmp

1

patsy.dmatrices puede funcionar en muchos casos. Si solo tiene un vector, un pandas.Series, entonces el siguiente código puede funcionar produciendo una matriz de diseño degenerada y sin una columna de intercepción.

def factor(series): 
    """Convert a pandas.Series to pandas.DataFrame design matrix. 

    Parameters 
    ---------- 
    series : pandas.Series 
     Vector with categorical values 

    Returns 
    ------- 
    pandas.DataFrame 
     Design matrix with ones and zeroes. 

    See Also 
    -------- 
    patsy.dmatrices : Converts categorical columns to numerical 

    Examples 
    -------- 
    >>> import pandas as pd 
    >>> design = factor(pd.Series(['a', 'b', 'a'])) 
    >>> design.ix[0,'[a]'] 
    1.0 
    >>> list(design.columns) 
    ['[a]', '[b]'] 

    """ 
    levels = list(set(series)) 
    design_matrix = np.zeros((len(series), len(levels))) 
    for row_index, elem in enumerate(series): 
     design_matrix[row_index, levels.index(elem)] = 1 
    name = series.name or "" 
    columns = map(lambda level: "%s[%s]" % (name, level), levels) 
    df = pd.DataFrame(design_matrix, index=series.index, 
         columns=columns) 
    return df 
2

Pandas 0.13.1 del 3 de febrero, 2014 tiene un método:

>>> pd.Series(['one', 'one', 'two', 'three', 'two', 'one', 'six']).str.get_dummies() 
    one six three two 
0 1 0  0 0 
1 1 0  0 0 
2 0 0  0 1 
3 0 0  1 0 
4 0 0  0 1 
5 1 0  0 0 
6 0 1  0 0 
Cuestiones relacionadas