我一直在开发一个工具,可以自动预处理熊猫中的数据。数据帧格式。在此预处理步骤中,我希望以不同的方式处理连续数据和分类数据。特别是,我希望能够将OneHotEncoder应用于分类数据。
现在,让我们假设我们得到了一只熊猫。数据帧,并且没有关于数据帧中数据的其他信息。什么是好的启发式方法,用于确定熊猫中的一列是否。数据帧是分类的?
我最初的想法是:
1)如果列中有字符串(例如,列数据类型为object
),则该列很可能包含分类数据
2)如果列中某些百分比的值是唯一的(例如,>=20%),则该列很可能包含连续数据
我发现1)
工作正常,但2)
效果不佳。我需要更好的启发式方法。你会如何解决这个问题?
编辑:有人要求我解释为什么2)
效果不佳。在一些测试案例中,我们在一列中仍然有连续值,但列中唯一值不多。在这种情况下,2)
启发式显然失败了。还有一些问题,我们有一个分类列,其中包含许多唯一值,例如,泰坦尼克号数据集中的乘客姓名。存在相同的列类型错误分类问题。
这里有几种方法:
- 查找唯一值
数与唯一值总数的比率。如下所示
likely_cat = {} for var in df.columns: likely_cat[var] = 1.*df[var].nunique()/df[var].count() < 0.05 #or some other threshold
检查前 n 个唯一值是否占所有值的一定比例
top_n = 10 likely_cat = {} for var in df.columns: likely_cat[var] = 1.*df[var].value_counts(normalize=True).head(top_n).sum() > 0.8 #or some other threshold
1) 通常比方法 2 更适合我)。但是,如果存在"长尾分布",则方法2)更好,其中少量分类变量具有高频率,而大量分类变量具有低频率。
地方可以"窃取"可以转换为"数字"的格式的定义。 ##,#e-# 将是这种格式之一,只是为了说明。也许你可以找到一个图书馆来做到这一点。我尝试先将所有内容转换为数字,剩下的是什么,好吧,除了将它们保持分类之外别无他法。
您可以定义哪些数据类型算作数字,然后排除相应的变量
如果初始数据帧为 df:
numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
dataframe = df.select_dtypes(exclude=numerics)
这里真正的问题是你是想偶尔打扰用户还是偶尔默默地失败。
如果您不介意打扰用户,也许检测歧义并引发错误是要走的路。
如果你不介意默默地失败,那么你的启发式方法就可以了。我不认为你会找到任何明显更好的东西。我想如果你真的愿意,你可以把它变成一个学习问题。下载一堆数据集,假设它们共同是世界上所有数据集的体面表示,并根据每个数据集/列的特征进行训练,以预测分类与连续。
但当然,最终没有什么是完美的。 例如,列 [1, 8, 22, 8, 9, 8] 是指一天中的小时数还是犬种?
我一直在考虑一个类似的问题,我考虑得越多,似乎这本身就是一个分类问题,可以从训练模型中受益。
我敢打赌,如果您检查了一堆数据集并为每列/熊猫提取了这些特征。系列:
- 浮点数百分比:浮点值的百分比
- % int:整数值的百分比
- % 字符串:字符串值的百分比 %唯一字符串
- :唯一字符串值数/总数 %唯一整数
- :唯一整数值的数量/总数
- 平均数值(非数值被视为 0)
- 数值的STD偏差
并训练了一个模型,它可以很好地推断列类型,其中可能的输出值是:分类、有序、定量。
旁注:就数值数量有限的序列而言,似乎有趣的问题是确定分类与序数;如果一个变量被证明是定量的,那么认为它是有序的,对吗?预处理步骤无论如何都会以数字方式对序号值进行编码,而无需独热编码。
一个有趣的相关问题:给定一组列,你能判断它们是否已经是独热编码的吗?例如,在森林覆盖类型预测 kaggle 竞赛中,您将自动知道土壤类型是单个分类变量。
IMO 相反的策略,识别分类更好,因为它取决于数据的内容。从技术上讲,地址数据可以被认为是无序分类数据,但通常我不会这样使用它。
对于调查数据,一个想法是寻找李克特量表,例如 5-8 个值,要么是字符串(可能需要硬编码(和翻译)级别来查找"好"、"坏"、"。同意.","非常.*",...)或 0-8 范围内 + NA 的整数值。
国家和这样的事情也可能是可以识别的......
年龄组(".-.")也可能有效。
在看这个,认为分享我所拥有的东西可能很有用。这是建立在@Rishabh斯里瓦斯塔瓦的答案之上的。
import pandas as pd
def remove_cat_features(X, method='fraction_unique', cat_cols=None, min_fraction_unique=0.05):
"""Removes categorical features using a given method.
X: pd.DataFrame, dataframe to remove categorical features from."""
if method=='fraction_unique':
unique_fraction = X.apply(lambda col: len(pd.unique(col))/len(col))
reduced_X = X.loc[:, unique_fraction>min_fraction_unique]
if method=='named_columns':
non_cat_cols = [col not in cat_cols for col in X.columns]
reduced_X = X.loc[:, non_cat_cols]
return reduced_X
然后,您可以调用此函数,将 pandas df 作为X
,您可以删除命名的分类列,也可以选择删除具有少量唯一值(由 min_fraction_unique
指定)的列。