2013-02-22 15 views
12

Próbuję użyć zestawu danych oceny samochodu z repozytorium UCI i zastanawiam się, czy istnieje wygodny sposób binaryzacji zmiennych jakościowych w sklearn. Jednym z podejść byłoby użycie DictVectorizer z LabelBinarizera, ale tutaj dostaję k różnych funkcji, podczas gdy powinieneś mieć tylko k-1, aby uniknąć kolinearyzacji. Zgaduję, że mógłbym napisać własną funkcję i upuścić jedną kolumnę, ale ta księgowość jest nudna, czy istnieje prosty sposób na przeprowadzenie takich przekształceń i uzyskanie w rezultacie rzadkiej matrycy?Jak zakodować zmienną kategoryczną w sklearn?

+0

Czy istnieje szczególny powód, dla którego preferujesz cechy k-1 powyżej k? Posiadanie k cech sprawia, że ​​interpretacja współczynników (powiedzmy w modelu liniowym) jest znacznie łatwiejsza i może promować rzadkie cechy. –

+1

Próbowałem znaleźć znaczenie współczynników i wpadłem w problemy kolinearności http://en.wikipedia.org/wiki/Multicollinearity – tonicebrian

+0

Myślę, że nie jestem wystarczająco w statystyce strony, aby zobaczyć, dlaczego to byłby problem . Wyobrażam sobie kodowanie cech k, które daje znacznie bardziej znaczące wyniki pod względem istotności funkcji niż jakakolwiek inna metoda kodowania. –

Odpowiedz

15

DictVectorizer jest zalecanym sposobem generowania jedno-gorącego kodowania zmiennych jakościowych; możesz użyć argumentu sparse, aby utworzyć rzadką matrycę CSR zamiast gęstej tablicy numpy. Zwykle nie dbam o wieloklinowość i nie zauważyłem problemu z podejściami, z których korzystam (tj. LinearSVC, SGDClassifier, metody oparte na drzewach).

Nie powinno być problemu z łataniem DictVectorizera, aby upuścić jedną kolumnę na kategorię - wystarczy, że usuniesz jeden termin z DictVectorizer.vocabulary na końcu metody fit. (Wnioski Pull są zawsze mile widziane!)

+5

Czy istnieje jakiś szczególny powód, dla którego polecasz DictVectorizer na klasę OneHotEncoder? – Dexter

+5

DictVectorizer jest bardziej ogólny - wejście OneHotEncoder jest ograniczone do kolumn liczb całkowitych reprezentujących kategorie. DictVectorizer zajmuje się również tekstowymi wartościami kategorycznymi. Z drugiej strony, jeśli wszystko, co masz, to przede wszystkim kategorie całkowite, OneHotEncoder wydaje się najprostszym wyborem. –

+1

Aby jednak użyć DictVectorizer, musiałbym przekonwertować tablicę na listę słowników z każdym słownikiem na liście odpowiadającym wierszowi w tablicy. To wygląda na włamanie. Dlaczego nie mogę po prostu przekazać tablicy do DictVectorizer? – Ben

16

Podstawową metodą jest

import numpy as np 
import pandas as pd, os 
from sklearn.feature_extraction import DictVectorizer 

def one_hot_dataframe(data, cols, replace=False): 
    vec = DictVectorizer() 
    mkdict = lambda row: dict((col, row[col]) for col in cols) 
    vecData = pd.DataFrame(vec.fit_transform(data[cols].apply(mkdict, axis=1)).toarray()) 
    vecData.columns = vec.get_feature_names() 
    vecData.index = data.index 
    if replace is True: 
     data = data.drop(cols, axis=1) 
     data = data.join(vecData) 
    return (data, vecData, vec) 

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 
     'year': [2000, 2001, 2002, 2001, 2002], 
     'pop': [1.5, 1.7, 3.6, 2.4, 2.9]} 

df = pd.DataFrame(data) 

df2, _, _ = one_hot_dataframe(df, ['state'], replace=True) 
print df2 

Oto jak to zrobić w formacie rozrzedzony

import numpy as np 
import pandas as pd, os 
import scipy.sparse as sps 
import itertools 

def one_hot_column(df, cols, vocabs): 
    mats = []; df2 = df.drop(cols,axis=1) 
    mats.append(sps.lil_matrix(np.array(df2))) 
    for i,col in enumerate(cols): 
     mat = sps.lil_matrix((len(df), len(vocabs[i]))) 
     for j,val in enumerate(np.array(df[col])): 
      mat[j,vocabs[i][val]] = 1. 
     mats.append(mat) 

    res = sps.hstack(mats) 
    return res 

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 
     'year': ['2000', '2001', '2002', '2001', '2002'], 
     'pop': [1.5, 1.7, 3.6, 2.4, 2.9]} 

df = pd.DataFrame(data) 
print df 

vocabs = [] 
vals = ['Ohio','Nevada'] 
vocabs.append(dict(itertools.izip(vals,range(len(vals))))) 
vals = ['2000','2001','2002'] 
vocabs.append(dict(itertools.izip(vals,range(len(vals))))) 

print vocabs 

print one_hot_column(df, ['state','year'], vocabs).todense() 
+2

Jak radzisz sobie z niewidocznymi wartościami w nowych danych z tym podejściem? – marbel

31

jeśli dane jest DataFrame pandy, to możesz po prostu zadzwoń get_dummies. Załóżmy, że twoja ramka danych jest df i chcesz mieć jedną zmienną binarną na każdy poziom zmiennej "klucz". Możesz po prostu zadzwonić:

pd.get_dummies(df['key']) 

a następnie usunąć jedną ze zmiennych fikcyjnych, aby uniknąć problemu multi-współliniowości. Mam nadzieję, że to pomoże ...

+5

Osobiście wolę pandasowe get_dummies od OneHotEncoder lub DictVectorizer od sklearn. Używanie get_dummies w Pandach często skutkuje bardziej usprawnioną procedurą i mniejszym kodem. Panda to bardziej analiza danych i wstępne przetwarzanie, a sklearn to bardziej "ciężkie" procesy uczenia się, jeśli o mnie chodzi. – luanjunyi

+19

Wadą dla get_dummies jest to, że niekoniecznie będzie generować te same fałszywe kolumny w zestawie danych scoringowych (pozostawiając tony złożoności przy próbie oceny modelu). – Chris

+1

Jednym ze sposobów na zrobienie tego jest najpierw przećwiczenie treningu i przetestowanie DataFrame, a następnie zastosuj get_dummies, a na końcu oddziel osobne szkolenie i test DataFrame. W ten sposób dane treningowe i testowe będą miały spójne, jedno gorące kodowanie. – weidongxu