如何有效地对测试数据的多个分类列进行编码?

时间:2019-07-15 00:37:15

标签: python-3.x pandas encoding scikit-learn

我有多个类别列(将近50个)。我使用定制的频率编码并将其用于训练数据。最后,我将其保存为嵌套字​​典。对于测试数据,我正在使用map函数进行编码,看不见的标签替换为0。但是我需要更有效的方法?

我已经尝试过用熊猫替换方法,但是它不关心看不见的标签,而是将其保留下来。此外,我非常担心时间,我想说60毫秒内要编码80列和1行。只需要我能做到的最有效的方法。我以here为例。

import pandas
from sklearn import preprocessing 

df = pandas.DataFrame({'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'meo'], 
                       'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'], 
                       'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego', 
             'New_York']})

我的字典看起来像这样:

enc = {'pets': {'cat': 0, 'dog': 1, 'monkey': 2},
       'owner': {'Brick': 0, 'Champ': 1, 'Ron': 2, 'Veronica': 3},
       'location': {'New_York': 0, 'San_Diego': 1}}

for col in enc:
    if col in input_df.columns:
        input_df[col]= input_df[col].map(dict_online['encoding'][col]).fillna(0)

我还希望同时对多个列进行编码。我不希望每一列都有任何循环。...我想我们不能在地图中做到这一点。因此,替换是一个不错的选择,但正如所说的那样,它并不关心看不见的标签。

编辑:

这是我现在使用的代码,请注意测试数据帧中只有1行(不是很确定我应该像numpy数组那样处理它,以减少时间...)。但是我需要将此时间减少到60毫秒以下:此外,我仅具有用于映射的字典(由于用例而不能使用一个热门的字典)。当前时间= 331.74毫秒。任何想法如何更有效地做到这一点。不确定多重处理是否可以工作。进一步用replace方法,我遇到了许多问题,例如:1.它不处理看不见的标签,并保持原样(对于字符串问题)。 2.键和值的重叠存在问题。

from string import ascii_lowercase
import itertools
import pandas as pd
import numpy as np
import time

def iter_all_strings():
    for size in itertools.count(1):
       for s in itertools.product(ascii_lowercase, repeat=size):
           yield "".join(s)


l = []
for s in iter_all_strings():
    l.append(s)
    if s == 'gr':
        break

columns = l
df = pd.DataFrame(columns=columns)
for col in df.columns:
    df[col] = np.random.randint(1, 4000, 3000)

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
print(f"The length of the dictionary is {len(transform_dict)}")


# Creating another test data frame
df2 = pd.DataFrame(columns=columns)
for col in df2.columns:
    df2[col] = np.random.randint(1, 4000, 1)
print(f"The shape of teh 2nd data frame is {df2.shape}")

t1 = time.time()

for col in df2.columns:
    df2[col] = df2[col].map(transform_dict[col]).fillna(0)
print(f"Time taken is {time.time() - t1}")
# print(df)

1 个答案:

答案 0 :(得分:0)

首先,当您要对非序数的分类变量进行编码时(意味着:变量/列的值之间没有固有的顺序。例如,catdog),您可以必须使用一种热编码。

import pandas as pd
from sklearn.preprocessing import OneHotEncoder 

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

enc = [['cat','dog','monkey'],
       ['Brick', 'Champ', 'Ron', 'Veronica'],
       ['New_York', 'San_Diego']]
ohe = OneHotEncoder(categories=enc, handle_unknown='ignore', sparse=False)

在这里,我已经修改了您的enc,可以将其添加到OneHotEncoder中。

  

现在我们要如何处理看不见的问题   标签?

当您将handle_unknown设为False时,所有虚拟变量中看不见的值将为零,这在某种程度上将有助于模型理解其未知值。

colnames= ['{}_{}'.format(col,val) for col,unique_values in zip(df.columns,ohe.categories_) \
                                       for val in unique_values]
pd.DataFrame(ohe.fit_transform(df), columns=colnames) 

enter image description here

更新:

如果您对序贯性没事,可以进行以下更改。


df2.apply(lambda row: [transform_dict[val].get(col,0) \
                                    for val,col in row.items()], 
          axis=1,
          result_type='expand')

#1000 loops, best of 3: 1.17 ms per loop