Scikit-learn'da birden çok sütun üzerinde etiket kodlaması


218

Scikit-learn'ın dize etiketlerinin LabelEncoderbir panda kodlamak için kullanmaya çalışıyorum DataFrame. Dataframe birçok (50+) sütun olduğundan, LabelEncoderher sütun için bir nesne oluşturmaktan kaçınmak istiyorum ; Tüm veri sütunlarımda LabelEncoderçalışan tek bir büyük nesneye sahip olmayı tercih ederim .

Tümünün DataFrameiçine LabelEncoderatılması aşağıdaki hatayı oluşturur. Burada kukla veriler kullandığımı lütfen unutmayın; Aslında ben yaklaşık 50 sütun dize etiketli veri ile ilgileniyorum, bu yüzden ada göre herhangi bir sütun referans vermeyen bir çözüm gerekir.

import pandas
from sklearn import preprocessing 

df = pandas.DataFrame({
    'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'], 
    'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'], 
    'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego', 
                 'New_York']
})

le = preprocessing.LabelEncoder()

le.fit(df)

Geri izleme (en son çağrı): "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py" Dosyasında "", 1. satır, fit y = column_or_1d (y, warn = True) Dosya "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", satır 306, column_or_1d içinde ValueError ("hatalı girdi şekli { 0} ". Biçimi (şekil) ValueError: hatalı giriş şekli (6, 3)

Bu sorunun üstesinden gelmek için herhangi bir düşünceniz var mı?


Bunu neden yapmaya çalışıyorsun?
Fred Foo

Çok sütunlu dataframedize verilerinin kodlanmasını basitleştirmek için . Ben kodlama nesneleri (ler) piclking, bu yüzden 50 ayrı nesneleri turşu / unpickle kaçınmak istiyorum. Ayrıca, kodlayıcının verileri basitleştirmesinin bir yolu olup olmadığını merak ediyorum, yani her sütundaki değişkenlerin her benzersiz kombinasyonu için bir tanımlayıcı ile bir satır döndürmek.
Bryan

Tüm bunları pandalarda bir sözlük sözlüğü replaceyöntemine geçirerek yapmanın basit bir yolu var . Aşağıdaki cevaba bakınız
Ted Petrou

Yanıtlar:


453

Bunu kolayca yapabilirsiniz,

df.apply(LabelEncoder().fit_transform)

EDIT2:

Scikit-learn 0.20'de önerilen yol

OneHotEncoder().fit_transform(df)

OneHotEncoder artık dize girişini desteklediğinden. ColumnTransformer ile OneHotEncoder'ı yalnızca belirli sütunlara uygulamak mümkündür.

DÜZENLE:

Bu cevap bir yıldan daha uzun bir süre önce olduğundan ve (bir ödül de dahil olmak üzere) birçok upvotes oluşturduğundan, muhtemelen bunu daha da genişletmeliyim.

Invers_transform ve transform için biraz hack yapmalısınız.

from collections import defaultdict
d = defaultdict(LabelEncoder)

Bununla, artık tüm sütunları LabelEncodersözlük olarak saklıyorsunuz.

# Encoding the variable
fit = df.apply(lambda x: d[x.name].fit_transform(x))

# Inverse the encoded
fit.apply(lambda x: d[x.name].inverse_transform(x))

# Using the dictionary to label future data
df.apply(lambda x: d[x.name].transform(x))

1
Bu şaşırtıcı, ama bu durumda ters dönüşümü nasıl uygulayabiliriz?
Supreeth Meka

10
Ama bu çözümü bir boru hattında kullanmak istiyorsanız, örneğin ayrı uyum ve dönüşüm (trende uyum ve daha sonra test setinde kullan -> öğrenilen sözlüğü yeniden kullanma) bu ile destekleniyor df.apply(LabelEncoder().fit_transform)mu?
Georg Heiler

2
LabelBinarizerBunun yerine bununla çalışmak ve bir test seti için sözlüğü yeniden kullanmak nasıl yapılabilir ? Denedim d = defaultdict(LabelBinarizer)ve sonra fit = df.apply(lambda x: d[x.name].fit_transform(x))ancak bir istisna yükseltilir: Exception: Data must be 1-dimensional. Nasıl ortaya çıkan DataFrame gibi görünmesini beklemek emin değilim ... belki her sütun ikili vektörleri tutmak gerekir.
Qululu

4
Güzel çözüm. Sadece belirli bir sütunda nasıl dönüşüm yapılır?
stenlytw

1
bir sütun için kodlama juste ters yapmak istiyorsanız, nasıl yaparım?
Ib D

95

Larsmans tarafından belirtildiği gibi, LabelEncoder () sadece 1-d dizisini argüman olarak alır . Bununla birlikte, seçtiğiniz birden çok sütun üzerinde çalışan ve dönüştürülmüş bir veri çerçevesi döndüren kendi etiket kodlayıcınızı yuvarlamak oldukça kolaydır. Buradaki kodum kısmen Zac Stewart'ın burada bulunan mükemmel blog yazısına dayanıyor .

Özel bir kodlayıcı oluşturma basitçe bir sınıf oluşturarak içerdiğini ye yanıt verir fit(), transform()ve fit_transform()yöntemlerle. Sizin durumunuzda, iyi bir başlangıç ​​böyle bir şey olabilir:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline

# Create some toy data in a Pandas dataframe
fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4]
})

class MultiColumnLabelEncoder:
    def __init__(self,columns = None):
        self.columns = columns # array of column names to encode

    def fit(self,X,y=None):
        return self # not relevant here

    def transform(self,X):
        '''
        Transforms columns of X specified in self.columns using
        LabelEncoder(). If no columns specified, transforms all
        columns in X.
        '''
        output = X.copy()
        if self.columns is not None:
            for col in self.columns:
                output[col] = LabelEncoder().fit_transform(output[col])
        else:
            for colname,col in output.iteritems():
                output[colname] = LabelEncoder().fit_transform(col)
        return output

    def fit_transform(self,X,y=None):
        return self.fit(X,y).transform(X)

Sayısal niteliği tek başına bırakırken iki kategorik özelliğimizi ( fruitve color) kodlamak istediğimizi varsayalım weight. Bunu şu şekilde yapabiliriz:

MultiColumnLabelEncoder(columns = ['fruit','color']).fit_transform(fruit_data)

Bu da fruit_dataveri setimizi

resim açıklamasını buraya girin için

resim açıklamasını buraya girin

Tamamen kategorik değişkenlerden oluşan bir veri çerçevesini geçirmek ve columnsparametreyi atlamak her sütunun kodlanmasına neden olur (ki aslında aradığınız şey olduğuna inanıyorum):

MultiColumnLabelEncoder().fit_transform(fruit_data.drop('weight',axis=1))

Bu dönüşüyor

resim açıklamasını buraya girin için

resim açıklamasını buraya girin.

Zaten sayısal olan nitelikleri kodlamaya çalıştığında muhtemelen boğulacağını unutmayın (isterseniz bunu işlemek için bir kod ekleyin).

Bununla ilgili bir başka güzel özellik de, bu özel trafoyu bir boru hattında kullanabilmemizdir:

encoding_pipeline = Pipeline([
    ('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
    # add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)

2
Az önce veriler bir portakalın yeşil renkte olduğunu ima etti. Hata. ;)
PriceHardman 15:15

5
Bu bir kez veri dönüştürmek için iyi bir yoldur, ancak bir doğrulama kümesinde bu dönüşümü yeniden kullanmak istersem. tekrar fit_transform kullanmanız gerekir ve yeni veri kümem tüm değişkenler için tüm kategorilere sahip olmamak gibi sorunlar ortaya çıkabilir. Örneğin, yeni renk kümemde yeşil rengin görünmediğini varsayalım. bu kodlamayı bozacaktır.
Ben

3
@Ben ile aynı fikirde. Bu aslında yöntem adlarının ötesinde sklearn'i taklit etmez. Bunu bir Pipeline'a
koymaya çalışırsanız

3
Etiket kodlamanın hem tren hem de test setlerinde tutarlı olduğundan emin olmak için kodlamayı tüm veri kümenizde (tren + test) gerçekleştirmek istersiniz. Bu, onları trene ve teste bölmeden önce yapılabilir veya bunları birleştirebilir, kodlamayı gerçekleştirebilir ve tekrar bölebilirsiniz.
PriceHardman

2
Geri gitmeye ne dersin? orijinaline geri mi?
user702846

18

0.20 scikit-öğrenme yana kullanabilirsiniz sklearn.compose.ColumnTransformerve sklearn.preprocessing.OneHotEncoder:

Yalnızca kategorik değişkenleriniz varsa, OneHotEncoderdoğrudan:

from sklearn.preprocessing import OneHotEncoder

OneHotEncoder(handle_unknown='ignore').fit_transform(df)

Heterojen olarak yazılan özelliklere sahipseniz:

from sklearn.compose import make_column_transformer
from sklearn.preprocessing import RobustScaler
from sklearn.preprocessing import OneHotEncoder

categorical_columns = ['pets', 'owner', 'location']
numerical_columns = ['age', 'weigth', 'height']
column_trans = make_column_transformer(
    (categorical_columns, OneHotEncoder(handle_unknown='ignore'),
    (numerical_columns, RobustScaler())
column_trans.fit_transform(df)

Belgelerdeki diğer seçenekler: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data


inverse_transform()olsa da ColumnTransformer'da desteklenmiyor. En azından şimdilik değil: github.com/scikit-learn/scikit-learn/issues/11463 . Bu, başvurum için büyük bir dezavantaj ve muhtemelen başkaları için de olacak.
Sander Vanden Hautte

16

LabelEncoder'a ihtiyacımız yok.

Sütunları kategorilere dönüştürebilir ve daha sonra kodlarını alabilirsiniz. Bu işlemi her sütuna uygulamak ve sonucu aynı indeksler ve sütun adları ile aynı şekildeki bir veri çerçevesine geri sarmak için aşağıda bir sözlük kavrama kullandım.

>>> pd.DataFrame({col: df[col].astype('category').cat.codes for col in df}, index=df.index)
   location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

Bir eşleme sözlüğü oluşturmak için, bir sözlük kavrayışı kullanarak kategorileri numaralandırabilirsiniz:

>>> {col: {n: cat for n, cat in enumerate(df[col].astype('category').cat.categories)} 
     for col in df}

{'location': {0: 'New_York', 1: 'San_Diego'},
 'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
 'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}

Bir sütun için geri (geri) gitmek istersem (örnek hedef değişkeni: Y) nasıl yaparım?
Ib D

9

bu doğrudan sorunuza cevap vermiyor (hangi Naputipulu Jon ve PriceHardman'ın harika cevapları var)

Ancak, birkaç sınıflandırma görevi vb. Amacıyla

pandas.get_dummies(input_df) 

bu, kategorik verilerle veri çerçevesi girebilir ve ikili değerlere sahip bir veri çerçevesi döndürebilir. değişken değerler, sonuçta elde edilen veri çerçevesinde sütun adlarına kodlanır. Daha


6

sklearn.preprocessing.LabelEncoder()Sütunlarınızı temsil etmek için kullanılabilecek bir nesne almaya çalıştığınızı varsayarsak , tek yapmanız gereken:

le.fit(df.columns)

Yukarıdaki kodda, her sütuna karşılık gelen benzersiz bir sayıya sahip olacaksınız. 1 eşleştirmesini: Daha doğrusu, bir 1 olacak df.columnskadar le.transform(df.columns.get_values()). Bir sütunun kodlamasını almak için basitçe şuraya iletin le.transform(...). Örnek olarak, aşağıdakiler her bir sütunun kodlamasını alır:

le.transform(df.columns.get_values())

sklearn.preprocessing.LabelEncoder()Tüm satır etiketleriniz için bir nesne oluşturmak istediğinizi varsayarsak , aşağıdakileri yapabilirsiniz:

le.fit([y for x in df.get_values() for y in x])

Bu durumda, büyük olasılıkla benzersiz olmayan satır etiketleriniz vardır (sorunuzda gösterildiği gibi). Kodlayıcının hangi sınıfları oluşturduğunu görmek için yapabilirsiniz le.classes_. Bunun içinde olduğu gibi aynı öğelere sahip olması gerektiğini göreceksiniz set(y for x in df.get_values() for y in x). Bir satır etiketini kodlanmış bir etikete dönüştürmek için bir kez daha kullanın le.transform(...). Örnek olarak, df.columnsdizideki ilk sütunun ve ilk satırın etiketini almak istiyorsanız , bunu yapabilirsiniz:

le.transform([df.get_value(0, df.columns[0])])

Yorumunuzdaki soru biraz daha karmaşıktır, ancak yine de başarılabilir:

le.fit([str(z) for z in set((x[0], y) for x in df.iteritems() for y in x[1])])

Yukarıdaki kod aşağıdakileri yapar:

  1. Tüm sütunların (sütun, satır) benzersiz bir kombinasyonunu oluşturun
  2. Her çifti, dizenin dize sürümü olarak gösterin. Bu, üstesinden gelmek için bir çözümdür.LabelEncoder bir sınıf adı olarak tuples desteklemeyen sınıfın çözümdür.
  3. Yeni öğeleri LabelEncoder.

Şimdi bu yeni modeli kullanmak biraz daha karmaşık. Önceki örnekte (df.columns'taki ilk sütun ve ilk satır) aradığımız aynı öğenin temsilini çıkarmak istediğimizi varsayarsak, bunu yapabiliriz:

le.transform([str((df.columns[0], df.get_value(0, df.columns[0])))])

Her aramanın artık (sütun, satır) içeren bir dizenin dize ile temsil edildiğini unutmayın.


5

Hayır, LabelEncoderbunu yapmaz. 1-d sınıf etiket dizileri alır ve 1-d diziler üretir. Sınıf etiketlerini rasgele verilerde değil sınıflandırma sorunlarıyla başa çıkmak için tasarlanmıştır ve diğer kullanımlara zorlama girişimleri, asıl problemi çözdüğü soruna (ve çözümü orijinal alana geri) dönüştürmek için kod gerektirir.


Tamam, bu göz önüne alındığında, dize etiketlerini DataFramebir kerede bir bütün olarak kodlayabilmemin en iyi yolu hakkındaki öneriniz nedir?
Bryan

@Bryan Koda bakın LabelEncoderve uyarlayın. Pandaları kendim kullanmıyorum, bu yüzden ne kadar zor olacağını bilmiyorum.
Fred Foo

Diğer pandasinsanların da bu soruya çatlak olmasına izin vereceğim - eminim bu zorluğa sahip olan tek kişi ben değilim, bu yüzden umarım orada önceden oluşturulmuş bir çözüm olabilir.
Bryan

5

Bu gerçeğin üzerinden bir buçuk yıl sonra, ama ben de .transform()aynı anda birden fazla panda veri çerçevesi sütununu yapabilmek (ve .inverse_transform()bunları yapabilmek ) gerekiyordu. Bu, yukarıdaki @PriceHardman'ın mükemmel önerisi üzerine genişliyor:

class MultiColumnLabelEncoder(LabelEncoder):
    """
    Wraps sklearn LabelEncoder functionality for use on multiple columns of a
    pandas dataframe.

    """
    def __init__(self, columns=None):
        self.columns = columns

    def fit(self, dframe):
        """
        Fit label encoder to pandas columns.

        Access individual column classes via indexig `self.all_classes_`

        Access individual column encoders via indexing
        `self.all_encoders_`
        """
        # if columns are provided, iterate through and get `classes_`
        if self.columns is not None:
            # ndarray to hold LabelEncoder().classes_ for each
            # column; should match the shape of specified `columns`
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            self.all_encoders_ = np.ndarray(shape=self.columns.shape,
                                            dtype=object)
            for idx, column in enumerate(self.columns):
                # fit LabelEncoder to get `classes_` for the column
                le = LabelEncoder()
                le.fit(dframe.loc[:, column].values)
                # append the `classes_` to our ndarray container
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                # append this column's encoder
                self.all_encoders_[idx] = le
        else:
            # no columns specified; assume all are to be encoded
            self.columns = dframe.iloc[:, :].columns
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            for idx, column in enumerate(self.columns):
                le = LabelEncoder()
                le.fit(dframe.loc[:, column].values)
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
        return self

    def fit_transform(self, dframe):
        """
        Fit label encoder and return encoded labels.

        Access individual column classes via indexing
        `self.all_classes_`

        Access individual column encoders via indexing
        `self.all_encoders_`

        Access individual column encoded labels via indexing
        `self.all_labels_`
        """
        # if columns are provided, iterate through and get `classes_`
        if self.columns is not None:
            # ndarray to hold LabelEncoder().classes_ for each
            # column; should match the shape of specified `columns`
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            self.all_encoders_ = np.ndarray(shape=self.columns.shape,
                                            dtype=object)
            self.all_labels_ = np.ndarray(shape=self.columns.shape,
                                          dtype=object)
            for idx, column in enumerate(self.columns):
                # instantiate LabelEncoder
                le = LabelEncoder()
                # fit and transform labels in the column
                dframe.loc[:, column] =\
                    le.fit_transform(dframe.loc[:, column].values)
                # append the `classes_` to our ndarray container
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
                self.all_labels_[idx] = le
        else:
            # no columns specified; assume all are to be encoded
            self.columns = dframe.iloc[:, :].columns
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            for idx, column in enumerate(self.columns):
                le = LabelEncoder()
                dframe.loc[:, column] = le.fit_transform(
                        dframe.loc[:, column].values)
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
        return dframe.loc[:, self.columns].values

    def transform(self, dframe):
        """
        Transform labels to normalized encoding.
        """
        if self.columns is not None:
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[
                    idx].transform(dframe.loc[:, column].values)
        else:
            self.columns = dframe.iloc[:, :].columns
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .transform(dframe.loc[:, column].values)
        return dframe.loc[:, self.columns].values

    def inverse_transform(self, dframe):
        """
        Transform labels back to original encoding.
        """
        if self.columns is not None:
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .inverse_transform(dframe.loc[:, column].values)
        else:
            self.columns = dframe.iloc[:, :].columns
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .inverse_transform(dframe.loc[:, column].values)
        return dframe.loc[:, self.columns].values

Misal:

Eğer dfve df_copy()karma türüdür pandasdataframes, uygulayabilirsiniz MultiColumnLabelEncoder()için dtype=objectşu şekilde sütunlar:

# get `object` columns
df_object_columns = df.iloc[:, :].select_dtypes(include=['object']).columns
df_copy_object_columns = df_copy.iloc[:, :].select_dtypes(include=['object']).columns

# instantiate `MultiColumnLabelEncoder`
mcle = MultiColumnLabelEncoder(columns=object_columns)

# fit to `df` data
mcle.fit(df)

# transform the `df` data
mcle.transform(df)

# returns output like below
array([[1, 0, 0, ..., 1, 1, 0],
       [0, 5, 1, ..., 1, 1, 2],
       [1, 1, 1, ..., 1, 1, 2],
       ..., 
       [3, 5, 1, ..., 1, 1, 2],

# transform `df_copy` data
mcle.transform(df_copy)

# returns output like below (assuming the respective columns 
# of `df_copy` contain the same unique values as that particular 
# column in `df`
array([[1, 0, 0, ..., 1, 1, 0],
       [0, 5, 1, ..., 1, 1, 2],
       [1, 1, 1, ..., 1, 1, 2],
       ..., 
       [3, 5, 1, ..., 1, 1, 2],

# inverse `df` data
mcle.inverse_transform(df)

# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
       ..., 
       ['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)

# inverse `df_copy` data
mcle.inverse_transform(df_copy)

# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
       ..., 
       ['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)

Her bir sütuna sığdırmak için kullanılan ayrı ayrı sütun sınıflarına, sütun etiketlerine ve sütun kodlayıcılarına erişebilirsiniz:

mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_


Merhaba Jason, mcle.all_labels_ işe yaramıyor (Python 3.5, Conda 4.3.29, Sklearn 0.18.1, Pandalar 0.20.1. Ben: AttributeError: 'MultiColumnLabelEncoder' nesnesinin 'all_labels_'
Jason

@Jason Merhaba, özür dilerim, bugüne kadar görmedim: / ama tahmin etmeliydim, sadece fityukarıdaki yöntemi kullandığınızı söyleyebilirim ki, bunu uygulayana kadar hiçbir etiket üretmeyecek ( transform/ fit_transform) veri.
Jason Wolosonovich

Daha iyi bir örnek vermeniz gerektiğini düşünüyorum - tüm kodlarınızı tekrar çalıştıramadım.
user702846

2

@ PriceHardman'ın çözümü üzerine yapılan yorumları takip ederek sınıfın aşağıdaki versiyonunu öneririm :

class LabelEncodingColoumns(BaseEstimator, TransformerMixin):
def __init__(self, cols=None):
    pdu._is_cols_input_valid(cols)
    self.cols = cols
    self.les = {col: LabelEncoder() for col in cols}
    self._is_fitted = False

def transform(self, df, **transform_params):
    """
    Scaling ``cols`` of ``df`` using the fitting

    Parameters
    ----------
    df : DataFrame
        DataFrame to be preprocessed
    """
    if not self._is_fitted:
        raise NotFittedError("Fitting was not preformed")
    pdu._is_cols_subset_of_df_cols(self.cols, df)

    df = df.copy()

    label_enc_dict = {}
    for col in self.cols:
        label_enc_dict[col] = self.les[col].transform(df[col])

    labelenc_cols = pd.DataFrame(label_enc_dict,
        # The index of the resulting DataFrame should be assigned and
        # equal to the one of the original DataFrame. Otherwise, upon
        # concatenation NaNs will be introduced.
        index=df.index
    )

    for col in self.cols:
        df[col] = labelenc_cols[col]
    return df

def fit(self, df, y=None, **fit_params):
    """
    Fitting the preprocessing

    Parameters
    ----------
    df : DataFrame
        Data to use for fitting.
        In many cases, should be ``X_train``.
    """
    pdu._is_cols_subset_of_df_cols(self.cols, df)
    for col in self.cols:
        self.les[col].fit(df[col])
    self._is_fitted = True
    return self

Bu sınıf, kodlayıcıyı eğitim setine sığdırır ve dönüştürme sırasında takılan versiyonu kullanır. Kodun ilk sürümünü burada bulabilirsiniz .


2

Aşağıdakileri LabelEncoder()içeren birden çok sütuna kısa bir yol dict():

from sklearn.preprocessing import LabelEncoder
le_dict = {col: LabelEncoder() for col in columns }
for col in columns:
    le_dict[col].fit_transform(df[col])

ve bunu le_dictbaşka herhangi bir sütunu labelEncode için kullanabilirsiniz :

le_dict[col].transform(df_another[col])

2

Tüm bunları doğrudan pandalarda yapmak mümkündür ve replaceyöntemin eşsiz bir yeteneği için çok uygundur .

İlk olarak, sütunları ve değerlerini yeni değiştirme değerleriyle eşleştiren sözlüklerden bir sözlük yapalım.

transform_dict = {}
for col in df.columns:
    cats = pd.Categorical(df[col]).categories
    d = {}
    for i, cat in enumerate(cats):
        d[cat] = i
    transform_dict[col] = d

transform_dict
{'location': {'New_York': 0, 'San_Diego': 1},
 'owner': {'Brick': 0, 'Champ': 1, 'Ron': 2, 'Veronica': 3},
 'pets': {'cat': 0, 'dog': 1, 'monkey': 2}}

Bu her zaman bire bir eşleme olacağından, yeni değerlerin orijinaline geri eşlenmesi için iç sözlüğü tersine çevirebiliriz.

inverse_transform_dict = {}
for col, d in transform_dict.items():
    inverse_transform_dict[col] = {v:k for k, v in d.items()}

inverse_transform_dict
{'location': {0: 'New_York', 1: 'San_Diego'},
 'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
 'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}

Şimdi, replaceiç içe bir sözlük listesi almak için yöntemin benzersiz yeteneğini kullanabilir ve dış anahtarları sütun olarak ve iç anahtarları değiştirmek istediğimiz değerler olarak kullanabiliriz.

df.replace(transform_dict)
   location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

replaceYöntemi tekrar zincirleyerek kolayca orijinaline geri dönebiliriz

df.replace(transform_dict).replace(inverse_transform_dict)
    location     owner    pets
0  San_Diego     Champ     cat
1   New_York       Ron     dog
2   New_York     Brick     cat
3  San_Diego     Champ  monkey
4  San_Diego  Veronica     dog
5   New_York       Ron     dog

2

Burada ve başka yerlerde bazı cevapları arama ve deney sürü sonra, sanırım Cevabınız burada :

pd.DataFrame (sütunlar = df.columns, veri = LabelEncoder (). fit_transform (df.values.flatten ()). yeniden şekillendirme (df.shape))

Bu, kategori adlarını sütunlar boyunca koruyacaktır:

import pandas as pd
from sklearn.preprocessing import LabelEncoder

df = pd.DataFrame([['A','B','C','D','E','F','G','I','K','H'],
                   ['A','E','H','F','G','I','K','','',''],
                   ['A','C','I','F','H','G','','','','']], 
                  columns=['A1', 'A2', 'A3','A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10'])

pd.DataFrame(columns=df.columns, data=LabelEncoder().fit_transform(df.values.flatten()).reshape(df.shape))

    A1  A2  A3  A4  A5  A6  A7  A8  A9  A10
0   1   2   3   4   5   6   7   9   10  8
1   1   5   8   6   7   9   10  0   0   0
2   1   3   9   6   8   7   0   0   0   0

2

Kaynak kodunu kontrol ettim ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.pyLabelEncoder'ın ) kontrol ettim. Bunlardan biri np.unique () olan bir dizi numpy dönüşümüne dayanıyordu. Ve bu fonksiyon sadece 1-d dizi girişi alır. (Eğer Yanlışsam beni düzelt).

Çok Kaba fikirler ... İlk olarak, hangi sütunların gerekli olduğunu belirleyin, ardından her sütunda döngü yapın.

def cat_var(df): 
    """Identify categorical features. 

    Parameters
    ----------
    df: original df after missing operations 

    Returns
    -------
    cat_var_df: summary df with col index and col name for all categorical vars
    """
    col_type = df.dtypes
    col_names = list(df)

    cat_var_index = [i for i, x in enumerate(col_type) if x=='object']
    cat_var_name = [x for i, x in enumerate(col_names) if i in cat_var_index]

    cat_var_df = pd.DataFrame({'cat_ind': cat_var_index, 
                               'cat_name': cat_var_name})

    return cat_var_df



from sklearn.preprocessing import LabelEncoder 

def column_encoder(df, cat_var_list):
    """Encoding categorical feature in the dataframe

    Parameters
    ----------
    df: input dataframe 
    cat_var_list: categorical feature index and name, from cat_var function

    Return
    ------
    df: new dataframe where categorical features are encoded
    label_list: classes_ attribute for all encoded features 
    """

    label_list = []
    cat_var_df = cat_var(df)
    cat_list = cat_var_df.loc[:, 'cat_name']

    for index, cat_feature in enumerate(cat_list): 

        le = LabelEncoder()

        le.fit(df.loc[:, cat_feature])    
        label_list.append(list(le.classes_))

        df.loc[:, cat_feature] = le.transform(df.loc[:, cat_feature])

    return df, label_list

Döndürülen df kodlamadan sonra olur ve label_list size tüm bu değerlerin karşılık gelen sütunda ne anlama geldiğini gösterir. Bu, iş için yazdığım bir veri işlem komut dosyasından bir parçacık. Başka bir gelişme olabileceğini düşünüyorsanız bana bildirin.

EDIT: Yukarıdaki yöntemlerin en iyi eksik olmayan veri çerçevesi ile çalıştığını belirtmek istiyorum. Veri çerçevesine doğru nasıl çalıştığından emin değilim eksik veri içeriyor. (Yukarıdaki yöntemleri yürütmeden önce eksik prosedür ile bir anlaşma yaptım)


1

etiket kodlamasını yapmak için tek bir sütunumuz varsa ve ters dönüşümü python'da birden fazla sütun olduğunda nasıl yapılacağını kolaydır

def stringtocategory(dataset):
    '''
    @author puja.sharma
    @see The function label encodes the object type columns and gives label      encoded and inverse tranform of the label encoded data
    @param dataset dataframe on whoes column the label encoding has to be done
    @return label encoded and inverse tranform of the label encoded data.
   ''' 
   data_original = dataset[:]
   data_tranformed = dataset[:]
   for y in dataset.columns:
       #check the dtype of the column object type contains strings or chars
       if (dataset[y].dtype == object):
          print("The string type features are  : " + y)
          le = preprocessing.LabelEncoder()
          le.fit(dataset[y].unique())
          #label encoded data
          data_tranformed[y] = le.transform(dataset[y])
          #inverse label transform  data
          data_original[y] = le.inverse_transform(data_tranformed[y])
   return data_tranformed,data_original

1

Veri çerçevesinde sayısal ve kategorik her iki veri türü varsa Kullanabilirsiniz: burada X, kategorik ve sayısal her iki değişkene sahip veri çerçevemdir

from sklearn import preprocessing
le = preprocessing.LabelEncoder()

for i in range(0,X.shape[1]):
    if X.dtypes[i]=='object':
        X[X.columns[i]] = le.fit_transform(X[X.columns[i]])

Not: Geri dönüştürmekle ilgilenmiyorsanız, bu teknik iyidir.


1

Neuraxle Kullanımı

TLDR; Burada kullanabilirsiniz FlattenForEach basitçe gibi df dönüştürmek için sınıfa sarıcı: FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df).

Bu yöntemle, etiket kodlayıcınız düzenli bir scikit-öğren Pipeline'a sığabilecek ve dönüşebilecektir . Sadece içe aktaralım:

from sklearn.preprocessing import LabelEncoder
from neuraxle.steps.column_transformer import ColumnTransformer
from neuraxle.steps.loop import FlattenForEach

Sütunlar için aynı paylaşılan kodlayıcı:

Paylaşılan bir LabelEncoder'ın onu kodlamak için tüm verilere nasıl uygulanacağı aşağıda açıklanmıştır:

    p = FlattenForEach(LabelEncoder(), then_unflatten=True)

Sonuç:

    p, predicted_output = p.fit_transform(df.values)
    expected_output = np.array([
        [6, 7, 6, 8, 7, 7],
        [1, 3, 0, 1, 5, 3],
        [4, 2, 2, 4, 4, 2]
    ]).transpose()
    assert np.array_equal(predicted_output, expected_output)

Sütun başına farklı kodlayıcılar:

Ve işte ilk bağımsız bir LabelEncoder evcil hayvanlara nasıl uygulanacak ve ikincisi sütun sahibi ve yeri için paylaşılacak. Kesin olmak gerekirse, burada farklı ve paylaşılan etiket kodlayıcıların bir karışımı var:

    p = ColumnTransformer([
        # A different encoder will be used for column 0 with name "pets":
        (0, FlattenForEach(LabelEncoder(), then_unflatten=True)),
        # A shared encoder will be used for column 1 and 2, "owner" and "location":
        ([1, 2], FlattenForEach(LabelEncoder(), then_unflatten=True)),
    ], n_dimension=2)

Sonuç:

    p, predicted_output = p.fit_transform(df.values)
    expected_output = np.array([
        [0, 1, 0, 2, 1, 1],
        [1, 3, 0, 1, 5, 3],
        [4, 2, 2, 4, 4, 2]
    ]).transpose()
    assert np.array_equal(predicted_output, expected_output)

0

Temelde @Alexander yanıtını kullandı ancak bazı değişiklikler yapmak zorunda kaldı -

cols_need_mapped = ['col1', 'col2']

mapper = {col: {cat: n for n, cat in enumerate(df[col].astype('category').cat.categories)} 
     for col in df[cols_need_mapped]}

for c in cols_need_mapped :
    df[c] = df[c].map(mapper[c])

Daha sonra gelecekte tekrar kullanmak için çıktıyı bir json belgesine kaydedebilirsiniz ve ihtiyacınız olduğunda onu okuyup .map()yukarıda yaptığım gibi kullanabilirsiniz.


0

Sorun, sığdırma işlevine ilettiğiniz verilerin (pd veri çerçevesi) şeklidir. 1d listesini geçmelisin.


0
import pandas as pd
from sklearn.preprocessing import LabelEncoder

train=pd.read_csv('.../train.csv')

#X=train.loc[:,['waterpoint_type_group','status','waterpoint_type','source_class']].values
# Create a label encoder object 
def MultiLabelEncoder(columnlist,dataframe):
    for i in columnlist:

        labelencoder_X=LabelEncoder()
        dataframe[i]=labelencoder_X.fit_transform(dataframe[i])
columnlist=['waterpoint_type_group','status','waterpoint_type','source_class','source_type']
MultiLabelEncoder(columnlist,train)

Burada konumdan bir csv okuyorum ve işlev i labelencode ve bu uygulamak istediğiniz veri çerçevesi için sütun listesi geçiyorum.


0

Buna ne dersin?

def MultiColumnLabelEncode(choice, columns, X):
    LabelEncoders = []
    if choice == 'encode':
        for i in enumerate(columns):
            LabelEncoders.append(LabelEncoder())
        i=0    
        for cols in columns:
            X[:, cols] = LabelEncoders[i].fit_transform(X[:, cols])
            i += 1
    elif choice == 'decode': 
        for cols in columns:
            X[:, cols] = LabelEncoders[i].inverse_transform(X[:, cols])
            i += 1
    else:
        print('Please select correct parameter "choice". Available parameters: encode/decode')

En verimli değil, ancak çalışıyor ve süper basit.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.