Pengkodean label di beberapa kolom di scikit-pelajari

216

Saya mencoba menggunakan scikit-learn's LabelEncoderuntuk menyandikan panda DataFramelabel string. Karena kerangka data memiliki banyak (50+) kolom, saya ingin menghindari membuat LabelEncoderobjek untuk setiap kolom; Saya lebih suka hanya memiliki satu LabelEncoderobjek besar yang berfungsi di semua kolom data saya.

Melempar keseluruhan DataFrameke dalam LabelEncodermenciptakan kesalahan di bawah ini. Harap diingat bahwa saya menggunakan data dummy di sini; sebenarnya saya sedang berurusan dengan sekitar 50 kolom data berlabel string, jadi perlu solusi yang tidak merujuk kolom apa pun dengan nama.

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)

Traceback (panggilan terakhir terakhir): File "", line 1, dalam File "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", baris 103, sesuai dengan Anda = column_or_1d (y, warn = True) File "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", baris 306, di column_or_1d naikkan ValueError ("bentuk input buruk { 0} ". Format (bentuk)) ValueError: bentuk input buruk (6, 3)

Adakah pemikiran tentang bagaimana mengatasi masalah ini?

Bryan
sumber
Mengapa Anda mencoba melakukan ini?
Fred Foo
Untuk menyederhanakan pengkodean multi-kolom dataframedata string. Saya mem-piclking objek pengkodean, jadi saya ingin menghindari keharusan untuk acar / membongkar 50 objek yang terpisah. Juga, saya bertanya-tanya apakah ada cara untuk membuat encoder menyederhanakan data, yaitu hanya mengembalikan satu baris dengan pengenal untuk setiap kombinasi variabel yang unik di setiap kolom.
Bryan
Ada cara sederhana untuk melakukan ini semua dalam panda dengan melewati kamus kamus ke replacemetode. Lihat jawaban di bawah ini
Ted Petrou

Jawaban:

451

Anda dapat dengan mudah melakukan ini,

df.apply(LabelEncoder().fit_transform)

EDIT2:

Di scikit-belajar 0,20, cara yang disarankan adalah

OneHotEncoder().fit_transform(df)

karena OneHotEncoder sekarang mendukung input string. Menerapkan OneHotEncoder hanya ke kolom tertentu dimungkinkan dengan ColumnTransformer.

EDIT:

Karena jawaban ini lebih dari setahun yang lalu, dan menghasilkan banyak upvote (termasuk hadiah), saya mungkin harus memperpanjang ini lebih jauh.

Untuk inverse_transformasi dan transformasi, Anda harus melakukan sedikit peretasan.

from collections import defaultdict
d = defaultdict(LabelEncoder)

Dengan ini, Anda sekarang mempertahankan semua kolom LabelEncodersebagai kamus.

# 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))
Napitupulu Jon
sumber
1
Ini Luar Biasa, tetapi dalam kasus ini bagaimana kita menerapkan transformasi terbalik?
Supreeth Meka
10
Tetapi jika saya ingin menggunakan solusi ini dalam pipa misalnya memisahkan dan mengubah (cocok di kereta, dan kemudian menggunakan pada test-set -> menggunakan kembali kamus yang dipelajari) apakah ini didukung df.apply(LabelEncoder().fit_transform)?
Georg Heiler
2
Bagaimana ini bisa dibuat untuk bekerja dengan LabelBinarizerdan menggunakan kembali kamus untuk set tes? Aku mencoba d = defaultdict(LabelBinarizer)dan kemudian fit = df.apply(lambda x: d[x.name].fit_transform(x))tapi eksepsi dimunculkan: Exception: Data must be 1-dimensional. Saya tidak yakin bagaimana saya mengharapkan DataFrame yang dihasilkan terlihat seperti ... mungkin setiap kolom harus memegang vektor binarized.
Qululu
4
Solusi bagus Bagaimana cara mengubah kolom tertentu saja?
stenlytw
1
jika saya ingin membalikkan encode juste untuk satu kolom, bagaimana cara melakukannya?
Ib D
95

Seperti yang disebutkan oleh larsmans, LabelEncoder () hanya menggunakan array 1-d sebagai argumen . Yang mengatakan, sangat mudah untuk roll encoder label Anda sendiri yang beroperasi pada beberapa kolom yang Anda pilih, dan mengembalikan kerangka data yang diubah. Kode saya di sini sebagian didasarkan pada posting blog Zac Stewart yang sangat baik yang ditemukan di sini .

Membuat encoder kustom melibatkan hanya menciptakan kelas yang merespon dengan fit(), transform(), dan fit_transform()metode. Dalam kasus Anda, awal yang baik mungkin seperti ini:

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)

Misalkan kita ingin menyandikan dua atribut kategoris kita ( fruitdan color), sambil membiarkan atribut numerik weightsaja. Kita bisa melakukan ini sebagai berikut:

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

Yang mengubah fruit_datadataset kami dari

masukkan deskripsi gambar di sini untuk

masukkan deskripsi gambar di sini

Melewatkannya kerangka data yang seluruhnya terdiri dari variabel kategorikal dan menghilangkan columnsparameter akan menghasilkan setiap kolom yang dikodekan (yang saya percaya adalah apa yang awalnya Anda cari):

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

Ini mengubah

masukkan deskripsi gambar di sini untuk

masukkan deskripsi gambar di sini.

Perhatikan bahwa itu mungkin akan tersedak ketika mencoba untuk menyandikan atribut yang sudah numerik (tambahkan beberapa kode untuk menangani ini jika Anda suka).

Fitur bagus lain tentang ini adalah bahwa kita dapat menggunakan transformator khusus ini dalam sebuah pipa:

encoding_pipeline = Pipeline([
    ('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
    # add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)
PriceHardman
sumber
2
Baru sadar data menyiratkan bahwa jeruk berwarna hijau. Ups. ;)
PriceHardman
5
ini adalah cara yang baik untuk mengubah data sekali, tetapi bagaimana jika saya ingin menggunakan kembali transformasi ini pada set validasi. Anda harus melakukan fit_transformasi lagi dan masalah dapat muncul seperti kumpulan data baru saya yang tidak memiliki semua kategori untuk semua variabel. mis., katakanlah warna hijau tidak muncul di kumpulan data baru saya. ini akan mengacaukan penyandian.
Ben
3
Setuju dengan @Ben. Ini sebenarnya tidak meniru sklearn sama sekali di luar nama metode. Jika Anda mencoba memasukkan ini ke dalam Pipeline, itu tidak akan berhasil
Tgsmith61591
3
Untuk memastikan pengkodean label konsisten di seluruh rangkaian kereta dan tes, Anda ingin melakukan pengkodean pada seluruh dataset Anda (train + test). Ini dapat dilakukan baik sebelum Anda membaginya menjadi kereta dan menguji, atau Anda dapat menggabungkannya, melakukan pengkodean, dan membaginya kembali.
PriceHardman
2
Bagaimana kalau membalik? decoding kembali ke aslinya?
user702846
18

Karena scikit-learn 0.20 Anda dapat menggunakan sklearn.compose.ColumnTransformerdan sklearn.preprocessing.OneHotEncoder:

Jika Anda hanya memiliki variabel kategori, OneHotEncoderlangsung:

from sklearn.preprocessing import OneHotEncoder

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

Jika Anda memiliki fitur yang diketik secara heterogen:

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)

Opsi lainnya dalam dokumentasi: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data

ogrisel
sumber
inverse_transform()tidak didukung di ColumnTransformer. Setidaknya, tidak untuk saat ini: github.com/scikit-learn/scikit-learn/issues/11463 . Itu kerugian besar untuk aplikasi saya, dan mungkin juga untuk orang lain.
Sander Vanden Hautte
16

Kami tidak membutuhkan LabelEncoder.

Anda dapat mengonversi kolom ke kategori dan kemudian mendapatkan kodenya. Saya menggunakan pemahaman kamus di bawah ini untuk menerapkan proses ini pada setiap kolom dan membungkus hasilnya kembali ke dalam kerangka data dengan bentuk yang sama dengan indeks dan nama kolom yang identik.

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

Untuk membuat kamus pemetaan, Anda bisa menghitung kategori menggunakan pemahaman kamus:

>>> {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'}}
Alexander
sumber
Jika saya ingin kembali (mundur) untuk satu kolom (contoh variabel target: Y) bagaimana saya melakukannya?
Ib D
9

ini tidak langsung menjawab pertanyaan Anda (yang memiliki balasan fantastis Naputipulu Jon dan PriceHardman)

Namun, untuk tujuan beberapa tugas klasifikasi dll, Anda dapat menggunakan

pandas.get_dummies(input_df) 

ini dapat memasukkan kerangka data dengan data kategorikal dan mengembalikan kerangka data dengan nilai biner. nilai variabel dikodekan menjadi nama kolom di dalam dataframe yang dihasilkan. lebih

Anurag Priyadarshi
sumber
6

Dengan asumsi Anda hanya mencoba untuk mendapatkan sklearn.preprocessing.LabelEncoder()objek yang dapat digunakan untuk mewakili kolom Anda, yang harus Anda lakukan adalah:

le.fit(df.columns)

Dalam kode di atas Anda akan memiliki nomor unik yang sesuai dengan setiap kolom. Lebih tepatnya, Anda akan memiliki pemetaan 1: 1 df.columnsuntuk le.transform(df.columns.get_values()). Untuk mendapatkan penyandian kolom, cukup kirimkan ke le.transform(...). Sebagai contoh, berikut ini akan mendapatkan pengkodean untuk setiap kolom:

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

Dengan asumsi Anda ingin membuat sklearn.preprocessing.LabelEncoder()objek untuk semua label baris Anda, Anda dapat melakukan hal berikut:

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

Dalam hal ini, Anda kemungkinan besar memiliki label baris yang tidak unik (seperti yang ditunjukkan dalam pertanyaan Anda). Untuk melihat kelas apa yang dibuat oleh encoder, Anda dapat melakukannya le.classes_. Anda akan perhatikan bahwa ini harus memiliki elemen yang sama dengan di set(y for x in df.get_values() for y in x). Sekali lagi untuk mengonversi label baris menjadi penggunaan label yang disandikan le.transform(...). Sebagai contoh, jika Anda ingin mengambil label untuk kolom pertama dalam df.columnsarray dan baris pertama, Anda bisa melakukan ini:

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

Pertanyaan yang Anda miliki dalam komentar Anda sedikit lebih rumit, tetapi masih dapat diselesaikan:

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

Kode di atas melakukan hal berikut:

  1. Buat kombinasi unik dari semua pasangan (kolom, baris)
  2. Tunjukkan setiap pasangan sebagai versi string dari tuple. Ini adalah solusi untuk mengatasiLabelEncoder kelas yang tidak mendukung tupel sebagai nama kelas.
  3. Pas item baru ke LabelEncoder.

Sekarang untuk menggunakan model baru ini sedikit lebih rumit. Dengan asumsi kita ingin mengekstrak representasi untuk item yang sama seperti yang kita cari pada contoh sebelumnya (kolom pertama di df.columns dan baris pertama), kita dapat melakukan ini:

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

Ingat bahwa setiap pencarian sekarang merupakan representasi string dari tuple yang berisi (kolom, baris).

TehTechGuy
sumber
5

Tidak, LabelEncoderjangan lakukan ini. Dibutuhkan array 1-d label kelas dan menghasilkan array 1-d. Ini dirancang untuk menangani label kelas dalam masalah klasifikasi, bukan data yang arbitrer, dan setiap upaya untuk memaksanya ke dalam penggunaan lain akan memerlukan kode untuk mengubah masalah aktual menjadi masalah yang dipecahkannya (dan solusi kembali ke ruang asli).

Fred Foo
sumber
Ok, mengingat ini, apa saran Anda tentang cara terbaik saya dapat menyandikan label string secara keseluruhan DataFrame?
Bryan
@Bryan Lihat LabelEncoderkode dan sesuaikan. Saya sendiri tidak menggunakan Panda, jadi saya tidak tahu seberapa sulitnya itu.
Fred Foo
Saya akan membiarkan pandasorang lain memecahkan pertanyaan ini juga - saya yakin saya bukan satu-satunya orang dengan tantangan ini, jadi saya berharap mungkin ada solusi pra-dibangun di luar sana.
Bryan
5

Ini adalah satu setengah tahun setelah fakta, tapi saya juga, perlu untuk dapat .transform()beberapa kolom dataframe panda sekaligus (dan dapat .inverse_transform()juga). Ini berkembang atas saran luar biasa dari @PriceHardman di atas:

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

Contoh:

Jika dfdan df_copy()merupakan pandaskerangka data tipe campuran, Anda bisa menerapkannya MultiColumnLabelEncoder()ke dtype=objectkolom dengan cara berikut:

# 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)

Anda dapat mengakses masing-masing kelas kolom, label kolom, dan penyandi kolom yang digunakan untuk menyesuaikan setiap kolom melalui pengindeksan:

mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_

Jason Wolosonovich
sumber
Hai Jason, mcle.all_labels_ tampaknya tidak berfungsi (Python 3.5, Conda 4.3.29, Sklearn 0.18.1, Pandas 0.20.1. Saya mendapatkan: AttributeError: 'objek MultiColumnLabelEncoder' tidak memiliki atribut 'all_labels_'
Jason
@Jason Hai, maaf, saya tidak melihat ini sampai hari ini: / tetapi jika saya harus menebak, saya akan mengatakan bahwa Anda hanya menggunakan fitmetode dari atas yang tidak akan benar-benar menghasilkan label sampai Anda menerapkannya ( transform/ fit_transform) ke data.
Jason Wolosonovich
Saya pikir Anda perlu memberikan contoh yang lebih baik - saya tidak bisa menjalankan kembali semua kode Anda.
user702846
2

Menindaklanjuti komentar yang diangkat pada solusi @PriceHardman saya akan mengusulkan versi kelas berikut:

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

Kelas ini cocok dengan encoder pada set pelatihan dan menggunakan versi yang pas saat mentransformasikannya. Versi awal kode dapat ditemukan di sini .

Dror
sumber
2

Cara singkat ke LabelEncoder()beberapa kolom dengan 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])

dan Anda dapat menggunakan ini le_dictuntuk memberi label Kode kolom lain:

le_dict[col].transform(df_another[col])
Tom
sumber
2

Adalah mungkin untuk melakukan ini semua dalam panda secara langsung dan sangat cocok untuk kemampuan unik dari replacemetode ini.

Pertama, mari kita membuat kamus kamus yang memetakan kolom dan nilainya ke nilai penggantian yang baru.

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}}

Karena ini akan selalu menjadi pemetaan satu-satu, kita dapat membalikkan kamus batin untuk mendapatkan pemetaan nilai-nilai baru kembali ke aslinya.

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'}}

Sekarang, kita dapat menggunakan kemampuan unik dari replacemetode untuk mengambil daftar kamus yang bersarang dan menggunakan kunci luar sebagai kolom, dan kunci dalam sebagai nilai yang ingin kita ganti.

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

Kita dapat dengan mudah kembali ke aslinya dengan kembali merantai replacemetode

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
Ted Petrou
sumber
2

Setelah banyak pencarian dan percobaan dengan beberapa jawaban di sini dan di tempat lain, saya pikir jawaban Anda ada di sini :

pd.DataFrame (kolom = df.columns, data = LabelEncoder (). fit_transform (df.values.flatten ()). membentuk kembali (df.shape))

Ini akan mempertahankan nama kategori di seluruh kolom:

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
Christopher
sumber
2

Saya memeriksa kode sumber ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py ) dari LabelEncoder. Itu didasarkan pada seperangkat transformasi numpy, yang salah satunya adalah np.unique (). Dan fungsi ini hanya membutuhkan input array 1-d. (koreksi saya jika saya salah).

Gagasan yang sangat kasar ... pertama, kenali kolom mana yang membutuhkan LabelEncoder, kemudian lewati setiap kolom.

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

Df yang dikembalikan akan menjadi yang setelah pengkodean, dan label_list akan menunjukkan kepada Anda apa arti semua nilai tersebut di kolom yang sesuai. Ini adalah cuplikan dari skrip proses data yang saya tulis untuk pekerjaan. Beri tahu saya jika Anda berpikir akan ada peningkatan lebih lanjut.

EDIT: Hanya ingin menyebutkan di sini bahwa metode di atas bekerja dengan bingkai data tanpa melewatkan yang terbaik. Tidak yakin bagaimana ini bekerja menuju bingkai data yang berisi data yang hilang. (Saya memiliki kesepakatan dengan prosedur yang hilang sebelum menjalankan metode di atas)

willaccc
sumber
1

jika kita memiliki satu kolom untuk melakukan pengkodean label dan inversnya mengubah dengan mudah bagaimana melakukannya ketika ada banyak kolom dalam python

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
Puja Sharma
sumber
1

Jika Anda memiliki numerik dan kategorikal kedua jenis data dalam kerangka data Anda dapat menggunakan: di sini X adalah kerangka data saya yang kategorikal dan numerik kedua variabel

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

Catatan: Teknik ini bagus jika Anda tidak tertarik untuk mengubahnya kembali.

Vikas Gupta
sumber
1

Menggunakan Neuraxle

TLDR; Anda di sini dapat menggunakan FlattenForEach wrapper class untuk hanya mengubah df Anda seperti: FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df).

Dengan metode ini, pembuat enkode label Anda akan dapat masuk dan bertransformasi dalam pipeline scikit-learn reguler . Mari kita impor:

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

Encoder bersama yang sama untuk kolom:

Berikut ini cara LabelEncoder yang dibagikan akan diterapkan pada semua data untuk menyandikannya:

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

Hasil:

    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)

Encoders berbeda per kolom:

Dan di sini adalah bagaimana LabelEncoder mandiri pertama akan diterapkan pada hewan peliharaan, dan yang kedua akan dibagikan untuk pemilik kolom dan lokasi. Jadi tepatnya, kami di sini memiliki campuran enkode label yang berbeda dan dibagikan:

    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)

Hasil:

    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)
Guillaume Chevalier
sumber
0

Terutama digunakan jawaban @Alexander tetapi harus membuat beberapa perubahan -

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

Kemudian untuk digunakan kembali di masa depan Anda hanya dapat menyimpan output ke dokumen json dan ketika Anda membutuhkannya Anda membacanya dan menggunakan .map()fungsi seperti yang saya lakukan di atas.

bbennett36
sumber
0

Masalahnya adalah bentuk data (pd dataframe) yang Anda lewati untuk fungsi fit. Anda harus melewati daftar 1d.

ali sadr
sumber
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)

Di sini saya membaca csv dari lokasi dan dalam fungsi saya melewati daftar kolom saya ingin labelencode dan dataframe saya ingin menerapkan ini.


sumber
0

Bagaimana dengan ini?

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')

Ini bukan yang paling efisien, namun bekerja dan sangat sederhana.

Dominik Novotný
sumber