Mã hóa nhãn trên nhiều cột trong scikit-learn


216

Tôi đang cố gắng sử dụng scikit-learn LabelEncoderđể mã hóa một DataFramechuỗi các nhãn chuỗi. Vì khung dữ liệu có nhiều cột (50+), tôi muốn tránh tạo một LabelEncoderđối tượng cho mỗi cột; Tôi chỉ muốn có một LabelEncoderđối tượng lớn hoạt động trên tất cả các cột dữ liệu của mình.

Ném toàn bộ DataFramevào LabelEncodertạo ra lỗi dưới đây. Xin lưu ý rằng tôi đang sử dụng dữ liệu giả ở đây; trong thực tế, tôi đang xử lý khoảng 50 cột dữ liệu được gắn nhãn chuỗi, vì vậy cần một giải pháp không tham chiếu bất kỳ cột nào theo tên.

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)

TracBack (cuộc gọi gần đây nhất vừa qua): Tệp "", dòng 1, trong Tệp "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/pre Processing / label.py", dòng 103, phù hợp với y = cột_or_1d (y, warn = True) Tệp "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", dòng 306, trong cột_or_1d nâng cao ValueError ("hình dạng đầu vào xấu { 0} ". Format (hình dạng)) ValueError: hình dạng đầu vào xấu (6, 3)

Bất kỳ suy nghĩ về làm thế nào để có được xung quanh vấn đề này?


Tại sao bạn cố gắng làm điều này?
Fred Foo

Để đơn giản hóa mã hóa một cột dataframenhiều dữ liệu chuỗi. Tôi đang piclking (các) đối tượng mã hóa, vì vậy muốn tránh phải chọn / giải nén 50 đối tượng riêng biệt. Ngoài ra, tôi tự hỏi liệu có cách nào để bộ mã hóa đơn giản hóa dữ liệu hay không, tức là chỉ trả về một hàng với một mã định danh cho mỗi tổ hợp biến duy nhất trong mỗi cột.
Bryan

Có một cách đơn giản để làm tất cả điều này trong gấu trúc bằng cách chuyển từ điển từ điển cho replacephương pháp. Xem câu trả lời dưới đây
Ted Petrou

Câu trả lời:


451

Bạn có thể dễ dàng làm điều này mặc dù,

df.apply(LabelEncoder().fit_transform)

EDIT2:

Trong scikit-learn 0,20, cách được đề xuất là

OneHotEncoder().fit_transform(df)

vì OneHotEncoder hiện hỗ trợ đầu vào chuỗi. Chỉ áp dụng OneHotEncoder cho một số cột nhất định với Trình định dạng cột.

BIÊN TẬP:

Vì câu trả lời này đã được hơn một năm trước và tạo ra nhiều sự ủng hộ (bao gồm cả tiền thưởng), tôi có lẽ nên mở rộng điều này hơn nữa.

Đối với inverse_transform và biến đổi, bạn phải thực hiện một chút hack.

from collections import defaultdict
d = defaultdict(LabelEncoder)

Với điều này, bây giờ bạn giữ lại tất cả các cột LabelEncodernhư từ điển.

# 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
Điều này thật tuyệt vời, nhưng trong trường hợp này làm thế nào chúng ta có thể áp dụng biến đổi nghịch đảo?
Supreeth Meka

10
Nhưng nếu tôi muốn sử dụng giải pháp này trong một đường ống, ví dụ như sự phù hợp và biến đổi riêng biệt (phù hợp với tàu hỏa, sau đó sử dụng trên tập kiểm tra -> sử dụng lại từ điển đã học) thì điều này có được hỗ trợ df.apply(LabelEncoder().fit_transform)không?
Georg Heiler

2
Làm thế nào điều này có thể được thực hiện để làm việc với LabelBinarizerthay vào đó và sử dụng lại từ điển cho một bộ kiểm tra? Tôi đã thử d = defaultdict(LabelBinarizer)và sau đó fit = df.apply(lambda x: d[x.name].fit_transform(x))một ngoại lệ được nêu ra : Exception: Data must be 1-dimensional. Tôi không chắc chắn làm thế nào tôi mong đợi DataFrame kết quả trông giống như ... có lẽ mỗi cột sẽ giữ các vectơ nhị phân.
Qululu

4
Giải pháp tốt đẹp. Làm thế nào để chuyển đổi trong cột nhất định?
stenlytw

1
Nếu tôi muốn đảo ngược mã hóa juste cho một cột, tôi phải làm thế nào?
Ib D

95

Như được đề cập bởi larsmans, LabelEncoder () chỉ lấy một mảng 1-d làm đối số . Điều đó nói rằng, khá dễ dàng để cuộn bộ mã hóa nhãn của riêng bạn hoạt động trên nhiều cột bạn chọn và trả về một khung dữ liệu được chuyển đổi. Mã của tôi ở đây dựa một phần vào bài đăng blog tuyệt vời của Zac Stewart được tìm thấy ở đây .

Tạo một bộ mã hóa tùy chỉnh liên quan đến việc chỉ đơn giản là tạo một lớp để đáp ứng các fit(), transform()fit_transform()phương pháp. Trong trường hợp của bạn, một khởi đầu tốt có thể là một cái gì đó như thế này:

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)

Giả sử chúng ta muốn mã hóa hai thuộc tính phân loại ( fruitcolor), trong khi để weightriêng thuộc tính số . Chúng ta có thể làm điều này như sau:

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

Điều này biến đổi fruit_datatập dữ liệu của chúng tôi từ

nhập mô tả hình ảnh ở đây đến

nhập mô tả hình ảnh ở đây

Truyền cho nó một khung dữ liệu bao gồm toàn bộ các biến phân loại và bỏ qua columnstham số sẽ dẫn đến mọi cột được mã hóa (mà tôi tin là những gì bạn đang tìm kiếm ban đầu):

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

Điều này biến đổi

nhập mô tả hình ảnh ở đây đến

nhập mô tả hình ảnh ở đây.

Lưu ý rằng nó có thể sẽ bị nghẹt thở khi nó cố mã hóa các thuộc tính đã là số (thêm một số mã để xử lý việc này nếu bạn muốn).

Một tính năng hay khác về điều này là chúng ta có thể sử dụng biến áp tùy chỉnh này trong một đường ống:

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

2
Chỉ cần nhận ra dữ liệu ngụ ý rằng một quả cam có màu xanh lá cây. Giáo sư. ;)
PriceHardman

5
đây là một cách tốt để chuyển đổi dữ liệu một lần, nhưng nếu tôi muốn sử dụng lại biến đổi này trên bộ xác thực. bạn sẽ phải fit_transform một lần nữa và các vấn đề có thể phát sinh, chẳng hạn như tập dữ liệu mới của tôi không có tất cả các danh mục cho tất cả các biến. ví dụ: giả sử màu xanh lục không hiển thị trong tập dữ liệu mới của tôi. điều này sẽ làm rối mã hóa.
Ben

3
Đồng ý với @Ben. Điều này không thực sự bắt chước sklearn ở tất cả ngoài tên phương thức. Nếu bạn đã cố gắng đặt cái này vào Đường ống, nó sẽ không hoạt động
Tgsmith61591

3
Để đảm bảo mã hóa nhãn nhất quán trên cả bộ xe lửa và bộ kiểm tra, bạn sẽ muốn thực hiện mã hóa trên toàn bộ tập dữ liệu của mình (train + test). Điều này có thể được thực hiện trước khi bạn chia chúng thành đào tạo và kiểm tra, hoặc bạn có thể kết hợp chúng, thực hiện mã hóa và tách chúng ra một lần nữa.
PriceHardman

2
Làm thế nào về đi ngược lại? giải mã trở lại ban đầu?
dùng702846

18

Vì scikit-learn 0,20, bạn có thể sử dụng sklearn.compose.ColumnTransformersklearn.preprocessing.OneHotEncoder:

Nếu bạn chỉ có các biến phân loại, OneHotEncodertrực tiếp:

from sklearn.preprocessing import OneHotEncoder

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

Nếu bạn có các tính năng gõ không đồng nhất:

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)

Các tùy chọn khác trong tài liệu: http://scikit-learn.org/urdy/modules/compose.html#columntransformer-for-heterogeneous-data


inverse_transform()mặc dù không được hỗ trợ trên ColumnTransformer. Ít nhất, không phải lúc này: github.com/scikit-learn/scikit-learn/issues/11463 . Đó là một bất lợi lớn cho ứng dụng của tôi, và có lẽ cũng sẽ dành cho những người khác.
Sander Vanden Hautte

16

Chúng tôi không cần một LabelEncoder.

Bạn có thể chuyển đổi các cột thành phân loại và sau đó lấy mã của họ. Tôi đã sử dụng một cách hiểu từ điển dưới đây để áp dụng quy trình này cho mọi cột và bọc kết quả lại thành một khung dữ liệu có cùng hình dạng với các chỉ mục và tên cột giống hệt nhau.

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

Để tạo một từ điển ánh xạ, bạn chỉ có thể liệt kê các danh mục bằng cách hiểu từ điển:

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

Nếu tôi muốn quay lại (đảo ngược) cho một cột (ví dụ biến mục tiêu: Y) tôi phải làm thế nào?
Ib D

9

điều này không trả lời trực tiếp câu hỏi của bạn (mà Naputipulu Jon và PriceHardman có câu trả lời tuyệt vời)

Tuy nhiên, với mục đích của một vài nhiệm vụ phân loại, v.v. bạn có thể sử dụng

pandas.get_dummies(input_df) 

điều này có thể nhập vào khung dữ liệu với dữ liệu phân loại và trả về một khung dữ liệu có giá trị nhị phân. giá trị biến được mã hóa thành tên cột trong khung dữ liệu kết quả. hơn


6

Giả sử bạn chỉ đang cố gắng để có được một sklearn.preprocessing.LabelEncoder()đối tượng có thể được sử dụng để đại diện cho các cột của mình, tất cả những gì bạn phải làm là:

le.fit(df.columns)

Trong đoạn mã trên, bạn sẽ có một số duy nhất tương ứng với mỗi cột. Chính xác hơn, bạn sẽ có một 1: lập bản đồ 1 df.columnstới le.transform(df.columns.get_values()). Để có được mã hóa của một cột, chỉ cần chuyển nó tới le.transform(...). Ví dụ, sau đây sẽ nhận được mã hóa cho mỗi cột:

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

Giả sử bạn muốn tạo một sklearn.preprocessing.LabelEncoder()đối tượng cho tất cả các nhãn hàng của mình, bạn có thể làm như sau:

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

Trong trường hợp này, rất có thể bạn có nhãn hàng không duy nhất (như được hiển thị trong câu hỏi của bạn). Để xem những lớp mà bộ mã hóa đã tạo, bạn có thể làm le.classes_. Bạn sẽ lưu ý rằng điều này nên có các yếu tố giống như trong set(y for x in df.get_values() for y in x). Một lần nữa để chuyển đổi nhãn hàng sang sử dụng nhãn được mã hóa le.transform(...). Ví dụ: nếu bạn muốn lấy nhãn cho cột đầu tiên trong df.columnsmảng và hàng đầu tiên, bạn có thể làm điều này:

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

Câu hỏi bạn có trong nhận xét của bạn phức tạp hơn một chút, nhưng vẫn có thể được thực hiện:

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

Đoạn mã trên thực hiện như sau:

  1. Tạo một sự kết hợp độc đáo của tất cả các cặp (cột, hàng)
  2. Đại diện cho mỗi cặp như là một phiên bản chuỗi của bộ. Đây là một cách giải quyết để vượt qua LabelEncoderlớp không hỗ trợ bộ dữ liệu như một tên lớp.
  3. Phù hợp với các mặt hàng mới để LabelEncoder.

Bây giờ để sử dụng mô hình mới này, nó phức tạp hơn một chút. Giả sử chúng tôi muốn trích xuất đại diện cho cùng một mục mà chúng tôi đã tìm kiếm trong ví dụ trước (cột đầu tiên trong df.columns và hàng đầu tiên), chúng tôi có thể làm điều này:

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

Hãy nhớ rằng mỗi tra cứu bây giờ là một chuỗi đại diện của một tuple chứa (cột, hàng).


5

Không, LabelEncoderkhông làm điều này. Phải mất các mảng 1-d của nhãn lớp và tạo ra các mảng 1-d. Nó được thiết kế để xử lý các nhãn lớp trong các vấn đề phân loại, không phải dữ liệu tùy ý và bất kỳ nỗ lực nào để buộc nó vào các mục đích sử dụng khác sẽ yêu cầu mã để chuyển đổi vấn đề thực tế sang vấn đề mà nó giải quyết (và giải pháp trở lại không gian ban đầu).


Ok, với điều này, đề xuất của bạn về cách tốt nhất tôi có thể mã hóa toàn bộ nhãn chuỗi DataFrametại một thời điểm là gì?
Bryan

@Bryan Nhìn vào LabelEncodermã và điều chỉnh nó. Tôi không sử dụng Pandas cho mình, vì vậy tôi không biết nó sẽ khó như thế nào.
Fred Foo

Tôi cũng sẽ để những pandasngười khác giải quyết câu hỏi này - tôi chắc chắn tôi không phải là người duy nhất gặp thử thách này, vì vậy tôi hy vọng có thể có một giải pháp được xây dựng sẵn ngoài kia.
Bryan

5

Đây là một năm rưỡi sau thực tế, nhưng tôi cũng vậy, cần phải có thể .transform()nhiều cột dataframe gấu trúc cùng một lúc (và cũng có thể .inverse_transform()như vậy). Điều này mở rộng dựa trên đề xuất tuyệt vời của @priceHardman ở trên:

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

Thí dụ:

Nếu dfdf_copy()là các kiểu dữ liệu hỗn hợp pandas, bạn có thể áp dụng MultiColumnLabelEncoder()các dtype=objectcột theo cách sau:

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

Bạn có thể truy cập các lớp cột riêng lẻ, nhãn cột và bộ mã hóa cột được sử dụng để khớp với từng cột thông qua lập chỉ mục:

mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_


Hi Jason, mcle.all_labels_ không xuất hiện để làm việc (Python 3.5, Conda 4.3.29, Sklearn 0.18.1, Pandas 0.20.1 tôi nhận được: AttributeError: đối tượng 'MultiColumnLabelEncoder' không có thuộc tính 'all_labels_'.
Jason

@Jason Xin chào, xin lỗi, tôi đã không thấy điều này cho đến ngày hôm nay: / nhưng nếu tôi phải đoán, tôi sẽ nói rằng bạn chỉ sử dụng fitphương pháp từ phía trên mà sẽ không thực sự tạo ra bất kỳ nhãn nào cho đến khi bạn áp dụng nó ( transform/ fit_transform) cho dữ liệu.
Jason Wolosonovich

Tôi nghĩ bạn cần đưa ra một ví dụ tốt hơn - tôi không thể chạy lại tất cả các mã của bạn.
dùng702846

2

Theo dõi các ý kiến ​​nêu ra về giải pháp của @priceHardman, tôi sẽ đề xuất phiên bản sau của lớp:

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

Lớp này phù hợp với bộ mã hóa trên tập huấn luyện và sử dụng phiên bản được trang bị khi chuyển đổi. Phiên bản ban đầu của mã có thể được tìm thấy ở đây .


2

Một cách ngắn để LabelEncoder()nhiều cột với một 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])

và bạn có thể sử dụng điều này le_dictđể gắn nhãnEncode cho bất kỳ cột nào khác:

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

2

Có thể làm tất cả điều này trong gấu trúc trực tiếp và rất phù hợp với khả năng độc đáo của replacephương pháp.

Trước tiên, hãy tạo một từ điển từ điển ánh xạ các cột và giá trị của chúng thành các giá trị thay thế mới của chúng.

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

Vì đây sẽ luôn là ánh xạ một đến một, chúng ta có thể đảo ngược từ điển bên trong để có được ánh xạ của các giá trị mới trở lại ban đầu.

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

Bây giờ, chúng ta có thể sử dụng khả năng duy nhất của replacephương thức để lấy danh sách từ điển lồng nhau và sử dụng các khóa bên ngoài làm cột và các khóa bên trong làm giá trị mà chúng ta muốn thay thế.

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

Chúng ta có thể dễ dàng quay lại bản gốc bằng cách nối lại replacephương thức

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

Sau rất nhiều tìm kiếm và thử nghiệm với một số câu trả lời ở đây và ở nơi khác, tôi nghĩ rằng câu trả lời của bạn ở đây :

pd.DataFrame (Cột = df.columns, data = LabelEncoder (). fit_transform (df.values.flatten ()). định hình lại (df.shape))

Điều này sẽ giữ tên danh mục trên các cột:

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

Tôi đã kiểm tra mã nguồn ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/pre Processing / label.py) của LabelEncoder. Nó được dựa trên một tập hợp các phép biến đổi numpy, một trong số đó là np.unique (). Và chức năng này chỉ mất đầu vào mảng 1-d. (đúng nếu tôi đã sai lầm).

Những ý tưởng rất thô sơ ... trước tiên, hãy xác định những cột nào cần LabelEncoder, sau đó lặp qua từng cột.

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

Sự trở lại Df được sẽ là cái sau khi mã hóa và nhãn_list sẽ cho bạn thấy tất cả các giá trị đó có nghĩa gì trong cột tương ứng. Đây là một đoạn trích từ một kịch bản xử lý dữ liệu tôi đã viết cho công việc. Hãy cho tôi biết nếu bạn nghĩ rằng có thể có bất kỳ cải thiện hơn nữa.

EDIT: Chỉ muốn đề cập ở đây rằng các phương pháp trên hoạt động với khung dữ liệu không thiếu thứ tốt nhất. Không chắc chắn làm thế nào nó hoạt động đối với khung dữ liệu chứa dữ liệu bị thiếu. (Tôi đã có một thỏa thuận với thủ tục bị thiếu trước khi thực hiện các phương thức trên)


1

nếu chúng ta có một cột duy nhất để thực hiện mã hóa nhãn và biến đổi nghịch đảo của nó thì làm thế nào dễ dàng để làm điều đó khi có nhiều cột trong 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

1

Nếu bạn có cả hai loại dữ liệu số và phân loại trong khung dữ liệu Bạn có thể sử dụng: ở đây X là khung dữ liệu của tôi có cả hai biến phân loại và số

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

Lưu ý: Kỹ thuật này là tốt nếu bạn không quan tâm đến việc chuyển đổi chúng trở lại.


1

Sử dụng thần kinh

TLDR; Bạn ở đây có thể sử dụng lớp trình bao bọc FlattenForEach để chuyển đổi df của bạn như : FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df).

Với phương pháp này, bộ mã hóa nhãn của bạn sẽ có thể phù hợp và biến đổi trong Đường ống tìm hiểu thông thường . Hãy nhập đơn giản:

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

Cùng một bộ mã hóa cho các cột:

Dưới đây là cách một LabelEncoder được chia sẻ sẽ được áp dụng trên tất cả dữ liệu để mã hóa nó:

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

Kết quả:

    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)

Bộ mã hóa khác nhau trên mỗi cột:

Và đây là cách một LabelEncoder độc lập đầu tiên sẽ được áp dụng cho vật nuôi và một giây sẽ được chia sẻ cho chủ sở hữu và vị trí cột. Vì vậy, chính xác, chúng tôi ở đây có sự kết hợp của các bộ mã hóa nhãn khác nhau và được chia sẻ:

    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)

Kết quả:

    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

Chủ yếu sử dụng câu trả lời @Alexander nhưng phải thực hiện một số thay đổi -

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

Sau đó, để sử dụng lại trong tương lai, bạn có thể lưu đầu ra vào tài liệu json và khi bạn cần, bạn đọc nó và sử dụng .map()chức năng như tôi đã làm ở trên.


0

Vấn đề là hình dạng của dữ liệu (pd dataframe) mà bạn đang chuyển đến hàm fit. Bạn đã vượt qua danh sách 1d.


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)

Ở đây tôi đang đọc một csv từ vị trí và trong chức năng tôi đang chuyển qua danh sách cột tôi muốn gắn nhãn và khung dữ liệu tôi muốn áp dụng điều này.


0

Còn cái này thì sao?

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

Nó không phải là hiệu quả nhất, tuy nhiên nó hoạt động và nó rất đơn giản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.