广告

Pandas教程:高效实现DataFrame各列唯一值计数并生成嵌套字典的实战方法(含代码示例)

1. 目标与应用场景

1.1 需求背景与场景分析

在数据分析流程中,Pandas对 DataFrame 的列级统计是最常见的任务之一。快速统计每一列的唯一值及其出现次数,可以帮助你理解数据分布、发现异常值以及为后续特征工程提供依据。本文围绕一个实战目标展开:在不逐列手写循环的情况下,建立一个通用的嵌套字典结构,把每一列的唯一值及对应计数组织起来,方便后续查询与输出。

以往的做法可能只统计单列的唯一值,但在实际项目中,往往需要对多个列同时进行统计,并聚合成一份易于查询的结果。本文提供的嵌套字典结构恰好满足这个需求:{列名: {值: 计数, ...}, ...},可直接转为 JSON、Excel 或数据库字段,极大提升数据分析的效率。

1.2 目标输出的嵌套结构

目标输出的嵌套结构大体如下:每一列映射到一个字典,该字典以唯一值为键,计数为值,形成形如 {列名: {唯一值: 出现次数, ...}, ...} 的结构。此结构在数据探索、异常值定位、以及特征工程阶段都非常实用。

在实现时,可以灵活选择是否包含 NaN 的计数。dropna 参数 的设置会直接影响结果的键集合与统计口径,因此在设计阶段就要明确需求。

2. 核心实现思路与数据结构

2.1 字典嵌套的设计要点

核心思想是将统计任务向量化,避免逐行遍历带来的性能开销。通过对每列调用 value_counts,可以得到该列内各唯一值的计数,再将结果转为字典并聚合成嵌套结构。

为提升灵活性,可以把 NaN 的统计纳入考虑。dropna=False 可以将 NaN 作为一个具体键纳入统计,而没有掉落。另一方面,若你只关心实际数值/文本值,则保持 dropna=True 即可,结果会更干净。

2.2 数据结构与内存注意点

嵌套字典在内存中的占用随数据规模增长而显著增加,因此在大数据场景下,应优先考虑先统计、再按需导出。以列为单位的统计结果,逐列构建字典,可以在遇到超大列时进行分块处理与分阶段输出。

此外,若目标是输出 JSON 或写入数据库,使用简洁的字典结构有利于序列化与网络传输,减少额外的转换成本。

3. 单列计数的高效实现方法

3.1 方法A:直接使用 value_counts 构建嵌套字典

第一种直观做法是对每一列调用 value_counts,再将结果转换为字典,最后汇总为一个顶层字典。该方法简单、直接,且对大多数数据集表现良好。

关键点:默认情况下 value_counts 会忽略 NaN 值,若需要纳入 NaN,请显式设置 dropna=False。

# 示例:对 DataFrame 的每一列,统计唯一值及其计数,输出嵌套字典
import pandas as pd

# 示例数据
df = pd.DataFrame({
    'City': ['NY','SF','NY','SF','LA'],
    'Product': ['Phone','Phone','Laptop','Phone','Laptop'],
    'Sales': [100, 150, 120, 130, 80]
})

# 构建嵌套字典:{列名: {唯一值: 计数}}
counts_per_column = {col: df[col].value_counts(dropna=False).to_dict() for col in df.columns}
print(counts_per_column)

示例输出类似如下结构:{ 'City': {'NY': 2, 'SF': 2, 'LA': 1}, 'Product': {'Phone': 3, 'Laptop': 2}, 'Sales': {100: 1, 150: 1, 120: 1, 130: 1, 80: 1} }

3.2 方法B:封装为可复用的函数

为了提高复用性,可以将统计逻辑封装成一个小函数,便于在不同的数据集上重复使用。函数返回的仍然是嵌套字典,便于后续序列化和输出。

设计要点:输入 DataFrame、可选参数控制 dropna、以及是否对结果进行排序或过滤。

def nested_unique_counts(df, dropna=False, sort_counts=False):
    """
    返回一个嵌套字典:{列名: {值: 计数, ...}, ...}
    """
    result = {col: df[col].value_counts(dropna=dropna).to_dict() for col in df.columns}
    if sort_counts:
        # 按计数排序(从大到小)
        for col in result:
            result[col] = dict(sorted(result[col].items(), key=lambda kv: kv[1], reverse=True))
    return result

# 使用示例
counts = nested_unique_counts(df, dropna=False, sort_counts=True)
print(counts)

4. 多列并行处理策略与细化实现

4.1 使用简洁的字典推导实现并行风格

虽然 Python 的原生并行性在 GIL 下对 CPU 密集型任务帮助有限,但 I/O 密集型或对 DataFrame 列进行独立统计时,分块或分列并行处理的思路依旧有益。在纯 Python 层面,我们可以通过列表/字典推导实现较为简洁的并行风格,逻辑清晰、可维护。

以下思路强调结构清晰:对每一列独立统计,再将结果合并成一份统一的嵌套字典。若要进一步提升吞吐,可结合 multiprocessing/pool 或分布式框架,但对多数场景而言,简单的集合推导已经足够高效。

4.2 处理缺失值策略与计数口径的统一

在多列同时统计时,统一的缺失值口径非常重要。请在调用 value_counts 时明确 dropna 的取值,以便得到一致的键集合。若你在后续环节需要对 NaN 单独分析,可以在结果中保留 NaN 这一键。

此外,若要对结果进行排序以便于查看,对每列的计数字典进行排序是一个常见需求,便于快速定位高频值。

5. 实践中的注意事项与性能优化

5.1 何时需要逐列分步计算

对极大数据集,单列的 value_counts 可能对内存产生短暂压力。分步处理、逐列统计并逐步输出,可以降低峰值内存消耗,特别是在你需要将结果写入磁盘的场景。

如果你只需要最终的嵌套字典作为中间结果,避免额外的副本拷贝也能提升性能。尽量使用就地操作和就地字典构建。

5.2 序列化与导出建议

将嵌套字典导出为 JSON、CSV 或数据库字段时,确保键与数据类型的兼容性,特别是当唯一值包含非字符串类型(如数值、日期)时。对于 JSON,建议使用 ensure_ascii=False 以保留中文或其他字符。

6. 完整实战案例:从数据读取到嵌套字典的生成

6.1 从 CSV 数据到嵌套字典的完整流程

在实际项目中,数据通常来自文件或数据库。该流程演示了从读取数据到生成嵌套字典的完整步骤,便于你在笔记本或生产环境中直接落地执行。

步骤要点:读取数据、对每列执行统计、汇总为嵌套字典、并可选地导出为 JSON。

import pandas as pd
import json

# 1) 读取数据
# 这里假设数据来自一个 CSV 文件,请将路径替换为你的实际路径
df = pd.read_csv('data.csv')

# 2) 统计并生成嵌套字典
counts_per_column = {col: df[col].value_counts(dropna=False).to_dict() for col in df.columns}

# 3) 导出为 JSON 字符串(或写入文件)
json_str = json.dumps(counts_per_column, ensure_ascii=False, indent=2)
print(json_str)

# 4) 若需要将结果写回到磁盘/数据库,可按需追加实现

6.2 常见变体与扩展思路

如果你希望进一步扩展功能,可以在原有嵌套字典的基础上,按列合并统计信息、输出其他聚合结果,如每列的唯一值总数、Top N 常见值、以及缺失值计数等。

例如,附加一个统计摘要:每列的唯一值数量与缺失计数,可以作为数据清洗阶段的快速诊断工具。

广告

后端开发标签