检测 pandas.DataFrame 中的列是不是是分类的有啥好的启发式方法?

Posted

技术标签:

【中文标题】检测 pandas.DataFrame 中的列是不是是分类的有啥好的启发式方法?【英文标题】:What is a good heuristic to detect if a column in a pandas.DataFrame is categorical?检测 pandas.DataFrame 中的列是否是分类的有什么好的启发式方法? 【发布时间】:2016-06-20 00:14:19 【问题描述】:

我一直在开发一种自动预处理 pandas.DataFrame 格式数据的工具。在这个预处理步骤中,我想以不同的方式处理连续数据和分类数据。特别是,我希望能够将 OneHotEncoder 应用到分类数据。

现在,假设我们提供了一个 pandas.DataFrame 并且没有关于 DataFrame 中数据的其他信息。确定 pandas.DataFrame 中的列是否是分类的有什么好的启发式方法?

我最初的想法是:

1) 如果列中有字符串(例如,列数据类型为object),则该列很可能包含分类数据

2) 如果列中某些百分比的值是唯一的(例如 >=20%),则该列很可能包含连续数据

我发现1) 工作正常,但2) 并没有很好地完成。我需要更好的启发式方法。你会如何解决这个问题?

编辑:有人要求我解释为什么2) 不能正常工作。在某些测试案例中,我们在列中仍然有连续值,但列中没有很多唯一值。在这种情况下,2) 中的启发式显然失败了。还有一个问题是,我们有一个分类列,其中包含许多独特的值,例如泰坦尼克号数据集中的乘客姓名。存在相同的列类型错误分类问题。

【问题讨论】:

我相信这个问题几乎是完全不确定的。世界上所有数据集的分布是什么?例如,对于邮政服务或电话簿,您的规则 1 非常失败。 尝试Benford's law 从分类数据中辨别数字数据。 @Barmaley.exe 你能详细说明一下这个想法吗? @RandyOlson,好吧,我不确定它是否有效,但这个想法是“自然”数字倾向于遵守本福德定律,而分类值 (ids) 则没有to:确实,您可以任意排列 id,并且什么都不会改变。因此,您可以尝试从该定律中得出某种测试。 您对此有何改进? 【参考方案1】:

我一直在看这个,认为分享我所拥有的可能有用。这建立在@Rishabh Srivastava 的回答之上。

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 指定)的列。

【讨论】:

我应该补充一点:我还为我的数据集(材料的物理特性)尝试了 Benfords 定律判别器,但没有成功。【参考方案2】:

您可以定义哪些数据类型算作数字,然后排除相应的变量

如果初始数据帧是 df:

numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
dataframe = df.select_dtypes(exclude=numerics)

【讨论】:

感觉上面是一个很棒的策略。这就是实施def is_numeric(input_frame:pd.core.frame.DataFrame, clmn_names:Optional[list]=None): numerics_types = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64'] return [True if input_frame[clmn_names].dtypes.name in numerics_types else False] 的方式【参考方案3】:

这里有几种方法:

    求唯一值的数量与唯一值总数的比率。类似于以下内容

    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) 会更好,其中少数类别变量的频率较高,而大量类别变量的频率较低。

【讨论】:

请问方法 2 是否缺少求和运算?当我在我的代码上对其进行测试时,它似乎会返回一系列布尔值,每个布尔值都表示该特定唯一值是否具有相对频率 > 阈值。是否打算将 top_n 行的总相对频率相加? (1.*dff['test'].value_counts(normalize=True).head(3)).sum() &gt; 0.8 @AiRiFiEd:是的 - 它缺少求和运算。非常感谢您指出这一点。已更新答案。 感谢您更新答案,尽管这是一个非常古老的帖子!我可以根据您的经验检查一下,作为方法 2 的阈值的合理启发式方法是什么?例如,我正在考虑将 top_n 分配为唯一值总数的 x 百分比(从而导致类似于“20% 的唯一值占所有值的 80%”-top_n = round(0.8 * (1.*dff[var].value_counts(normalize=True).head(3)).shape[0])【参考方案4】:

IMO 相反的策略,识别分类更好,因为它取决于数据的内容。从技术上讲,地址数据可以被认为是无序的分类数据,但通常我不会那样使用它。

对于调查数据,一个想法是寻找李克特量表,例如5-8 个值,无论是字符串(可能需要硬编码(和翻译)级别来查找“好”、“坏”、“.agree.”、“very .*”、.. .) 或 0-8 范围内的 int 值 + NA。

国家和类似的东西也可能是可识别的......

年龄组(“.-.”)也可能有效。

【讨论】:

【参考方案5】:

我一直在考虑一个类似的问题,我考虑得越多,似乎这本身就是一个分类问题,可以从训练模型中受益。

我敢打赌,如果您检查了一堆数据集并为每一列/pandas.Series 提取了这些特征:

% floats:浮动值的百分比 % int:整数值的百分比 % 字符串:字符串值的百分比 % 唯一字符串:唯一字符串值的数量/总数 % 唯一整数:唯一整数值​​的数量/总数 平均数值(非数值被认为是0) 数值的标准偏差

并训练了一个模型,它可以很好地推断列类型,其中可能的输出值为:分类、有序、定量。

旁注:就数值数量有限的系列而言,有趣的问题似乎是确定分类与序数;如果一个变量被证明是定量的,那么认为一个变量是序数并没有什么坏处吗?无论如何,预处理步骤都会以数字方式对序数值进行编码,而无需一次性编码。

一个有趣的相关问题:给定一组列,你能判断它们是否已经被单热编码吗?例如在森林覆盖类型预测 kaggle 比赛中,你会自动知道土壤类型是一个单一的分类变量。

【讨论】:

> 一个有趣的相关问题:给定一组列,你能判断它们是否已经被单热编码吗? ||这将需要柱状元数据。见github.com/pandas-dev/pandas/issues/3402【参考方案6】:

我认为这里真正的问题是,您是想偶尔打扰用户还是偶尔默默地失败。

如果您不介意打扰用户,也许可以检测歧义并引发错误。

如果您不介意默默地失败,那么您的启发式方法是可以的。我不认为你会发现任何明显更好的东西。我想如果你真的想的话,你可以把它变成一个学习问题。下载一堆数据集,假设它们共同代表了世界上所有数据集,并根据每个数据集/列的特征进行训练,以预测分类与连续。

当然,最终没有什么是完美的。例如。 [1, 8, 22, 8, 9, 8] 列是指一天中的几个小时还是指犬种?

【讨论】:

【参考方案7】:

有很多地方可以“窃取”可以转换为“数字”的格式定义。 ##,#e-# 将是这样的格式之一,只是为了说明。也许你可以找到一个图书馆来做这件事。 我尝试先将所有内容都转换为数字,然后剩下的,好吧,除了保持它们分类之外别无他法。

【讨论】:

我喜欢这个主意。有人知道这样的图书馆吗? 如果您喜欢这个想法,请考虑对答案进行投票,这样其他人会更容易看到它,他们可能会推荐该库。

以上是关于检测 pandas.DataFrame 中的列是不是是分类的有啥好的启发式方法?的主要内容,如果未能解决你的问题,请参考以下文章

迭代 Pandas Dataframe 中的列和行

从 pandas DataFrame 中的列中提取 JSON 数据

根据 Pandas Dataframe 中的时间戳列过滤给定的列(计数)

如何使用字典键和值重命名 pandas DataFrame 中的列?

使用包含嵌套 JSON 字符串的一列解析 Pandas DataFrame 中的列

pandas dataframe中的列进行重新排序倒排正排自定义排序详解及实践