标签编码器编码缺失值

Posted

技术标签:

【中文标题】标签编码器编码缺失值【英文标题】:label-encoder encoding missing values 【发布时间】:2016-08-16 22:43:41 【问题描述】:

我正在使用标签编码器将分类数据转换为数值。

LabelEncoder 如何处理缺失值?

from sklearn.preprocessing import LabelEncoder
import pandas as pd
import numpy as np
a = pd.DataFrame(['A','B','C',np.nan,'D','A'])
le = LabelEncoder()
le.fit_transform(a)

输出:

array([1, 2, 3, 0, 4, 1])

对于上面的示例,标签编码器将 NaN 值更改为类别。我怎么知道哪个类别代表缺失值?

【问题讨论】:

***.com/a/60186800/10375049 【参考方案1】:

这是我的尝试!

import numpy as np
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
#Now lets encode the incomplete Cabin feature
titanic_train_le['Cabin'] = le.fit_transform(titanic_train_le['Cabin'].astype(str))
#get nan code for the cabin categorical feature
cabin_nan_code=le.transform(['nan'])[0]
#Now, retrieve the nan values in the encoded data
titanic_train_le['Cabin'].replace(cabin_nan_code,np.nan,inplace=True)

【讨论】:

请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。【参考方案2】: 我想和你分享我的解决方案。 我创建了一个模块,它采用混合数据集并将其从分类转换为数值 和逆。

这个模块也可以在my Github 中找到,并带有示例。 如果您喜欢我的解决方案,请点赞。

谢谢, 伊丹

class label_encoder_contain_missing_values :

        def __init__ (self) :    
            pass  

        def categorical_to_numeric (self,dataset):
            import numpy as np
            import pandas as pd
            
            self.dataset = dataset
            self.summary = None
            self.table_encoder= 

            for index in self.dataset.columns :
                if self.dataset[index].dtypes == 'object' :               
                   column_data_frame = pd.Series(self.dataset[index],name='column').to_frame()
                   unique_values = pd.Series(self.dataset[index].unique())
                   i = 0
                   label_encoder = pd.DataFrame('value_name':[],'Encode':[])
                   while i <= len(unique_values)-1:
                         if unique_values.isnull()[i] == True : 
                           label_encoder = label_encoder.append('value_name': unique_values[i],'Encode':np.nan, ignore_index=True) #np.nan = -1
                         else:
                           label_encoder = label_encoder.append('value_name': unique_values[i],'Encode':i, ignore_index=True)
                         i+=1 

                   output = pd.merge(left=column_data_frame,right = label_encoder, how='left',left_on='column',right_on='value_name')
                   self.summary = output[['column','Encode']].drop_duplicates().reset_index(drop=True)
                   self.dataset[index] = output.Encode 
                   self.table_encoder.update(index:self.summary)
                    
                else :
                     pass
                     
            # ---- Show Encode Table ----- #               
            print('''\nLabel Encoding completed in Successfully.\n
                       Next steps: \n
                       1.  To view table_encoder, Execute the follow: \n
                           for index in table_encoder :
                           print(f'\\nindex \\n',table_encoder[index])
                           
                       2. For inverse, execute the follow : \n
                          df = label_encoder_contain_missing_values().
                               inverse_numeric_to_categorical(table_encoder, df) ''') 
                        
            return self.table_encoder  ,self.dataset 
        

        def inverse_numeric_to_categorical (self,table_encoder, df):
            dataset = df.copy()
            for column in table_encoder.keys():
                df_column = df[column].to_frame()
                output = pd.merge(left=df_column,right = table_encoder[column], how='left',left_on= column,right_on='Encode')#.rename(columns='column_x' :'encode','column_y':'category')
                df[column]= output.column
            print('\nInverse Label Encoding, from categorical to numerical completed in Successfully.\n')
            return df
            
**execute command from categorical to numerical** <br>
table_encoder, df = label_encoder_contain_missing_values().categorical_to_numeric(df) 

**execute command from numerical to categorical** <br>
df = label_encoder_contain_missing_values().inverse_numeric_to_categorical(table_encoder, df)

【讨论】:

【参考方案3】:

此函数从数据框中获取一列并返回仅对非 NaN 进行标签编码的列,其余部分保持不变

import pandas as pd
from sklearn.preprocessing import LabelEncoder

def label_encode_column(col):
    nans = col.isnull()
    nan_lst = []
    nan_idx_lst = []
    label_lst = []
    label_idx_lst = []

    for idx, nan in enumerate(nans):
        if nan:
            nan_lst.append(col[idx])
            nan_idx_lst.append(idx)
        else:
            label_lst.append(col[idx])
            label_idx_lst.append(idx)

    nan_df = pd.DataFrame(nan_lst, index=nan_idx_lst)
    label_df = pd.DataFrame(label_lst, index=label_idx_lst) 

    label_encoder = LabelEncoder()
    label_df = label_encoder.fit_transform(label_df.astype(str))
    label_df = pd.DataFrame(label_df, index=label_idx_lst)
    final_col = pd.concat([label_df, nan_df])
    
    return final_col.sort_index()

【讨论】:

【参考方案4】:

这是我的解决方案,因为我对此处发布的解决方案不满意。我需要一个 LabelEncoder 将我的缺失值保留为 NaN 以便之后使用 Imputer。所以我写了我自己的LabelEncoder 类。它适用于 DataFrame。

from sklearn.base import BaseEstimator
from sklearn.base import TransformerMixin
from sklearn.preprocessing import LabelEncoder

class LabelEncoderByCol(BaseEstimator, TransformerMixin):
    def __init__(self,col):
        #List of column names in the DataFrame that should be encoded
        self.col = col
        #Dictionary storing a LabelEncoder for each column
        self.le_dic = 
        for el in self.col:
            self.le_dic[el] = LabelEncoder()

    def fit(self,x,y=None):
        #Fill missing values with the string 'NaN'
        x[self.col] = x[self.col].fillna('NaN')
        for el in self.col:
            #Only use the values that are not 'NaN' to fit the Encoder
            a = x[el][x[el]!='NaN']
            self.le_dic[el].fit(a)
        return self

    def transform(self,x,y=None):
        #Fill missing values with the string 'NaN'
        x[self.col] = x[self.col].fillna('NaN')
        for el in self.col:
            #Only use the values that are not 'NaN' to fit the Encoder
            a = x[el][x[el]!='NaN']
            #Store an ndarray of the current column
            b = x[el].to_numpy()
            #Replace the elements in the ndarray that are not 'NaN'
            #using the transformer
            b[b!='NaN'] = self.le_dic[el].transform(a)
            #Overwrite the column in the DataFrame
            x[el]=b
        #return the transformed DataFrame
        return x

您可以输入 DataFrame,而不仅仅是 1-dim Series。使用 col 你可以选择应该编码的列。

我想在这里提供一些反馈。

【讨论】:

我使用了newdf = LabelEncoderByCol(df) - 现在如何将其转换为熊猫? 如果测试集的值不在训练集中怎么办。 @whatsnext 它与原始的 LabelEncoder 具有相同的行为,但具有看不见的值。您可能需要一些额外的行来实现体面的行为。参考:***.com/questions/21057621/…如果您编辑我的答案以改进,我会批准。 能否包含inverse_transform函数?【参考方案5】:

您可以通过将缺失值替换为字符串“NaN”来处理缺失值。类别可以通过le.transfrom()获取。

le.fit_transform(a.fillna('NaN'))
category = le.transform(['NaN'])

另一种解决方案是标签编码器忽略缺失值。

a = le.fit_transform(a.astype(str))

【讨论】:

【参考方案6】:

@Kerem 投票最多的答案有错别字,因此我在此处发布更正和改进的答案:

from sklearn.preprocessing import LabelEncoder
import pandas as pd
import numpy as np
a = pd.DataFrame(['A','B','C',np.nan,'D','A'])
for j in a.columns.values:
    le = LabelEncoder()
### fit with the desired col, col in position 0 for this ###example
    fit_by = pd.Series([i for i in a[j].unique() if type(i) == str])
    le.fit(fit_by)
    ### Set transformed col leaving np.NaN as they are
    a["transformed"] = a[j].apply(lambda x: le.transform([x])[0] if type(x) == str else x)

【讨论】:

【参考方案7】:

您也可以使用掩码替换标记后的原始数据框

df = pd.DataFrame('A': ['x', np.NaN, 'z'], 'B': [1, 6, 9], 'C': [2, 1, np.NaN])

    A   B   C
0   x   1   2.0
1   NaN 6   1.0
2   z   9   NaN

original = df
mask = df_1.isnull()
       A    B   C
0   False   False   False
1   True    False   False
2   False   False   True

df = df.astype(str).apply(LabelEncoder().fit_transform)
df.where(~mask, original)

A   B   C
0   1.0 0   1.0
1   NaN 1   0.0
2   2.0 2   NaN

【讨论】:

【参考方案8】:

我也想贡献我的解决方法,因为在处理包含缺失值的分类数据时,我发现其他解决方法有点乏味

# Create a random dataframe
foo = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))

# Randomly intersperse column 'A' with missing data (NaN)
foo['A'][np.random.randint(0,len(foo), size=20)] = np.nan

# Convert this series to string, to simulate our problem
series = foo['A'].astype(str)

# np.nan are converted to the string "nan", mask these out
mask = (series == "nan")

# Apply the LabelEncoder to the unmasked series, replace the masked series with np.nan
series[~mask] = LabelEncoder().fit_transform(series[~mask])
series[mask] = np.nan

foo['A'] = series

【讨论】:

【参考方案9】:

这是一个简单的方法

是Titanic的例子

LABEL_COL = ["Sex", "Embarked"]

def label(df):
    _df = df.copy()
    le = LabelEncoder()
    for col in LABEL_COL:
        # Not NaN index
        idx = ~_df[col].isna()
        _df.loc[idx, col] \
            = le.fit(_df.loc[idx, col]).transform(_df.loc[idx, col])
    return _df

【讨论】:

很好,您可以立即使用 fit_transform:_df.loc[idx, col] = le.fit_transform(_df.loc[idx, col])【参考方案10】:

我就是这样做的:

import pandas as pd
from sklearn.preprocessing import LabelEncoder

UNKNOWN_TOKEN = '<unknown>'
a = pd.Series(['A','B','C', 'D','A'], dtype=str).unique().tolist()
a.append(UNKNOWN_TOKEN)
le = LabelEncoder()
le.fit_transform(a)
embedding_map = dict(zip(le.classes_, le.transform(le.classes_)))

当应用于新的测试数据时:

test_df = test_df.apply(lambda x: x if x in embedding_map else UNKNOWN_TOKEN)
le.transform(test_df)

【讨论】:

【参考方案11】:

以下编码器地址每个类别中都没有值。

class MultiColumnLabelEncoder:
    def __init__(self):
        self.columns = None
        self.led = defaultdict(preprocessing.LabelEncoder)

    def fit(self, X):
        self.columns = X.columns
        for col in self.columns:
            cat = X[col].unique()
            cat = [x if x is not None else "None" for x in cat]
            self.led[col].fit(cat)
        return self

    def fit_transform(self, X):
        if self.columns is None:
            self.fit(X)
        return self.transform(X)

    def transform(self, X):
        return X.apply(lambda x:  self.led[x.name].transform(x.apply(lambda e: e if e is not None else "None")))

    def inverse_transform(self, X):
        return X.apply(lambda x: self.led[x.name].inverse_transform(x))

使用示例

df = pd.DataFrame(
    'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
    'owner': ['Champ', 'Ron', 'Brick', None, 'Veronica', 'Ron'],
    'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
                 None]
)


print(df)

   location     owner    pets
0  San_Diego     Champ     cat
1   New_York       Ron     dog
2   New_York     Brick     cat
3  San_Diego      None  monkey
4  San_Diego  Veronica     dog
5       None       Ron     dog

le = MultiColumnLabelEncoder()
le.fit(df)

transformed = le.transform(df)
print(transformed)

   location  owner  pets
0         2      1     0
1         0      3     1
2         0      0     0
3         2      2     2
4         2      4     1
5         1      3     1

inverted = le.inverse_transform(transformed)
print(inverted)

        location     owner    pets
0  San_Diego     Champ     cat
1   New_York       Ron     dog
2   New_York     Brick     cat
3  San_Diego      None  monkey
4  San_Diego  Veronica     dog
5       None       Ron     dog

【讨论】:

【参考方案12】:

您好,我为自己的工作做了一点计算技巧:

from sklearn.preprocessing import LabelEncoder
import pandas as pd
import numpy as np
a = pd.DataFrame(['A','B','C',np.nan,'D','A'])
le = LabelEncoder()
### fit with the desired col, col in position 0 for this example
fit_by = pd.Series([i for i in a.iloc[:,0].unique() if type(i) == str])
le.fit(fit_by)
### Set transformed col leaving np.NaN as they are
a["transformed"] = fit_by.apply(lambda x: le.transform([x])[0] if type(x) == str else x)

【讨论】:

fit_by是一个列表,列表没有.apply()方法,请更正 他的回答可能只是一个错字。使用 apply(function,axis=1) 或 map。例如:df['col'] = df['col'].map(lambda x: le.transform([x])[0] if type(x)==str else x)【参考方案13】:

您可以用一些值填充 na,然后将数据框列类型更改为字符串以使其正常工作。

from sklearn.preprocessing import LabelEncoder
import pandas as pd
import numpy as np
a = pd.DataFrame(['A','B','C',np.nan,'D','A'])
a.fillna(99)
le = LabelEncoder()
le.fit_transform(a.astype(str))

【讨论】:

【参考方案14】:

我遇到了同样的问题,但以上方法都不适合我。所以我在只包含“nan”的训练数据中添加了一个新行

【讨论】:

【参考方案15】:

不要使用带有缺失值的LabelEncoder。我不知道您使用的是哪个版本的 scikit-learn,但在 0.17.1 中,您的代码会引发 TypeError: unorderable types: str() &gt; float()

如您所见,in the source 它使用numpy.unique 对数据进行编码,如果发现缺失值,则会引发TypeError。如果要对缺失值进行编码,首先将其类型改为字符串:

a[pd.isnull(a)]  = 'NaN'

【讨论】:

所以您会将“NaN”编码为虚拟值?我有同样的问题,但想使用估算值进行线性回归。 模型对缺失值 (nan) 和“Nan”的处理方式不同。一种解决方法是仅使用具有非缺失值的 LabelEnconder,并让 nan 值保持不变: df['col'] = df['col'].map(lambda x: le.transform([x])[0] if type(x)==str else x)

以上是关于标签编码器编码缺失值的主要内容,如果未能解决你的问题,请参考以下文章

详解支持向量机-SVC真实数据案例:预测明天是否会下雨-填补缺失值和编码菜菜的sklearn课堂笔记

R语言构建xgboost模型:使用xgboost模型训练tweedie回归模型,特征工程(dataframe转化到data.table独热编码缺失值删除DMatrix结构生成)

数据竞赛知识点 | 数值特征的缩放与编码

R语言使用caret包的predict函数对测试数据集进行数据预处理(和训练集的处理方式保持一致):缺失值填充数值变量最小最大缩放因子变量独热编码等

集成学习模型(xgboostlightgbmcatboost)进行回归预测构建实战:异常数据处理缺失值处理数据重采样resample独热编码预测特征检查特征可视化预测结构可视化模型

机器学习--数据预处理