การเข้ารหัสเลเบลในหลายคอลัมน์ใน scikit-Learn


217

ฉันกำลังพยายามใช้ scikit-Learn LabelEncoderเพื่อเข้ารหัส pandas DataFrameของสตริงฉลาก เนื่องจาก 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) ไฟล์ "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py" บรรทัด 306 ในคอลัมน์ _or_1d เพิ่ม ValueError ("รูปร่างอินพุตไม่ดี { 0} ". format (shape)) ValueError: รูปร่างอินพุตไม่ถูกต้อง (6, 3)

มีความคิดเห็นเกี่ยวกับวิธีแก้ไขปัญหานี้ไหม?


ทำไมคุณถึงพยายามทำเช่นนี้?
Fred Foo

เพื่อลดความซับซ้อนของการเข้ารหัสdataframeข้อมูลสตริงหลายคอลัมน์ ฉันกำลังอ่านออบเจ็กต์การเข้ารหัสดังนั้นต้องการหลีกเลี่ยงการแยก / ปลดล็อค 50 วัตถุแยกต่างหาก นอกจากนี้ฉันสงสัยว่ามีวิธีให้ตัวเข้ารหัสทำให้ข้อมูลง่ายขึ้นหรือไม่เช่นส่งคืนหนึ่งแถวด้วยตัวระบุสำหรับชุดค่าผสมที่ไม่ซ้ำกันของตัวแปรในแต่ละคอลัมน์
ไบรอัน

มีวิธีง่าย ๆ ในการทำทั้งหมดนี้ใน pandas โดยส่งพจนานุกรมของพจนานุกรมไปยังreplaceวิธีการ ดูคำตอบนี้ด้านล่าง
Ted Petrou

คำตอบ:


452

คุณสามารถทำได้อย่างง่ายดายแม้ว่า

df.apply(LabelEncoder().fit_transform)

EDIT2:

ใน scikit เรียนรู้ 0.20 วิธีที่แนะนำคือ

OneHotEncoder().fit_transform(df)

เนื่องจาก OneHotEncoder รองรับการป้อนสตริง การใช้ OneHotEncoder กับคอลัมน์บางคอลัมน์เป็นไปได้ด้วย ColumnTransformer

แก้ไข:

เนื่องจากคำตอบนี้มากกว่าหนึ่งปีที่ผ่านมาและสร้าง upvotes จำนวนมาก (รวมถึงเงินรางวัล) ฉันอาจจะขยายต่อไปนี้

สำหรับ 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
ถ้าฉันต้องการที่จะผกผันการเข้ารหัส juste สำหรับหนึ่งคอลัมน์ฉันจะทำอย่างไร
Ib D

95

ตามที่ได้รับการกล่าวถึงโดย larsmans LabelEncoder () ใช้อาร์เรย์ 1-d เป็นอาร์กิวเมนต์เท่านั้น ที่กล่าวมาแล้วมันค่อนข้างง่ายที่จะม้วนโปรแกรมเข้ารหัสฉลากของคุณเองที่ทำงานในหลายคอลัมน์ที่คุณเลือกและส่งคืนดาต้าเฟรมที่แปลงแล้ว รหัสของฉันที่นี่ตั้งอยู่ในส่วนที่เกี่ยวกับบล็อกโพสต์ซัคสจ๊วตดีเยี่ยมพบที่นี่

การสร้างการเข้ารหัสที่กำหนดเองที่เกี่ยวข้องกับการเพียงแค่การสร้างชั้นที่ตอบสนองต่อการ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)

สมมติว่าเราต้องการเข้ารหัสแอตทริบิวต์ที่เป็นหมวดหมู่ทั้งสองของเรา ( fruitและcolor) ในขณะที่ปล่อยคุณลักษณะตัวเลขweightไว้เท่านั้น เราสามารถทำได้ดังนี้:

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

ซึ่งเปลี่ยนfruit_dataชุดข้อมูลของเราจาก

ป้อนคำอธิบายรูปภาพที่นี่ ถึง

ป้อนคำอธิบายรูปภาพที่นี่

ผ่านมันไปเป็น dataframe ที่ประกอบด้วยตัวแปรเด็ดขาดและการละเว้น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

5
นี่เป็นวิธีที่ดีในการแปลงข้อมูลเพียงครั้งเดียว แต่ถ้าฉันต้องการนำการแปลงนี้กลับมาใช้ใหม่ในชุดการตรวจสอบความถูกต้อง คุณจะต้อง fit_transform อีกครั้งและปัญหาอาจเกิดขึ้นเช่นชุดข้อมูลใหม่ของฉันไม่ได้มีหมวดหมู่ทั้งหมดสำหรับตัวแปรทั้งหมด เช่น. สมมติว่าสีเขียวไม่ปรากฏในชุดข้อมูลใหม่ของฉัน สิ่งนี้จะทำให้การเข้ารหัสยุ่งเหยิง
Ben

3
ตกลงกับ @Ben สิ่งนี้ไม่ได้เลียนแบบ sklearn เลยนอกเหนือจากชื่อเมธอด หากคุณพยายามที่จะนำสิ่งนี้ไปป์ไลน์มันจะไม่ทำงาน
Tgsmith61591

3
เพื่อให้แน่ใจว่าการเข้ารหัสฉลากมีความสอดคล้องกันทั้งในชุดรถไฟและชุดทดสอบคุณจะต้องทำการเข้ารหัสบนชุดข้อมูลทั้งหมดของคุณ (รถไฟ + ทดสอบ) สิ่งนี้สามารถทำได้ก่อนที่คุณจะแยกพวกเขาออกเป็นรถไฟและทดสอบหรือคุณสามารถรวมพวกมันทำการเข้ารหัสและแยกออกมาอีกครั้ง
PriceHardman

2
จะย้อนกลับอย่างไร ถอดรหัสกลับเป็นต้นฉบับหรือไม่
user702846

18

ตั้งแต่ scikit เรียนรู้ 0.20 คุณสามารถใช้sklearn.compose.ColumnTransformerและsklearn.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) 

สิ่งนี้สามารถป้อนข้อมูล dataframe ด้วยข้อมูลเด็ดขาดและส่งคืน dataframe ด้วยค่าไบนารี่ ค่าตัวแปรจะถูกเข้ารหัสเป็นชื่อคอลัมน์ใน dataframe ผลลัพธ์ มากกว่า


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. แสดงแต่ละคู่เป็นเวอร์ชันสตริงของ tuple นี่เป็นวิธีแก้ปัญหาเพื่อเอาชนะLabelEncoderคลาสที่ไม่สนับสนุนสิ่งอันดับเป็นชื่อคลาส
  3. LabelEncoderเหมาะกับรายการใหม่ไป

ตอนนี้ใช้โมเดลใหม่มันซับซ้อนกว่านี้เล็กน้อย สมมติว่าเราต้องการแยกการแสดงสำหรับรายการเดียวกันที่เราค้นหาในตัวอย่างก่อนหน้า (คอลัมน์แรกใน df.columns และแถวแรก) เราสามารถทำสิ่งนี้:

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

โปรดจำไว้ว่าขณะนี้การค้นหาแต่ละรายการเป็นการแสดงสตริงของ tuple ที่มี (คอลัมน์, แถว)


5

ไม่มีLabelEncoderไม่ได้ทำเช่นนี้ ต้องใช้อาร์เรย์ 1-d ของคลาสป้ายชื่อและสร้างอาร์เรย์ 1-d มันถูกออกแบบมาเพื่อจัดการกับเลเบลของคลาสในปัญหาการจัดหมวดหมู่ไม่ใช่ข้อมูลโดยพลการและความพยายามใด ๆ ในการบังคับให้ใช้งานอื่น ๆ จะต้องใช้รหัสในการแปลงปัญหาจริงให้เป็นปัญหาที่แก้ไขได้


ตกลงรับสิ่งนี้ข้อเสนอแนะของคุณเกี่ยวกับวิธีที่ดีที่สุดที่ฉันสามารถเข้ารหัสฉลากสตริงโดยรวมDataFrameในเวลาคืออะไร?
ไบรอัน

@ ไบรอันดูLabelEncoderรหัสแล้วปรับมัน ฉันไม่ได้ใช้หมีแพนด้าด้วยตัวเองดังนั้นฉันจึงไม่รู้ว่ามันจะยากแค่ไหน
Fred Foo

ฉันจะปล่อยให้pandasคนอื่นถามคำถามนี้ด้วย - ฉันแน่ใจว่าฉันไม่ใช่คนเดียวที่มีความท้าทายนี้ดังนั้นฉันหวังว่าอาจมีวิธีแก้ปัญหาที่สร้างไว้ล่วงหน้า
ไบรอัน

5

นี่เป็นครึ่งปีหลังจากความจริง แต่ฉันก็ต้องมี.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

ตัวอย่าง:

หากdfและdf_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_


สวัสดี Jason, mcle.all_labels_ ไม่ทำงาน (Python 3.5, Conda 4.3.29, Sklearn 0.18.1, Pandas 0.20.1. ฉันได้รับ: AttributeError: วัตถุ 'MultiColumnLabelEncoder' ไม่มีแอตทริบิวต์ 'all_labels_'
Jason

@ 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 (คอลัมน์ = 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.py ) ของ LabelEncoder มันขึ้นอยู่กับชุดของการแปลง numpy ซึ่งหนึ่งในนั้นคือ np.unique () และฟังก์ชั่นนี้ใช้อินพุตอาร์เรย์ 1-d เท่านั้น (แก้ไขฉันถ้าฉันผิด)

แนวคิดที่หยาบมาก ... ก่อนอื่นให้ระบุว่าคอลัมน์ใดจำเป็นต้องใช้ 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

หากคุณมีทั้งตัวเลขและหมวดหมู่ของข้อมูลใน dataframe คุณสามารถใช้: ที่นี่ X คือ dataframe ของฉันที่มีทั้งตัวแปรและตัวเลขที่แน่ชัด

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 เรียนรู้ทางท่อ ลองนำเข้า:

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

Encoder ที่แชร์แบบเดียวกันสำหรับคอลัมน์:

นี่คือวิธีที่ 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 dataframe) ที่คุณกำลังส่งผ่านไปยังฟังก์ชั่นพอดี คุณต้องผ่านรายการ 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.