Python Pandas: как превратить DataFrame с факторами в матрицу дизайна для линейной регрессии?

Если память обслуживает меня, в R есть тип данных, называемый фактором, который при использовании в DataFrame может быть автоматически распакован в необходимые столбцы матрицы проектирования регрессии. Например, фактор, содержащий значения True / False / Maybe, будет преобразован в:

1 0 0
0 1 0
or
0 0 1

с целью использования кода регрессии более низкого уровня. Есть ли способ добиться чего-то подобного с помощью библиотеки pandas? Я вижу, что в Pandas есть некоторая поддержка регрессии, но, поскольку у меня есть свои собственные настраиваемые процедуры регрессии, меня действительно интересует построение матрицы дизайна (массив или матрица 2d numpy) из разнородных данных с поддержкой обратного сопоставления и форта между столбцы объекта numpy и фрейма данных Pandas, из которого он получен.

Обновление: вот пример матрицы данных с разнородными данными, о которых я думаю (пример взят из руководства 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
>>> 

Столбец 'a' должен быть преобразован в 4 столбца с плавающей запятой (несмотря на значение, есть только четыре уникальных атома), столбец 'b' может быть преобразован в один столбец с плавающей запятой, а столбец 'c' должен быть неизмененным заключительным столбцом в матрице плана.

Спасибо,

SetJmp


person Setjmp    schedule 17.04.2012    source источник
comment
Непонятно, что вы имеете в виду. Столбец «a» должен быть преобразован в 4 столбца с плавающей запятой ... Вы имеете в виду 4 значения с плавающей запятой? Я не понимаю, как разделение первых столбцов на несколько столбцов позволит создать матрицу дизайна. Насколько я понимаю, первые два столбца здесь являются категориальными переменными. Вы имеете в виду, что вам нужны 4 двоичные переменные, которые равны 1, только если эта строка данных имеет этот категориальный номер первого столбца?   -  person ely    schedule 18.04.2012
comment
Преобразование фактора с k уровнями в k различных столбцов / переменных называется дискретизацией.   -  person smci    schedule 10.03.2013


Ответы (4)


Есть новый модуль под названием patsy, который решает эту проблему. Приведенное ниже руководство по быстрому запуску решает в точности описанную выше проблему с помощью пары строк кода.

Вот пример использования:

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

генерирует:

> 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>)
person Setjmp    schedule 28.07.2012
comment
пастообразный превосходно подходит для преобразования непрерывных значений в дискретные. - person Pranav Waila; 17.03.2016

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

Я получаю такой вывод:

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

Итак, первый столбец является индикатором местоположений DataFrame, которые были «одним», второй столбец - индикатором местоположений DataFrame, которые были «двумя», и так далее. Столбцы 4 и 5 - это индикаторы местоположений DataFrame, которые были «x» и «y» соответственно, а последний столбец - это просто случайные данные.

person ely    schedule 17.04.2012
comment
Атрибут values ​​возвращает вложенные массивы ndarray, в которых самый внутренний массив содержит dtype = object. Коэффициенты преобразуются в строки, а данные с плавающей запятой внутри этого внутреннего массива являются плавающими. - person Setjmp; 17.04.2012
comment
У меня это не работает. Я отредактировал вопрос выше, чтобы проиллюстрировать. - person ely; 17.04.2012
comment
Это работает для вас, потому что в вашем примере все данные относятся к типу с плавающей запятой. Однако при наличии строковых данных я получаю другую структуру в качестве возвращаемого типа. То, что я ищу, как логическое отображение, которое преобразует фрейм данных в 2d-массив чисел с плавающей запятой, который затем может быть помещен в решатель низкого уровня, ожидающий матрицы проектирования X и зависимых переменных y. Под низким уровнем я подразумеваю обратный код, который знает, как работать только с двумерными массивами с плавающей запятой (но не с повторными массивами). Это кодирование нижнего уровня называется матрицей проекта в справочниках по статистике. - person Setjmp; 18.04.2012
comment
Вот обсуждение, в котором подчеркивается, как код R переводит факторы в матрицу проектирования за кулисами перед отправкой в ​​код решающей программы с низким уровнем рычага. Хотя факторы примера имеют только 2 уровня, я считаю, что правильного поведения можно ожидать для 3 или более уровней. r.789695.n4.nabble.com/ - person Setjmp; 18.04.2012
comment
Кажется, что numpy recarray может быть подходящим. Я посмотрю, можно ли values легко экспортировать в recarray - person ely; 18.04.2012
comment
Кроме того, было бы полезно, если бы вы могли предоставить рабочий код, который создает небольшой пример DataFrame со строками и т. Д. В местах, аналогичных тому, с которым вы работаете. Чтобы мы могли протестировать методы. - person ely; 18.04.2012
comment
Я изменил вопрос небольшим примером такого фрейма данных. - person Setjmp; 18.04.2012
comment
Я изменил ответ, исходя из своих предположений о том, чего вы хотите от категориальных переменных. Если я вас понял, вам нужны столбцы индикаторов, и все вышеперечисленное должно помочь. - person ely; 18.04.2012
comment
Спасибо, что приложили много усилий. Ваше решение теперь довольно близко к тому, что мне нужно, хотя и немного необщего, поскольку ваш комментарий о порядке словаря намекает. Наличие кодировки обратного отображения в общем случае также важно. Я нашел то, что я считаю эквивалентной функцией в R: model.matrix. Я все еще ожидаю, что появится лучшее / более элегантное решение, поэтому я пока не нажимаю кнопку «Принять». - person Setjmp; 19.04.2012
comment
Ничего страшного, не беспокойтесь. Меня тоже заинтересует более элегантное решение. Конечно, должен быть более питонический способ сделать это. - person ely; 19.04.2012

В Pandas 0.13.1 от 3 февраля 2014 г. есть метод:

>>> 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
person Finn Årup Nielsen    schedule 12.06.2014

patsy.dmatrices во многих случаях может работать хорошо. Если у вас есть только вектор - pandas.Series, то приведенный ниже код может работать, создавая вырожденную матрицу проекта и без столбца перехвата.

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
person Finn Årup Nielsen    schedule 20.03.2014