python-3.x - 如何有效地为测试数据编码多个分类列?
问题描述
我有多个类别列(近 50 个)。我使用定制的频率编码并将其用于训练数据。最后我将它保存为嵌套字典。对于测试数据,我使用 map 函数进行编码,看不见的标签被替换为 0。但我需要更有效的方法吗?
我已经尝试过 pandas replace 方法,但它不关心看不见的标签,而是保持原样。此外,我非常关心时间,我希望在 60 毫秒内编码 80 列和 1 行。只需要我能做到的最有效的方法。我从这里举了我的例子。
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 毫秒。任何想法如何更有效地做到这一点。不确定多处理是否有效..?进一步使用替换方法,我遇到了许多问题,例如: 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)
解决方案
首先,当您要编码非序数的分类变量时(意思是:变量/列的值之间没有内在的顺序。例如cat
,dog
),您必须使用一种热编码。
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
as时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)
更新:
如果您对序数内切没问题,以下更改可能会有所帮助。
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
推荐阅读
- flutter - 如何在颤动中显示没有 Context 对象的 Snackbar?
- python - X.shape[1] = 2 应该等于9,训练时的特征个数
- excel - Selenium Web 驱动程序从下拉列表中选择选项
- java - 我使用@Query 和 Pageable 有错误:只有在通过引用列名的表达式进行排序时才允许使用变量
- java - 如何从 jenkinsFile 传递多个参数,如 env、凭据、黄瓜标签
- blender - 使用 gltf-part 在 Aframe 中导入的场景将对象原点重置为 0,0,0
- corda - 如何在corda社区版中访问网络参数的HTTP Rest API端点?
- python - 使用 Pandas 使用列的最小值构建另一个数据框
- java - 为什么我的“中位数”算法总是错在几个位置?
- android - React Native Android 应用程序安全检查显示到 googleapis.com 的传出流量