当前位置:

首页 > 编程开发 > Python处理非结构化CSV:字段对齐与清洗教程

Python处理非结构化CSV:字段对齐与清洗教程

本教程旨在解决CSV文件中字段长度不一致导致的数据错位问题。通过Python和Pandas库,我们将学习如何根据每行字段的数量对数据进行分组,并为每个分组创建独立的DataFrame。这种方法为后续的精细化数据清洗和分析奠定了基础,尤其适用于处理历史遗留或结构松散的数据集。

本文目录

    使用Python和Pandas处理非结构化CSV数据:字段对齐与初步清洗指南

    本教程旨在解决CSV文件中字段长度不一致导致的数据错位问题。通过Python和Pandas库,我们将学习如何根据每行字段的数量对数据进行分组,并为每个分组创建独立的DataFrame。这种方法为后续的精细化数据清洗和分析奠定了基础,尤其适用于处理历史遗留或结构松散的数据集。

    引言:CSV数据字段对齐的挑战

    在处理历史遗留或由不同系统导出的CSV数据时,经常会遇到数据结构不一致的问题。最常见的挑战之一是,同一文件中的不同行可能包含不同数量的字段,导致字段错位,使得数据难以直接用于分析。例如,某些行可能包含额外的描述性字段,而另一些行则没有,这使得传统的按列读取方式变得不可行。

    考虑以下示例数据,其中不同行的字段数量明显不同:

    30,1204,PO,71100,147130,I09,B10,OC,350,20105402
    31,1221,PO,70400,147170,I09,B10,OC,500,20105402
    32,1223,SI,70384,147122,I09,B10,OC,500,PN,3,BO,OI,20105402
    38,1307,SI,70379,146041,I09,B10,OC,500,21,BH,1,BO,195,40,SW,20105402
    49,1405,LD,2,70119,148280,I10,B10,OC,0000,20105403

    从上述数据可以看出,第一行和第二行有10个字段,而第三行有14个字段,第四行有17个字段,第五行又有11个字段。这种差异使得我们无法简单地将整个文件作为一个统一的表格来处理。

    核心策略:按行字段数量分组

    解决此类问题的有效初步方法是根据每行所包含的字段数量进行分组。其基本思想是:如果两行具有相同数量的字段,那么它们很可能遵循相同的结构模式,或者至少在字段数量上是一致的。通过将具有相同字段数量的行聚合在一起,我们可以为每种结构模式创建一个独立的子数据集,从而简化后续的清洗和分析工作。

    Python的Pandas库是处理此类结构化和半结构化数据的强大工具,它能够方便地将数据转换为DataFrame,并进行各种数据操作。

    Python实现:数据分组与DataFrame构建

    以下是使用Python和Pandas实现上述分组策略的步骤和示例代码:

    1. 准备数据 我们首先将示例数据存储在一个多行字符串中,以便于演示。在实际应用中,您可以从CSV文件中读取数据。

    2. 按行解析并分组 遍历每一行数据,使用逗号作为分隔符将其拆分为字段列表。然后,根据每个列表的长度(即字段数量)将其存储在一个字典中。字典的键是字段数量,值是包含所有具有该字段数量的行的列表。

    3. 为每个分组创建DataFrame 遍历字典中的每个分组,使用Pandas的DataFrame构造函数将该分组的数据转换为一个独立的DataFrame。

    from io import StringIO
    import pandas as pd
    
    # 示例数据,实际应用中可以从文件读取
    data = """
    30,1204,PO,71100,147130,I09,B10,OC,350,20105402
    31,1221,PO,70400,147170,I09,B10,OC,500,20105402
    32,1223,SI,70384,147122,I09,B10,OC,500,PN,3,BO,OI,20105402
    33,1224,SI,70392,147032,I09,B10,OC,500,PN,1,BO,OI,20105402
    34,1227,PO,70400,146430,I09,B10,PF,500,20105402
    35,1241,PO,71100,146420,I09,B10,PF,500,20105402
    36,1249,PO,71100,146000,I09,B10,SN,500,20105402
    37,1305,PO,70400,146000,I09,B10,OC,500,20105402
    38,1307,SI,70379,146041,I09,B10,OC,500,21,BH,1,BO,195,40,SW,20105402
    39,1312,SD,70372,146062,I09,B10,OC,500,20105402
    40,1332,SI,70334,146309,I09,B10,OC,500,PN,4,BO,OI,20105402
    41,1332,SI,70334,146309,I09,B10,OC,500,PN,5,BO,OI,20105403
    42,1333,SI,70333,146324,I09,B10,OC,500,PN,2,BO,OI,20105403
    43,1334,SI,70328,146348,I09,B10,OC,500,PN,1,BO,OI,20105403
    44,1335,SI,70326,146356,I09,B10,OC,500,PN,1,BO,OI,20105403
    45,1336,SI,70310,146424,I09,B10,OC,500,PN,1,BO,OI,20105403
    46,1338,SI,70302,146457,I10,B10,OC,500,PN,1,BO,OI,20105403
    47,1338,SI,70301,146464,I10,B10,OC,500,PN,1,BO,OI,20105403
    48,1340,SI,70295,146503,I10,B10,OC,500,PN,8,BO,OI,20105403
    49,1405,LD,2,70119,148280,I10,B10,OC,0000,20105403
    01,1024,LA,1R,70120,148280,B10,OC,0000,21105501
    02,1039,PO,70340,149400,I10,B10,OC,500,21105501
    03,1045,SI,70378,149025,I10,B07,PF,300,PN,17,BO,OI,21105501
    """
    
    # 用于存储按字段数量分组的数据
    all_data_by_length = {}
    
    # 逐行处理数据
    for line in map(str.strip, data.splitlines()): # 移除每行首尾空白字符
        if not line: # 跳过空行
            continue
        fields = line.split(",") # 按逗号分割字段
        field_count = len(fields)
    
        # 将行添加到对应字段数量的分组中
        all_data_by_length.setdefault(field_count, []).append(fields)
    
    # 为每个分组创建并打印DataFrame
    print("--- 分组后的DataFrames ---")
    for count, lines_in_group in all_data_by_length.items():
        print(f"数据行数: {len(lines_in_group)}, 字段数量: {count}")
        df = pd.DataFrame(lines_in_group)
        print(df)
        print("-" * 80)

    代码解析:

    • from io import StringIO: StringIO 模块允许我们将字符串当作文件来处理,方便 pd.read_csv 等函数使用,尽管在这个例子中我们直接处理字符串。
    • map(str.strip, data.splitlines()): data.splitlines() 将多行字符串分割成一个列表,其中每个元素是一行。map(str.strip, ...) 则对列表中的每一行应用 str.strip() 方法,移除行首尾的空白字符,包括换行符。
    • if not line: continue: 过滤掉可能存在的空行,避免处理空字符串。
    • line.split(","): 使用逗号作为分隔符将每行字符串拆分成字段列表。
    • all_data_by_length.setdefault(field_count, []).append(fields): 这是分组的核心逻辑。setdefault(key, default_value) 方法会检查字典中是否存在 key。如果存在,则返回其对应的值;如果不存在,则将 key 添加到字典中,并将其值设置为 default_value(在这里是一个空列表 []),然后返回这个 default_value。这样,我们就可以直接向返回的列表中添加当前行的字段列表 fields。
    • pd.DataFrame(lines_in_group): 将同一分组内的所有行列表转换为一个Pandas DataFrame。由于此时我们没有列名信息,Pandas会默认使用整数作为列索引(0, 1, 2...)。

    输出示例:

    运行上述代码,您将看到根据字段数量生成了多个独立的DataFrame,每个DataFrame都包含字段数量相同的行。例如,一个DataFrame可能包含所有10个字段的行,另一个包含所有14个字段的行,以此类推。

    --- 分组后的DataFrames ---
    数据行数: 9, 字段数量: 10
        0     1   2      3       4       5    6   7     8         9
    0  30  1204  PO  71100  147130     I09  B10  OC   350  20105402
    1  31  1221  PO  70400  147170     I09  B10  OC   500  20105402
    2  34  1227  PO  70400  146430     I09  B10  PF   500  20105402
    3  35  1241  PO  71100  146420     I09  B10  PF   500  20105402
    4  36  1249  PO  71100  146000     I09  B10  SN   500  20105402
    5  37  1305  PO  70400  146000     I09  B10  OC   500  20105402
    6  39  1312  SD  70372  146062     I09  B10  OC   500  20105402
    7  01  1024  LA     1R   70120  148280  B10  OC  0000  21105501
    8  02  1039  PO  70340  149400     I10  B10  OC   500  21105501
    --------------------------------------------------------------------------------
    数据行数: 12, 字段数量: 14
        0     1   2      3       4    5    6   7    8   9   10  11  12        13
    0   32  1223  SI  70384  147122  I09  B10  OC  500  PN   3  BO  OI  20105402
    1   33  1224  SI  70392  147032  I09  B10  OC  500  PN   1  BO  OI  20105402
    2   40  1332  SI  70334  146309  I09  B10  OC  500  PN   4  BO  OI  20105402
    3   41  1332  SI  70334  146309  I09  B10  OC  500  PN   5  BO  OI  20105403
    4   42  1333  SI  70333  146324  I09  B10  OC  500  PN   2  BO  OI  20105403
    5   43  1334  SI  70328  146348  I09  B10  OC  500  PN   1  BO  OI  20105403
    6   44  1335  SI  70326  146356  I09  B10  OC  500  PN   1  BO  OI  20105403
    7   45  1336  SI  70310  146424  I09  B10  OC  500  PN   1  BO  OI  20105403
    8   46  1338  SI  70302  146457  I10  B10  OC  500  PN   1  BO  OI  20105403
    9   47  1338  SI  70301  146464  I10  B10  OC  500  PN   1  BO  OI  20105403
    10  48  1340  SI  70295  146503  I10  B10  OC  500  PN   8  BO  OI  20105403
    11  03  1045  SI  70378  149025  I10  B07  PF  300  PN  17  BO  OI  21105501
    --------------------------------------------------------------------------------
    数据行数: 1, 字段数量: 17
        0     1   2      3       4    5    6   7    8   9   10 11  12   13  14  15        16
    0  38  1307  SI  70379  146041  I09  B10  OC  500  21  BH  1  BO  195  40  SW  20105402
    --------------------------------------------------------------------------------
    数据行数: 1, 字段数量: 11
        0     1   2  3      4       5    6    7   8     9         10
    0  49  1405  LD  2  70119  148280  I10  B10  OC  0000  20105403
    --------------------------------------------------------------------------------

    后续数据清洗与分析建议

    将数据按字段数量分组只是数据清洗的第一步。完成此步骤后,您将拥有多个结构相对一致的DataFrame。接下来的工作需要结合对数据内容的理解(领域知识)来进一步处理:

    1. 确定列名: 对于每个DataFrame,根据其字段数量和内容,赋予有意义的列名。这通常需要手动检查数据样本,识别每个位置的字段含义。例如,一个10字段的DataFrame可能代表一种订单类型,而14字段的DataFrame可能代表另一种包含更多详情的订单类型。
    2. 数据类型转换: 将字符串类型的字段转换为正确的数值、日期或布尔类型。
    3. 处理缺失值: 识别并处理每个DataFrame中的缺失值。不同的数据模式可能需要不同的缺失值处理策略(例如,填充平均值、中位数,或删除行)。
    4. 合并与对齐: 如果不同的DataFrame代表同一实体(例如,都是订单数据但结构不同),您可能需要根据它们的共同字段(如订单ID)进行合并。这可能涉及到识别不同DataFrame中相同意义的字段,然后进行重命名和合并操作,必要时填充缺失的字段。
    5. 正则匹配与模式识别: 对于那些在同一列中包含多种信息或格式不规则的字段,可以使用正则表达式来提取、清洗或标准化数据。
    6. 异常值检测: 在每个结构一致的DataFrame中,更容易发现并处理异常值。

    注意事项与最佳实践

    • 领域知识至关重要: 没有任何自动化工具可以完全替代对数据含义的理解。在清洗非结构化数据时,了解每个字段的预期内容和业务逻辑是成功的关键。
    • 迭代式清洗: 数据清洗通常是一个迭代过程。您可能需要多次运行代码,根据中间结果调整清洗策略。
    • 处理大规模数据: 对于非常大的CSV文件,一次性将所有数据加载到内存中可能不可行。在这种情况下,可以考虑使用Pandas的read_csv函数的chunksize参数分块读取,或者使用Dask等工具进行并行处理。
    • 文档记录: 记录您的清洗步骤和决策,这对于未来的维护和团队协作至关重要。

    总结

    通过将CSV数据按行字段数量进行分组,我们能够有效地将非结构化、字段错位的数据分解为多个结构相对一致的子数据集。这种初步的清洗步骤为后续的精细化处理奠定了坚实的基础,使得利用Pandas进行进一步的数据类型转换、缺失值处理和业务逻辑分析成为可能。请记住,数据清洗是一个结合技术工具和领域知识的艺术,持续的探索和迭代是成功的关键。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    GitHub Actions重跑失败作业会使用最新代码吗
    GitHub Actions重跑失败作业会使用最新代码吗

    解释已有运行重跑的提交和权限边界,给出确认、失败作业重跑及结果核对命令,区分漏触发事件。

    chat-demo v0.1.1怎么本地运行并理解DeepSeek历史数据边界
    chat-demo v0.1.1怎么本地运行并理解DeepSeek历史数据边界

    chat-demo v0.1.1可以作为静态聊天客户端在本地运行,但模型、搜索、文件和语音能力仍由DeepSeek API提供。源码运行环境为Node.js 22.12及以上、Git与pnpm。Demo版本号不等于应用API版本;这套应用API未单独标版本,默认聊天模型ID是deepseek-flash。

    GitHub Copilot CLI v1.0.111的用量图与上下文比例应该怎样理解
    GitHub Copilot CLI v1.0.111的用量图与上下文比例应该怎样理解

    理解GitHub Copilot CLI v1.0.111的高级请求百分比、用户提示活动图与实际路由模型窗口,区分显示口径和任务状态。

    n8n 2.47.6、2.47.7、2.48.3 Beta、2.48.4 Beta、3.2.2预发布与1.123.96适用哪些安全修复?
    n8n 2.47.6、2.47.7、2.48.3 Beta、2.48.4 Beta、3.2.2预发布与1.123.96适用哪些安全修复?

    按维护分支、利用权限与节点类型对应四项修复,区分正式补丁、Beta和临时缓解的适用边界。

    GitHub合并故障的已缓解、监控与已解决有什么不同
    GitHub合并故障的已缓解、监控与已解决有什么不同

    GitHub合并故障中的“已缓解并监控”和“已解决”不能互换。前者表示影响已经采取措施缓解,仍在观察稳定性;后者是供应商正式结束这场事故的状态。11月13日的Pull Requests合并超时事件先进入监控,随后于北京时间11月14日02:29标记为已解决。

    llama.cpp v1.0.0的网页聊天分组与Markdown编辑适合哪些场景
    llama.cpp v1.0.0的网页聊天分组与Markdown编辑适合哪些场景

    llama.cpp v1.0.0改善聊天组织、长消息编辑和附件预览;界面变化与底层API迁移、缓存及访问边界需要分别理解。

    Postman 12.36.4 更新后仍报错,怎么判断是哪一层的问题
    Postman 12.36.4 更新后仍报错,怎么判断是哪一层的问题

    Postman 12.36.4 更新后仍有异常时,可按应用、API请求和平台服务区分问题范围,避免把补丁版本当作故障原因。

    n8n 2.47.6、2.48.3 Beta与1.123.96适合哪些部署环境?
    n8n 2.47.6、2.48.3 Beta与1.123.96适合哪些部署环境?

    按正式、预发布和1.x维护渠道对应补丁,再结合Redis、Agent端点和Pinecone索引判断适用范围。

    Codex CLI 0.169.0与0.171.0-alpha.2怎样选择,终端工作区适合哪些任务
    Codex CLI 0.169.0与0.171.0-alpha.2怎样选择,终端工作区适合哪些任务

    Codex CLI 0.169.0提供有明确说明的终端工作区能力;0.171.0-alpha.2为预发布,当前没有功能清单,选用时应分开评估。

    llama.cpp b12345的Hexagon后端支持哪些Q5量化格式?
    llama.cpp b12345的Hexagon后端支持哪些Q5量化格式?

    llama.cpp b12345的预发布构建为Hexagon HTP后端增加Q5_0和Q5_1支持。选择模型时需要核对完整量化名称及实际运行后端,不能只看到“Q5”就视为同一种格式。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。