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:
-
Ik heb het treinbestand gelezen:
num_rows_to_read = 10000 train_small = pd.read_csv("../../dataset/train.csv", nrows=num_rows_to_read)
-
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')
-
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 OneHotEncoder
heeft het voordeel dat het kan fit
op sommige trainingsgegevens en vervolgens transform
op andere gegevens met dezelfde instantie. We hebben ook handle_unknown
om 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-learn
gebruiken.
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:
…en ik wil de kolom ‘Gewaardeerd’ in één keer coderen, ik doe dit:
pd.get_dummies(imdb_movies.Rated)
Dit retourneert een nieuw dataframe
met 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)
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:
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.eye
en 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 DictVectorizer
en 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 DictVectorizer
of LabelEncoder
gebruiken (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 DictVectorizer
te 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.concat
niet 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 Color
en 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_) + 1
kan 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_encoded
is hetzelfde als het origineel, maar de categorische kenmerken zijn nu vervangen door hun one-hot-encoded versies.
Meer informatie over category_encoders
hier.
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)