scikit-learn에서 여러 열의 레이블 인코딩


217

scikit-learn LabelEncoder을 사용하여 팬더 DataFrame문자열 문자열 을 인코딩 하려고합니다 . 데이터 프레임에 많은 (50+) 열 LabelEncoder이 있으므로 각 열에 대한 개체를 만드는 것을 피하고 싶습니다 . 차라리 모든 데이터 열에서 LabelEncoder작동하는 하나의 큰 객체가 있습니다 .

전체 DataFrame를 던지면 LabelEncoder아래 오류가 발생합니다. 여기에서 더미 데이터를 사용하고 있음을 명심하십시오. 실제로 약 50 열의 문자열 레이블이 지정된 데이터를 처리하므로 이름으로 열을 참조하지 않는 솔루션이 필요합니다.

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)

역 추적 (가장 최근 호출) : 파일 "", 1 행, 파일 "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py"의 103 행, y에 적합 = column_or_1d (y, warn = True) column_or_1d의 파일 "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", 306 행, value_Error ( "잘못된 입력 형태 { 0} ". format (shape)) ValueError : 잘못된 입력 모양 (6, 3)

이 문제를 해결하는 방법에 대한 생각이 있습니까?


왜 이러려고합니까?
Fred Foo

여러 열의 dataframe문자열 데이터 인코딩을 단순화 합니다. 인코딩 객체를 피킹하고 있으므로 50 개의 개별 객체를 피클 / 피클 링하지 않아도됩니다. 또한 인코더가 데이터를 단순화하는 방법이 있는지 궁금합니다. 즉, 각 열의 모든 고유 변수 조합에 대한 식별자로 하나의 행을 반환하면됩니다.
Bryan

사전 사전을 replace메소드 에 전달하여 팬더 에서이 작업을 수행하는 간단한 방법이 있습니다. 아래 답변을 참조하십시오
Ted Petrou

답변:


452

그래도 쉽게 할 수 있습니다.

df.apply(LabelEncoder().fit_transform)

EDIT2 :

scikit-learn 0.20에서 권장되는 방법은

OneHotEncoder().fit_transform(df)

OneHotEncoder는 이제 문자열 입력을 지원합니다. ColumnTransformer를 사용하면 특정 열에 만 OneHotEncoder를 적용 할 수 있습니다.

편집하다:

이 답변은 1 년 전에 끝났으며 현상금을 포함한 많은 공감대를 생성했기 때문에 아마도 이것을 더 확장해야합니다.

inverse_transform 및 transform의 경우 약간의 해킹이 필요합니다.

from collections import defaultdict
d = defaultdict(LabelEncoder)

이를 통해 이제 모든 열 LabelEncoder을 사전으로 유지합니다 .

# 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
이것은 놀라운 일이지만이 경우 역 변환을 어떻게 적용 할 수 있습니까?
Supreeth Meka

10
그러나 파이프 라인 에서이 솔루션을 사용하려면 예를 들어 별도의 맞춤 및 변환 (기차에 적합 한 다음 테스트 세트에서 사용-> 학습 된 사전 재사용)이 지원 df.apply(LabelEncoder().fit_transform)됩니까?
Georg Heiler

2
어떻게 이것이 LabelBinarizer대신 작업 하고 테스트 세트에 사전을 재사용 할 수 있습니까? 나는 시도 d = defaultdict(LabelBinarizer)하고 fit = df.apply(lambda x: d[x.name].fit_transform(x))있지만 예외가 발생합니다 : Exception: Data must be 1-dimensional. 결과 DataFrame이 어떻게 보일지 잘 모르겠습니다 ... 각 열에 이진화 된 벡터가 있어야합니다.
Qululu

4
좋은 해결책. 특정 열에서만 변환하는 방법은 무엇입니까?
stenlytw

1
하나의 열에 대한 인코딩 정의를 반전시키고 싶다면 어떻게해야합니까?
Ib D

95

larsmans가 언급했듯이 LabelEncoder ()는 1 차원 배열 만 인수로 사용 합니다. 즉, 선택한 여러 열에서 작동하고 변환 된 데이터 프레임을 반환하는 자체 레이블 인코더를 롤링하는 것은 매우 쉽습니다. 여기 내 코드는 Zac Stewart의 훌륭한 블로그 게시물에 있습니다 .

사용자 지정 인코더를 만들기 단순히 클래스를 만드는 작업이 포함됩니다 그에게 응답 fit(), transform()fit_transform()방법. 귀하의 경우 좋은 시작은 다음과 같습니다.

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)

숫자 속성 만 남겨두고 두 범주 형 속성 ( fruitcolor) 을 인코딩하려고한다고 가정 합니다 weight. 우리는 다음과 같이 할 수 있습니다 :

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

어떤 우리의 변환 fruit_data에서 데이터 집합을

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

전적으로 범주 형 변수로 구성된 데이터 프레임을 전달하고 columns매개 변수를 생략하면 모든 열이 인코딩됩니다 (원래 찾고있는 것으로 생각합니다).

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

이것은 변환

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오.

이미 숫자 인 속성을 인코딩하려고 할 때 질식 할 수 있습니다 (원하는 경우이를 처리하는 코드를 추가하십시오).

이것에 대한 또 다른 좋은 특징은 파이프 라인 에서이 맞춤형 변압기를 사용할 수 있다는 것입니다.

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

2
데이터가 오렌지색이 녹색임을 나타냅니다. 죄송합니다. ;)
PriceHardman 21:53에

5
이것은 데이터를 한 번 변환하는 좋은 방법이지만 유효성 검사 세트에서이 변환을 재사용하려면 어떻게해야합니까? 다시 fit_transform해야하고 내 새 데이터 세트가 모든 변수에 대한 모든 범주를 갖지 않는 등의 문제가 발생할 수 있습니다. 예를 들어, 새 데이터 세트에 녹색이 표시되지 않는다고 가정하십시오. 인코딩이 엉망이됩니다.
Ben

3
@Ben과 동의 함. 이것은 실제로 메소드 이름 너머로 sklearn을 모방하지는 않습니다. 이것을 파이프 라인에 넣으려고하면 작동하지 않습니다.
Tgsmith61591

3
기차와 테스트 세트 모두에서 레이블 인코딩이 일관되게하려면 전체 데이터 세트 (열차 + 테스트)에서 인코딩을 수행해야합니다. 이를 훈련 및 테스트로 분할하기 전에 수행하거나 결합하여 인코딩을 수행 한 후 다시 분리 할 수 ​​있습니다.
PriceHardman

2
역전은 어떻습니까? 원래대로 다시 디코딩?
user702846

18

0.20 scikit이 배우기 때문에 당신이 사용할 수있는 sklearn.compose.ColumnTransformersklearn.preprocessing.OneHotEncoder:

범주 형 변수 만있는 경우 OneHotEncoder직접 :

from sklearn.preprocessing import OneHotEncoder

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

유형이 다른 유형의 기능이있는 경우 :

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)

설명서의 추가 옵션 : http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data


inverse_transform()ColumnTransformer에서는 지원되지 않습니다. 적어도 지금은 아닙니다 : github.com/scikit-learn/scikit-learn/issues/11463 . 그것은 내 응용 프로그램에 큰 단점이며 아마도 다른 사람들에게도 도움이 될 것입니다.
Sander Vanden Hautte

16

LabelEncoder가 필요하지 않습니다.

열을 범주 형으로 변환 한 다음 해당 코드를 가져올 수 있습니다. 아래의 사전 이해를 사용하여이 프로세스를 모든 열에 적용하고 결과를 동일한 인덱스 및 열 이름을 가진 동일한 모양의 데이터 프레임으로 다시 래핑했습니다.

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

매핑 사전을 만들려면 사전 이해를 사용하여 범주를 열거하면됩니다.

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

한 열 (예 : 대상 변수 : Y)에 대해 뒤로 (역전) 돌아가려면 어떻게해야합니까?
Ib D

9

이것은 귀하의 질문에 직접 답변하지 않습니다 (Naputipulu Jon과 PriceHardman은 환상적인 답글을 가지고 있습니다)

그러나 몇 가지 분류 작업 등의 목적으로 사용할 수 있습니다.

pandas.get_dummies(input_df) 

이것은 범주 형 데이터로 데이터 프레임을 입력하고 이진 값을 가진 데이터 프레임을 반환 할 수 있습니다. 변수 값은 결과 데이터 프레임에서 열 이름으로 인코딩됩니다.


6

단순히 sklearn.preprocessing.LabelEncoder()열을 나타내는 데 사용할 수 있는 객체 를 얻으려고한다고 가정하면 다음과 같이하면 됩니다.

le.fit(df.columns)

위의 코드에는 각 열에 해당하는 고유 번호가 있습니다. 1 매핑 : 더 정확하게, 당신은 일 것 df.columns까지를 le.transform(df.columns.get_values()). 열의 인코딩을 얻으려면 간단히 전달하십시오 le.transform(...). 예를 들어, 다음은 각 열에 대한 인코딩을 가져옵니다.

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

sklearn.preprocessing.LabelEncoder()모든 행 레이블에 대한 오브젝트 를 작성한다고 가정하면 다음을 수행 할 수 있습니다.

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

이 경우 질문에 표시된 것처럼 고유하지 않은 행 레이블이있을 가능성이 큽니다. 인코더가 생성 한 클래스를 확인하려면 수행 할 수 있습니다 le.classes_. 이것과의 요소는 동일해야합니다 set(y for x in df.get_values() for y in x). 다시 한 번 행 레이블을 인코딩 된 레이블로 변환하려면 사용하십시오 le.transform(...). 예를 들어 df.columns배열의 첫 번째 열과 첫 번째 행 의 레이블을 검색하려는 경우 다음을 수행 할 수 있습니다.

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

귀하의 의견에 대한 질문은 조금 더 복잡하지만 여전히 달성 할 수 있습니다.

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

위의 코드는 다음을 수행합니다.

  1. (열, 행)의 모든 쌍을 고유하게 조합하십시오.
  2. 각 쌍을 튜플의 문자열 버전으로 나타냅니다. 이 해결 방법은LabelEncoder 튜플을 클래스 이름으로 지원하지 않는 클래스 입니다.
  3. 새 항목을에 맞 춥니 다 LabelEncoder.

이 새로운 모델을 사용하려면 조금 더 복잡합니다. 이전 예제에서 찾은 것과 동일한 항목 (df.columns의 첫 번째 열과 첫 번째 행)에 대한 표현을 추출한다고 가정하면 다음을 수행 할 수 있습니다.

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

각 조회는 이제 (열, 행)을 포함하는 튜플의 문자열 표현입니다.


5

아니요, LabelEncoder이 작업을 수행하지 않습니다. 클래스 레이블의 1 차원 배열을 취하고 1 차원 배열을 생성합니다. 클래스 레이블을 임의의 데이터가 아닌 분류 문제에서 처리하도록 설계되었으며 다른 용도로 강요하려고 시도하면 실제 문제를 해결하는 문제 (및 원래 공간으로 솔루션을 다시 변환)하는 코드가 필요합니다.


자, 이것을 감안할 때 문자열 레이블을 한 번에 전체적으로 인코딩하는 가장 좋은 방법에 대한 제안은 무엇 DataFrame입니까?
Bryan

@Bryan LabelEncoder코드를보고 적응하십시오. 나는 팬더를 직접 사용하지 않으므로 얼마나 힘든지 모르겠습니다.
Fred Foo

나는 다른 pandas사람들도이 질문에 균열을 갖도록 할 것이다. 나는이 도전을 가진 유일한 사람이 아니라고 확신한다.
Bryan

5

이것은 사실 이후 1 년 반이지만, 나는 .transform()팬더 데이터 프레임 열을 한 번 에 여러 개 (그리고 .inverse_transform()그것들도 가능하게) 할 수 있어야했습니다 . 이것은 위의 @PriceHardman의 훌륭한 제안으로 확장됩니다.

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

예:

경우 dfdf_copy()혼합 유형이다 pandasdataframes, 당신은을 적용 할 수 있습니다 MultiColumnLabelEncoder()받는 dtype=object다음과 같은 방법으로 열 :

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

인덱싱을 통해 각 열을 맞추는 데 사용되는 개별 열 클래스, 열 레이블 및 열 인코더에 액세스 할 수 있습니다.

mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_


안녕 제이슨, mcle.all_labels_는 (사업에 파이썬 3.5, CONDA 4.3.29, Sklearn 0.18.1, 팬더 0.20.1 나타나지 않습니다 내가 얻을 : AttributeError를 'MultiColumnLabelEncoder'개체가 어떤 속성 'all_labels_'가 없습니다.
제이슨

@Jason 안녕하세요, 죄송합니다. 오늘까지 이것을 보지 못했습니다 : /하지만 추측해야한다면, fit위 의 방법을 사용하여 실제로 레이블을 생성하지 않는 방법을 사용했다고 말할 것입니다 ( transform/ fit_transform) 자료.
Jason Wolosonovich

더 나은 예를 들어야한다고 생각합니다. 모든 코드를 다시 실행할 수는 없습니다.
user702846

2

@PriceHardman 의 솔루션에 대해 제기 된 의견에 따라 다음 버전의 클래스를 제안합니다.

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

이 클래스는 엔코더를 훈련 세트에 맞추고 변환 할 때 적합 버전을 사용합니다. 코드의 초기 버전은 여기 에서 찾을 수 있습니다 .


2

다음 LabelEncoder()과 같이 여러 열에 대한 간단한 방법입니다 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])

이것을 사용 le_dict하여 다른 열을 labelEncode 할 수 있습니다 .

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

2

팬더에서 직접이 작업을 수행 할 수 있으며 독창적 인 능력에 적합합니다. replace 방법 .

먼저 열과 해당 값을 새로운 대체 값에 매핑하는 사전 사전을 만들어 보겠습니다.

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

이것은 항상 일대일 매핑이기 때문에 내부 사전을 뒤집어 새 값을 원래 값으로 다시 매핑 할 수 있습니다.

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

이제이 replace메소드 의 고유 한 기능을 사용하여 중첩 된 사전 목록을 가져 와서 외부 키를 열로 사용하고 내부 키를 대체하려는 값으로 사용할 수 있습니다.

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

우리는 replace방법 을 다시 연결하여 쉽게 원본으로 돌아갈 수 있습니다

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

여기와 다른 곳에서 몇 가지 답변을 많이 검색하고 실험 한 후에 귀하의 답변이 여기에 있다고 생각합니다 .

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

이렇게하면 열의 범주 이름이 유지됩니다.

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

LabelEncoder 의 소스 코드 ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py )를 확인했습니다. 그것은 일련의 numpy 변환을 기반으로했으며, 그중 하나는 np.unique ()입니다. 그리고이 함수는 1 차원 배열 입력 만받습니다. (내가 틀렸다면 나를 교정하십시오).

매우 거친 아이디어 ... 먼저 LabelEncoder가 필요한 열을 식별 한 다음 각 열을 반복합니다.

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 는 인코딩 후 하나이며 label_list 는 해당 열에서 모든 값이 의미하는 바를 보여줍니다. 이것은 내가 작업을 위해 작성한 데이터 프로세스 스크립트의 스 니펫입니다. 추가 개선이 필요하다고 생각되면 알려주십시오.

편집 : 여기에 위의 방법이 최선을 놓치지 않고 데이터 프레임에서 작동한다는 것을 언급하고 싶습니다. 데이터 프레임으로 작동하는 방법이 확실하지 않은 데이터가 포함되어 있습니다. (위의 방법을 실행하기 전에 누락 된 절차를 다루었습니다.)


1

레이블 인코딩을 수행하는 단일 열이 있고 파이썬에 여러 열이있을 때 쉽게 변환하는 방법

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

데이터 프레임에 숫자 및 범주가있는 두 유형의 데이터가있는 경우 사용할 수 있습니다 : 여기 X는 범주 및 숫자 변수가있는 내 데이터 프레임입니다

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

참고 :이 기술은 변환에 관심이없는 경우에 유용합니다.


1

Neuraxle 사용

TLDR; 여기서는 FlattenForEach 래퍼 클래스를 사용하여 다음 과 같이 df를 간단히 변환 할 수 있습니다 FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df).

이 방법을 사용하면 라벨 엔코더가 일반 scikit-learn Pipeline 내에 맞고 변형 될 수 있습니다 . 간단히 가져 오자 :

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

열에 동일한 공유 인코더 :

다음은 하나의 공유 LabelEncoder를 인코딩하기 위해 모든 데이터에 적용하는 방법입니다.

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

결과:

    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)

열당 다른 엔코더 :

여기에 첫 번째 독립형 LabelEncoder가 애완 동물에 적용되는 방법과 두 번째가 컬럼 소유자 및 위치에 공유되는 방법이 있습니다. 정확하게 말하자면, 우리는 서로 다른 공유 레이블 인코더가 혼합되어 있습니다.

    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)

결과:

    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

주로 @Alexander 답변을 사용했지만 약간 변경해야했습니다.

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

그런 다음 나중에 재사용하려면 출력을 json 문서에 저장하면 필요할 때 읽을 수 있으며 .map()위에서했던 것처럼 함수를 사용할 수 있습니다.


0

문제는 맞춤 함수에 전달할 데이터의 모양 (pd 데이터 프레임)입니다. 당신은 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)

여기에서 위치에서 CSV를 읽고 있으며 함수에서 레이블을 지정하려는 열 목록과이를 적용하려는 데이터 프레임을 전달하고 있습니다.


0

이건 어때요?

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

가장 효율적이지는 않지만 작동하며 매우 간단합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.