scikit-learnの複数の列にわたるラベルエンコーディング


216

文字列ラベルのLabelEncoderパンダをエンコードするためにscikit-learnを使用しようとしていますDataFrame。データフレームには多数(50以上)の列があるLabelEncoderため、列ごとにオブジェクトを作成しないようにします。私はむしろ、データのすべての列LabelEncoderにわたって機能する1つの大きなオブジェクトが欲しいだけです。

全体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)ファイル "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py"、line 306、in column_or_1d raise ValueError( "bad input shape { 0} "。format(shape))ValueError:不正な入力形状(6、3)

この問題を回避する方法について何か考えはありますか?


なぜこれをやろうとしているのですか?
Fred Foo 2014年

dataframe文字列データの複数列のエンコードを簡略化します。私はエンコーディングオブジェクトをピクルしているので、50の個別のオブジェクトをピクル/ピクルする必要がないようにします。また、エンコーダーでデータを単純化する方法、つまり、各列の変数の一意の組み合わせごとに1つの行を識別子で返す方法はあるのでしょうか。
ブライアン

replaceメソッドの辞書の辞書を渡すことによってパンダでこれをすべて行う簡単な方法があります。以下のこの回答を参照してください
Ted Petrou 2017年

回答:


451

これは簡単にできますが、

df.apply(LabelEncoder().fit_transform)

EDIT2:

scikit-learn 0.20では、推奨される方法は

OneHotEncoder().fit_transform(df)

OneHotEncoderが文字列入力をサポートするようになったためです。ColumnTransformerを使用すると、特定の列にのみOneHotEncoderを適用できます。

編集:

この回答は1年以上前であり、多くの賛成票(報奨金を含む)を生成したので、おそらくこれをさらに拡張する必要があります。

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

2
これをLabelBinarizer代わりに使用してテストセットの辞書を再利用するにはどうすればよいですか?私が試したd = defaultdict(LabelBinarizer)し、次にfit = df.apply(lambda x: d[x.name].fit_transform(x))けど例外が発生しますException: Data must be 1-dimensional。結果のDataFrameがどのように見えるかはわかりません...多分各列は2値化されたベクトルを保持する必要があります。
Qululu 2017年

4
素晴らしい解決策。特定の列のみを変換する方法は?
stenlytw 2017

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

数値属性はそのままにして、2つのカテゴリー属性(fruitおよびcolor)をエンコードするとしますweight。これは次のように行うことができます。

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

fruit_dataデータセットを変換します

ここに画像の説明を入力してください

ここに画像の説明を入力してください

カテゴリ変数から完全に構成されるデータフレームを渡し、columnsパラメータを省略すると、すべての列がエンコードされます(これは元々探していたものだと思います)。

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

これは変形する

ここに画像の説明を入力してください

ここに画像の説明を入力してください

すでに数値である属性をエンコードしようとするとおそらく詰まることに注意してください(必要に応じてこれを処理するためのコードを追加します)。

これに関するもう1つの優れた機能は、このカスタムトランスフォーマーをパイプラインで使用できることです。

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

2
データがオレンジが緑に着色されていることを意味することを認識したところです。おっとっと。;)
PriceHardman

5
これはデータを1回変換するのに適した方法ですが、検証セットでこの変換を再利用したい場合はどうでしょうか。もう一度fit_transformを実行する必要があり、新しいデータセットにすべての変数のすべてのカテゴリがないなどの問題が発生する可能性があります。たとえば、緑色が新しいデータセットに表示されないとします。これはエンコーディングを台無しにするでしょう。
Ben

3
@Benに同意しました。これは、実際にはメソッド名以外のsklearnを模倣していません。これをパイプラインに入れようとしても機能しません
Tgsmith61591

3
ラベルのエンコーディングがトレーニングセットとテストセットの両方で一貫していることを確認するには、データセット全体(トレーニング+テスト)でエンコーディングを実行する必要があります。これは、それらをトレーニングとテストに分割する前に行うか、それらを組み合わせてエンコードを実行し、再度分割して戻すことができます。
PriceHardman 2016

2
逆に行ってみませんか?元にデコードしますか?
user702846

18

scikit-learn 0.20以降では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'}}

1つの列(ターゲット変数の例:Y)に戻りたい(リバースしたい)場合、どうすればよいですか?
Ib D

9

これはあなたの質問に直接答えることはありません(Naputipulu JonとPriceHardmanは素晴らしい回答を持っています)

ただし、いくつかの分類タスクなどの目的で使用できます

pandas.get_dummies(input_df) 

これは、カテゴリカルデータを含むデータフレームを入力し、バイナリ値を含むデータフレームを返すことができます。変数値は、結果のデータフレームの列名にエンコードされます。もっと


6

sklearn.preprocessing.LabelEncoder()列を表すために使用できるオブジェクトを取得しようとしているだけだとすると、次のことを行うだけです。

le.fit(df.columns)

上記のコードでは、各列に対応する一意の番号があります。より正確には、1対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さて、これを踏まえて、一度に全体で文字列ラベルをエンコードできる最良の方法についての提案は何ですか?
ブライアン

@ブライアンLabelEncoderコードを見て、それを適応させます。私はパンダを自分で使っていないので、それがどれほど難しいかわかりません。
Fred Foo

他のpandas人にもこの質問に答えてもらいましょう-この問題を抱えているのは私だけではないので、事前に構築された解決策があるといいのですが。
ブライアン

5

これは1年半後のことですが、私も、.transform()複数のpandasデータフレーム列を一度に(そして.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()混合型ですpandasデータフレーム、あなたは適用することができます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_


こんにちはJason、mcle.all_labels_が機能していないようです(Python 3.5、Conda 4.3.29、Sklearn 0.18.1、Pandas 0.20.1。私は次のように取得します。AttributeError: 'MultiColumnLabelEncoder' object has no attribute 'all_labels_'
Jason

@ジェイソンこんにちは、申し訳ありませんが、今日まで見ていませんでした:/でも、推測する必要がある場合はfit、上記の方法を使用しただけで、実際にラベルを付けるまで、ラベルは生成されません(transform/ fit_transform)。データ。
Jason Wolosonovich、2018年

あなたはもっと良い例を書く必要があると思います-私はすべてのコードを再実行することができませんでした。
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}}

これは常に1対1のマッピングであるため、内部辞書を反転させて、新しい値のマッピングを元のマッピングに戻すことができます。

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

ソースコードをチェックしました(https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.pyLabelEncoder)を確認しました。numpy変換のセットに基づいており、そのうちの1つは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

ラベルのエンコードとその逆変換を行う単一の列がある場合、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

データフレームに数値とカテゴリの両方のタイプのデータがある場合使用できます:ここで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パイプラインに適合および変換できます。インポートしましょう:

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

列の同じ共有エンコーダー:

これは、1つの共有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がペットに適用され、2番目は列の所有者と場所で共有される方法です。正確に言うと、ここには異なる共有ラベルエンコーダーが混在しています。

    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

問題は、関数fitに渡すデータ(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を読み取り、関数でlabelencodeしたい列リストとこれを適用したいデータフレームを渡します。


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.