Hoe kan ik hot coderen in Python?

Ik heb een classificatieprobleem voor machine learning met 80% categorische variabelen. Moet ik één hot-codering gebruiken als ik een classificatie wil gebruiken voor de classificatie? Kan ik de gegevens doorgeven aan een classifier zonder de codering?

Ik probeer het volgende te doen voor het selecteren van functies:

  1. Ik heb het treinbestand gelezen:

    num_rows_to_read = 10000
    train_small = pd.read_csv("../../dataset/train.csv",   nrows=num_rows_to_read)
    
  2. Ik verander het type categorische kenmerken in ‘categorie’:

    non_categorial_features = ['orig_destination_distance',
                              'srch_adults_cnt',
                              'srch_children_cnt',
                              'srch_rm_cnt',
                              'cnt']
    for categorical_feature in list(train_small.columns):
        if categorical_feature not in non_categorial_features:
            train_small[categorical_feature] = train_small[categorical_feature].astype('category')
    
  3. Ik gebruik één hot-codering:

    train_small_with_dummies = pd.get_dummies(train_small, sparse=True)
    

Het probleem is dat het derde deel vaak vastloopt, hoewel ik een sterke machine gebruik.

Dus zonder die ene hot-codering kan ik geen enkele functieselectie uitvoeren om het belang van de functies te bepalen.

Wat raden jullie aan?


Antwoord 1, autoriteit 100%

Aanpak 1: u kunt panda’s gebruiken’ pd.get_dummies.

Voorbeeld 1:

import pandas as pd
s = pd.Series(list('abca'))
pd.get_dummies(s)
Out[]: 
     a    b    c
0  1.0  0.0  0.0
1  0.0  1.0  0.0
2  0.0  0.0  1.0
3  1.0  0.0  0.0

Voorbeeld 2:

Het volgende zal een bepaalde kolom transformeren in één hot. Gebruik het voorvoegsel om meerdere dummies te hebben.

import pandas as pd
df = pd.DataFrame({
          'A':['a','b','a'],
          'B':['b','a','c']
        })
df
Out[]: 
   A  B
0  a  b
1  b  a
2  a  c
# Get one hot encoding of columns B
one_hot = pd.get_dummies(df['B'])
# Drop column B as it is now encoded
df = df.drop('B',axis = 1)
# Join the encoded df
df = df.join(one_hot)
df  
Out[]: 
       A  a  b  c
    0  a  0  1  0
    1  b  1  0  0
    2  a  0  0  1

Aanpak 2: Scikit-learn gebruiken

Een OneHotEncoderheeft het voordeel dat het kan fitop sommige trainingsgegevens en vervolgens transformop andere gegevens met dezelfde instantie. We hebben ook handle_unknownom verder te controleren wat de encoder doet met ongezienegegevens.

Gegeven een dataset met drie functies en vier voorbeelden, laten we de encoder de maximale waarde per functie vinden en de gegevens transformeren naar een binaire one-hot-codering.

>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])   
OneHotEncoder(categorical_features='all', dtype=<class 'numpy.float64'>,
   handle_unknown='error', n_values='auto', sparse=True)
>>> enc.n_values_
array([2, 3, 4])
>>> enc.feature_indices_
array([0, 2, 5, 9], dtype=int32)
>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])

Hier is de link voor dit voorbeeld: http:// scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html


Antwoord 2, autoriteit 44%

Veel gemakkelijker te gebruiken Panda’s voor standaard one-hot-codering. Als u op zoek bent naar meer opties, kunt u scikit-learngebruiken.

Voor eenvoudige one-hot-codering met Panda’sgeef je je dataframe door aan de functie get_dummies.

Als ik bijvoorbeeld een dataframe heb met de naam imdb_movies:

voer hier de afbeeldingsbeschrijving in

…en ik wil de kolom ‘Gewaardeerd’ in één keer coderen, ik doe dit:

pd.get_dummies(imdb_movies.Rated)

voer hier de afbeeldingsbeschrijving in

Dit retourneert een nieuw dataframemet een kolom voor elk “niveau” van bestaande beoordeling, samen met een 1 of 0 die de aanwezigheid van die beoordeling voor een gegeven observatie.

Meestal willen we dat dit deel uitmaakt van het originele dataframe. In dit geval bevestigen we ons nieuwe dummy-gecodeerde frame op het originele frame met behulp van “column-binding.

We kunnen kolom-binden door Panda’s concatfunctie te gebruiken:

rated_dummies = pd.get_dummies(imdb_movies.Rated)
pd.concat([imdb_movies, rated_dummies], axis=1)

voer hier de afbeeldingsbeschrijving in

We kunnen nu een analyse uitvoeren op ons volledige dataframe.

EENVOUDIGE HULPFUNCTIE

Ik raad je aan om een ​​hulpfunctievoor jezelf te maken om dit snel te doen:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    return(res)

Gebruik:

encode_and_bind(imdb_movies, 'Rated')

Resultaat:

voer hier de afbeeldingsbeschrijving in

Ook, volgens de opmerking van @pmalbu, als je wilt dat de functie de originele feature_to_encode verwijdert, gebruik dan deze versie:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    res = res.drop([feature_to_encode], axis=1)
    return(res) 

U kunt als volgt meerdere functies tegelijk coderen:

features_to_encode = ['feature_1', 'feature_2', 'feature_3',
                      'feature_4']
for feature in features_to_encode:
    res = encode_and_bind(train_set, feature)

Antwoord 3, autoriteit 15%

Je kunt het doen met numpy.eyeen a met behulp van het selectiemechanisme voor array-elementen:

import numpy as np
nb_classes = 6
data = [[2, 3, 4, 0]]
def indices_to_one_hot(data, nb_classes):
    """Convert an iterable of indices to one-hot encoded labels."""
    targets = np.array(data).reshape(-1)
    return np.eye(nb_classes)[targets]

De retourwaarde van indices_to_one_hot(nb_classes, data)is nu

array([[[ 0.,  0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  1.,  0.],
        [ 1.,  0.,  0.,  0.,  0.,  0.]]])

De .reshape(-1)is er om ervoor te zorgen dat je het juiste labelformaat hebt (je hebt misschien ook [[2], [3], [4], [0]]).


Antwoord 4, autoriteit 11%

Ten eerste, de gemakkelijkste manier om één hot codering te krijgen: gebruik Sklearn.

http://scikit-learn.org/stable/ modules/generated/sklearn.preprocessing.OneHotEncoder.html

Ten tweede denk ik dat het niet zo eenvoudig is om panda’s te gebruiken voor één hot codering (hoewel niet bevestigd)

Dummy-variabelen maken in panda’s voor python

Ten slotte, is het nodig dat u één hot-encode uitvoert? Eén hot-codering verhoogt het aantal functies exponentieel, waardoor de looptijd van elke classifier of iets anders dat u gaat uitvoeren drastisch wordt verlengd. Vooral wanneer elke categorische functie veel niveaus heeft. In plaats daarvan kun je dummy coderen.

Het gebruik van dummy-codering werkt meestal goed, voor veel minder runtime en complexiteit. Een wijze prof zei ooit tegen mij: ‘Less is More’.

Hier is de code voor mijn aangepaste coderingsfunctie als je wilt.

from sklearn.preprocessing import LabelEncoder
#Auto encodes any dataframe column of type category or object.
def dummyEncode(df):
        columnsToEncode = list(df.select_dtypes(include=['category','object']))
        le = LabelEncoder()
        for feature in columnsToEncode:
            try:
                df[feature] = le.fit_transform(df[feature])
            except:
                print('Error encoding '+feature)
        return df

EDIT: vergelijking om duidelijker te zijn:

One-hot codering: converteer n niveaus naar n-1 kolommen.

Index  Animal         Index  cat  mouse
  1     dog             1     0     0
  2     cat       -->   2     1     0
  3    mouse            3     0     1

Je kunt zien hoe dit je geheugen zal exploderen als je veel verschillende typen (of niveaus) in je categorische functie hebt. Houd er rekening mee dat dit slechts EEN kolom is.

Dummy-codering:

Index  Animal         Index  Animal
  1     dog             1      0   
  2     cat       -->   2      1 
  3    mouse            3      2

In plaats daarvan converteren naar numerieke weergaven. Bespaart veel ruimte voor functies, ten koste van een beetje nauwkeurigheid.


Antwoord 5, autoriteit 10%

Eén hot codering met panda’s is heel eenvoudig:

def one_hot(df, cols):
    """
    @param df pandas DataFrame
    @param cols a list of columns to encode 
    @return a DataFrame with one-hot encoding
    """
    for each in cols:
        dummies = pd.get_dummies(df[each], prefix=each, drop_first=False)
        df = pd.concat([df, dummies], axis=1)
    return df

BEWERKEN:

Een andere manier om one_hot te gebruiken met sklearn’s LabelBinarizer:

from sklearn.preprocessing import LabelBinarizer 
label_binarizer = LabelBinarizer()
label_binarizer.fit(all_your_labels_list) # need to be global or remembered to use it later
def one_hot_encode(x):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
    """
    return label_binarizer.transform(x)

Antwoord 6, autoriteit 8%

U kunt de numpy.eye-functie gebruiken.

import numpy as np
def one_hot_encode(x, n_classes):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
     """
    return np.eye(n_classes)[x]
def main():
    list = [0,1,2,3,4,3,2,1,0]
    n_classes = 5
    one_hot_list = one_hot_encode(list, n_classes)
    print(one_hot_list)
if __name__ == "__main__":
    main()

Resultaat

D:\Desktop>python test.py
[[ 1.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]]

Antwoord 7, autoriteit 4%

panda’s hebben een ingebouwde functie “get_dummies” om één hot-codering van die bepaalde kolom/kolommen te krijgen.

één regel code voor één-hot-codering:

df=pd.concat([df,pd.get_dummies(df['column name'],prefix='column name')],axis=1).drop(['column name'],axis=1)

Antwoord 8, autoriteit 2%

Hier is een oplossing met behulp van DictVectorizeren de Pandas DataFrame.to_dict('records')methode.

>>> import pandas as pd
>>> X = pd.DataFrame({'income': [100000,110000,90000,30000,14000,50000],
                      'country':['US', 'CAN', 'US', 'CAN', 'MEX', 'US'],
                      'race':['White', 'Black', 'Latino', 'White', 'White', 'Black']
                     })
>>> from sklearn.feature_extraction import DictVectorizer
>>> v = DictVectorizer()
>>> qualitative_features = ['country','race']
>>> X_qual = v.fit_transform(X[qualitative_features].to_dict('records'))
>>> v.vocabulary_
{'country=CAN': 0,
 'country=MEX': 1,
 'country=US': 2,
 'race=Black': 3,
 'race=Latino': 4,
 'race=White': 5}
>>> X_qual.toarray()
array([[ 0.,  0.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.,  1.,  0.],
       [ 1.,  0.,  0.,  0.,  0.,  1.],
       [ 0.,  1.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  1.,  1.,  0.,  0.]])

Antwoord 9

One-hot codering vereist iets meer dan het converteren van de waarden naar indicatorvariabelen. Normaal gesproken vereist het ML-proces dat u deze codering meerdere keren toepast op validatie- of testgegevenssets en het model dat u maakt, toepast op realtime geobserveerde gegevens. U moet de toewijzing (transformatie) opslaan die is gebruikt om het model te construeren. Een goede oplossing zou de DictVectorizerof LabelEncodergebruiken (gevolgd door get_dummies. Hier is een functie die u kunt gebruiken:

def oneHotEncode2(df, le_dict = {}):
    if not le_dict:
        columnsToEncode = list(df.select_dtypes(include=['category','object']))
        train = True;
    else:
        columnsToEncode = le_dict.keys()   
        train = False;
    for feature in columnsToEncode:
        if train:
            le_dict[feature] = LabelEncoder()
        try:
            if train:
                df[feature] = le_dict[feature].fit_transform(df[feature])
            else:
                df[feature] = le_dict[feature].transform(df[feature])
            df = pd.concat([df, 
                              pd.get_dummies(df[feature]).rename(columns=lambda x: feature + '_' + str(x))], axis=1)
            df = df.drop(feature, axis=1)
        except:
            print('Error encoding '+feature)
            #df[feature]  = df[feature].convert_objects(convert_numeric='force')
            df[feature]  = df[feature].apply(pd.to_numeric, errors='coerce')
    return (df, le_dict)

Dit werkt op een panda-dataframe en voor elke kolom van het dataframe wordt een toewijzing gemaakt en geretourneerd. Dus je zou het zo noemen:

train_data, le_dict = oneHotEncode2(train_data)

Vervolgens op de testgegevens wordt de oproep gedaan door het woordenboek door te geven dat terugkomt van de training:

test_data, _ = oneHotEncode2(test_data, le_dict)

Een equivalente methode is om DictVectorizerte gebruiken. Een gerelateerd bericht hierover staat op mijn blog. Ik noem het hier omdat het enige redenering geeft achter deze aanpak door simpelweg get_dummies te gebruiken post(openbaarmaking: dit is mijn eigen blog).


Antwoord 10

Je kunt de gegevens zonder codering doorgeven aan de catboost-classificatie. Catboost verwerkt categorische variabelen zelf door one-hot en target-expandering mean-codering uit te voeren.


Antwoord 11

U kunt ook het volgende doen. Opmerking voor het onderstaande hoeft u pd.concatniet te gebruiken.

import pandas as pd 
# intialise data of lists. 
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
       'Group':[1,2,1,2]} 
# Create DataFrame 
df = pd.DataFrame(data) 
for _c in df.select_dtypes(include=['object']).columns:
    print(_c)
    df[_c]  = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed

U kunt expliciete kolommen ook wijzigen in categorisch. Hier verander ik bijvoorbeeld de Coloren Group

import pandas as pd 
# intialise data of lists. 
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
       'Group':[1,2,1,2]} 
# Create DataFrame 
df = pd.DataFrame(data) 
columns_to_change = list(df.select_dtypes(include=['object']).columns)
columns_to_change.append('Group')
for _c in columns_to_change:
    print(_c)
    df[_c]  = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed

Antwoord 12

Ik weet dat ik te laat ben voor dit feestje, maar de eenvoudigste manier om een ​​dataframe geautomatiseerd te coderen, is door deze functie te gebruiken:

def hot_encode(df):
    obj_df = df.select_dtypes(include=['object'])
    return pd.get_dummies(df, columns=obj_df.columns).values

Antwoord 13

Dit werkt voor mij:

pandas.factorize( ['B', 'C', 'D', 'B'] )[0]

Uitvoer:

[0, 1, 2, 0]

Antwoord 14

Ik heb dit gebruikt in mijn akoestische model:
waarschijnlijk helpt dit in je model.

def one_hot_encoding(x, n_out):
    x = x.astype(int)  
    shape = x.shape
    x = x.flatten()
    N = len(x)
    x_categ = np.zeros((N,n_out))
    x_categ[np.arange(N), x] = 1
    return x_categ.reshape((shape)+(n_out,))

Antwoord 15

Kort antwoord

Hier is een functie om one-hot-encoding uit te voeren zondernumpy, panda’s of andere pakketten te gebruiken. Er is een lijst met gehele getallen, booleans of strings nodig (en misschien ook andere typen).

import typing
def one_hot_encode(items: list) -> typing.List[list]:
    results = []
    # find the unique items (we want to unique items b/c duplicate items will have the same encoding)
    unique_items = list(set(items))
    # sort the unique items
    sorted_items = sorted(unique_items)
    # find how long the list of each item should be
    max_index = len(unique_items)
    for item in items:
        # create a list of zeros the appropriate length
        one_hot_encoded_result = [0 for i in range(0, max_index)]
        # find the index of the item
        one_hot_index = sorted_items.index(item)
        # change the zero at the index from the previous line to a one
        one_hot_encoded_result[one_hot_index] = 1
        # add the result
        results.append(one_hot_encoded_result)
    return results

Voorbeeld:

one_hot_encode([2, 1, 1, 2, 5, 3])
# [[0, 1, 0, 0],
#  [1, 0, 0, 0],
#  [1, 0, 0, 0],
#  [0, 1, 0, 0],
#  [0, 0, 0, 1],
#  [0, 0, 1, 0]]
one_hot_encode([True, False, True])
# [[0, 1], [1, 0], [0, 1]]
one_hot_encode(['a', 'b', 'c', 'a', 'e'])
# [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0], [0, 0, 0, 1]]

Lang(er) antwoord

Ik weet dat er al veel antwoorden op deze vraag zijn, maar ik heb twee dingen opgemerkt. Ten eerste gebruiken de meeste antwoorden pakketten zoals numpy en/of panda’s. En dit is een goede zaak. Als je productiecode schrijft, zou je waarschijnlijk robuuste, snelle algoritmen moeten gebruiken zoals die in de numpy/pandas-pakketten. Maar omwille van het onderwijs vind ik dat iemand een antwoord moet geven dat een transparant algoritme heeft en niet alleen een implementatie van het algoritme van iemand anders. Ten tweede merkte ik dat veel van de antwoorden geen robuuste implementatie van one-hot-codering bieden omdat ze niet voldoen aan een van de onderstaande vereisten. Hieronder staan ​​enkele van de vereisten (zoals ik ze zie) voor een nuttige, nauwkeurige en robuuste one-hot coderingsfunctie:

Een one-hot coderingsfunctie moet:

  • lijst van verschillende typen (bijv. gehele getallen, strings, floats, etc.) als invoer verwerken
  • een invoerlijst met duplicaten behandelen
  • retourneer een lijst met lijsten die overeenkomen (in dezelfde volgorde als) met de invoer
  • retourneer een lijst met lijsten waarbij elke lijst zo kort mogelijk is

Ik heb veel van de antwoorden op deze vraag getest en de meeste voldoen niet aan een van de bovenstaande vereisten.


Antwoord 16

Laat me, om andere vragen toe te voegen, uitleggen hoe ik het deed met een Python 2.0-functie met Numpy:

def one_hot(y_):
    # Function to encode output labels from number indexes 
    # e.g.: [[5], [0], [3]] --> [[0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]
    y_ = y_.reshape(len(y_))
    n_values = np.max(y_) + 1
    return np.eye(n_values)[np.array(y_, dtype=np.int32)]  # Returns FLOATS

De regel n_values = np.max(y_) + 1kan hard-coded zijn zodat je het goede aantal neuronen kunt gebruiken in het geval je bijvoorbeeld mini-batches gebruikt.

Demoproject/tutorial waarbij deze functie is gebruikt:
https://github.com/guillaume-chevalier/LSTM-Human-Activity- Erkenning


Antwoord 17

Het kan en moet eenvoudig zijn als:

class OneHotEncoder:
    def __init__(self,optionKeys):
        length=len(optionKeys)
        self.__dict__={optionKeys[j]:[0 if i!=j else 1 for i in range(length)] for j in range(length)}

Gebruik:

ohe=OneHotEncoder(["A","B","C","D"])
print(ohe.A)
print(ohe.D)

Antwoord 18

Uitbreiding van het antwoord van @Martin Thoma

def one_hot_encode(y):
    """Convert an iterable of indices to one-hot encoded labels."""
    y = y.flatten() # Sometimes not flattened vector is passed e.g (118,1) in these cases
    # the function ends up creating a tensor e.g. (118, 2, 1). flatten removes this issue
    nb_classes = len(np.unique(y)) # get the number of unique classes
    standardised_labels = dict(zip(np.unique(y), np.arange(nb_classes))) # get the class labels as a dictionary
    # which then is standardised. E.g imagine class labels are (4,7,9) if a vector of y containing 4,7 and 9 is
    # directly passed then np.eye(nb_classes)[4] or 7,9 throws an out of index error.
    # standardised labels fixes this issue by returning a dictionary;
    # standardised_labels = {4:0, 7:1, 9:2}. The values of the dictionary are mapped to keys in y array.
    # standardised_labels also removes the error that is raised if the labels are floats. E.g. 1.0; element
    # cannot be called by an integer index e.g y[1.0] - throws an index error.
    targets = np.vectorize(standardised_labels.get)(y) # map the dictionary values to array.
    return np.eye(nb_classes)[targets]

Antwoord 19

Probeer dit:

!pip install category_encoders
import category_encoders as ce
categorical_columns = [...the list of names of the columns you want to one-hot-encode ...]
encoder = ce.OneHotEncoder(cols=categorical_columns, use_cat_names=True)
df_train_encoded = encoder.fit_transform(df_train_small)

df_encoded.head()

Het resulterende dataframe df_train_encodedis hetzelfde als het origineel, maar de categorische kenmerken zijn nu vervangen door hun one-hot-encoded versies.

Meer informatie over category_encodershier.


Antwoord 20

Hier heb ik het met deze aanpak geprobeerd:

import numpy as np
#converting to one_hot
def one_hot_encoder(value, datal):
    datal[value] = 1
    return datal
def _one_hot_values(labels_data):
    encoded = [0] * len(labels_data)
    for j, i in enumerate(labels_data):
        max_value = [0] * (np.max(labels_data) + 1)
        encoded[j] = one_hot_encoder(i, max_value)
    return np.array(encoded)

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes