清理并高效读取含非结构化文本的CSV文件

清理并高效读取含非结构化文本的CSV文件

本教程旨在解决读取包含非结构化文本的CSV文件的问题。面对文件开头和结尾的冗余信息,我们将探讨多种高效策略,包括基于关键词定位头部并跳过指定行,以及逐行扫描文件直至识别到数据起始点。通过结合Pandas库的强大功能,我们将实现精确的数据提取和清洗,确保仅读取所需的结构化数据,适用于处理大量类似格式的文件。

在实际数据处理中,我们经常会遇到csv文件并非纯粹的逗号分隔值数据,而是在文件开头或结尾包含一些非结构化的元数据、报告标题或脚注。对于少量文件,手动清理尚可接受,但当需要处理成千上万个此类文件时,自动化清理和读取就变得至关重要。本文将介绍几种利用python和pandas库来应对这一挑战的有效方法。

1. 准备示例数据

为了演示这些方法,我们首先创建一个模拟包含非结构化文本的CSV文件 students.csv:

# 创建一个示例文件sample_data = """SAMPLE FILE LTDSTUDENT NUMBERSINFO OF ALL STUDENTS No :  from 27-Mar-2023 00:00:00 to 04-Apr-2023 00:00:00 and  from 05-Oct-2023 00:00:00 to 13-Oct-2023 00:00:00Student,id,add,div,rankABC,12,USA,A,1DEF,13,IND,C,2XYZ,14,UK,E,3PQR,15,DE,F,4 This is System generated report, and needs no signature. 14-Oct-2023 18:14:12"""with open('students.csv', 'w') as f:    f.write(sample_data)print("示例文件 students.csv 已创建。")

我们的目标是从这个文件中准确地读取以下数据:

Student,id,add,div,rankABC,12,USA,A,1DEF,13,IND,C,2XYZ,14,UK,E,3PQR,15,DE,F,4

2. 方法一:基于关键词定位并跳过指定行

这种方法的核心思想是,首先找到包含实际数据头部的行(例如,通过匹配列名),然后计算出在该行之前有多少行需要跳过,最后使用 pd.read_csv 的 skiprows 参数进行读取。

2.1 实现步骤

定位头部行: 编写一个函数,逐行读取文件,直到找到包含所有列名(或其中一个关键列名)的行。计算跳过行数: 记录从文件开头到头部行之间的行数。使用 pd.read_csv 读取: 将计算出的行数传递给 skiprows 参数。后处理: 由于文件末尾可能仍有冗余文本或空行,使用 dropna() 清理。

2.2 示例代码

import pandas as pddef get_rows_to_skip(file_name, header_keyword):    """    计算从文件开头到包含指定关键词的行之间的行数。    """    rows = 0    with open(file_name, 'r') as file:        while True:            line = file.readline()            if not line: # 文件结束                return -1 # 表示未找到关键词            if header_keyword in line:                return rows            rows += 1def read_cleaned_csv_by_skiprows(file_name, header_keyword, expected_columns):    """    通过跳过指定行数来读取清理后的CSV文件。    """    skip_rows = get_rows_to_skip(file_name, header_keyword)    if skip_rows == -1:        print(f"错误:未在文件 '{file_name}' 中找到关键词 '{header_keyword}'。")        return pd.DataFrame()    # 读取CSV,跳过前导行    df = pd.read_csv(file_name, skiprows=skip_rows)    # 清理数据:移除全为空的行,这通常发生在文件末尾的冗余文本被读入后    # 确保列名是预期的,并且数据行不包含NaN    # 检查第一行是否是预期的列名,如果不是,则可能需要进一步处理    if not all(col in df.columns for col in expected_columns):        print(f"警告:读取的列名与预期不符。实际列名:{df.columns.tolist()}")        # 尝试将第一行作为列名并重新读取,或者进行更复杂的清洗        # 考虑到我们的header_keyword是'rank',它在列名中,所以pd.read_csv会正确识别头部。        pass    # 移除所有列都为NaN的行,这有助于清理文件末尾的空行或无关文本    df = df.dropna(how='all')    # 进一步清理:如果某些列被读取为NaN,但它们应该是数据,这通常意味着文件末尾有额外文本    # 我们可以根据关键列(如'rank')来过滤掉无效数据行    if 'rank' in df.columns:        df = df[df['rank'].notna()]    return df# 预期列名,用于验证和清理expected_columns = ['Student', 'id', 'add', 'div', 'rank']df_skiprows = read_cleaned_csv_by_skiprows('students.csv', 'rank', expected_columns)print("方法一:基于关键词跳过行读取结果:")print(df_skiprows)print("-" * 30)

2.3 注意事项

此方法依赖于 header_keyword 的唯一性和稳定性。如果关键词在非数据行中也出现,或者数据头部行结构不稳定,可能会导致错误。skiprows 参数只能跳过文件开头的行,对于文件末尾的冗余文本,需要额外的 dropna() 等后处理步骤。pd.read_csv 会尝试自动识别列名。如果 header_keyword 是列名的一部分,通常能正确识别。

3. 方法二:逐行读取定位头部并传递文件句柄(推荐)

这种方法更加灵活和健壮,尤其适用于头部行位置不固定,但其内容结构相对稳定的情况。它通过Python的文件操作逐行读取,直到找到真正的CSV头部,然后将文件句柄的剩余部分直接传递给 pd.read_csv。

3.1 实现步骤

打开文件: 使用 with open(…) 打开文件。逐行扫描: 循环读取文件的每一行,直到找到符合头部特征的行(例如,以特定字符串开头,或包含所有预期的列名)。解析头部: 从找到的头部行中提取列名。传递文件句柄: 将当前文件句柄(它已定位在头部行之后)传递给 pd.read_csv。指定列名和清理: 使用解析出的列名作为 names 参数,并使用 dropna() 清理可能存在的空行或文件末尾的冗余数据。

3.2 示例代码

import pandas as pddef read_cleaned_csv_by_line_scan(file_name, header_start_string, expected_columns):    """    通过逐行扫描定位头部,然后读取清理后的CSV文件。    """    with open(file_name, 'r') as file:        header_line = None        # 逐行读取直到找到头部行        for line in file:            if line.strip().startswith(header_start_string):                header_line = line.strip()                break        if header_line is None:            print(f"错误:未在文件 '{file_name}' 中找到以 '{header_start_string}' 开头的头部行。")            return pd.DataFrame()        # 从找到的头部行解析列名        column_names = header_line.split(',')        # 将文件句柄的剩余部分传递给pd.read_csv        # 使用 names 参数指定列名,因为我们已经读取了头部行        df = pd.read_csv(file, names=column_names)        # 清理数据:移除所有列都为NaN的行,这有助于清理文件末尾的空行或无关文本        df = df.dropna(how='all')        # 进一步清理:如果某些列被读取为NaN,但它们应该是数据,这通常意味着文件末尾有额外文本        if 'rank' in df.columns:            df = df[df['rank'].notna()]        return df# 使用 'Student' 作为头部行的起始字符串df_line_scan = read_cleaned_csv_by_line_scan('students.csv', 'Student', expected_columns)print("方法二:逐行扫描定位头部读取结果:")print(df_line_scan)print("-" * 30)

3.3 优点与注意事项

优点: 这种方法对文件头部冗余行的数量不敏感,只要能准确识别头部行即可。对于非常大的文件,它避免了一次性加载整个文件到内存,效率更高。灵活性: header_start_string 可以是更复杂的条件,例如检查是否包含所有 expected_columns 中的列名。names 参数: 由于我们手动读取了头部行,pd.read_csv 应该使用 names 参数来明确指定列名,而不是让它尝试从文件中读取。dropna(how=’all’): 这是清理文件末尾空行或无关文本的有效方式。如果文件末尾的文本不是完全空行,可能需要更精确的过滤。

4. 方法三:全文件读取与后处理(通用但可能效率低)

这种方法将整个文件内容作为字符串读取,然后进行分割、清洗和转换为DataFrame。它更通用,可以处理更复杂的非标准格式,但对于超大文件可能效率较低,因为它需要将整个文件内容加载到内存中。

4.1 实现步骤

读取整个文件: 将整个文件内容读取为一个字符串。按行分割: 将字符串按换行符分割成行的列表。转换为DataFrame: 将行的列表转换为单列的DataFrame。分割列并清洗: 使用逗号分割列,并删除包含NaN的行。设置列名: 手动将第一行数据设置为列名。

4.2 示例代码

import pandas as pddef read_cleaned_csv_by_full_read(file_name):    """    将整个文件读取为字符串,然后进行分割和清洗。    """    with open(file_name, 'r') as file:        # 将整个文件读取为字符串,然后按换行符分割成行        df_raw = pd.DataFrame(file.read().split('n'))    # 将单列DataFrame的每一行按逗号分割成多列    # dropna() 用于移除文件开头和结尾的非CSV行,以及可能存在的空行    df = df_raw[0].str.split(',', expand=True).dropna()    # 将第一行(此时应该是实际的CSV头部)设置为列名    # 并移除原始的第一行(因为现在它是列名)    df.columns = df.iloc[0].values    df = df[1:].reset_index(drop=True)    # 再次清理,确保数据行中没有NaN    df = df.dropna(how='any')    return dfdf_full_read = read_cleaned_csv_by_full_read('students.csv')print("方法三:全文件读取与后处理读取结果:")print(df_full_read)print("-" * 30)

4.3 优点与注意事项

优点: 这种方法非常灵活,可以处理各种非标准格式,只要能通过字符串操作进行解析。缺点: 对于非常大的文件,一次性将所有内容加载到内存中可能导致性能问题或内存溢出。复杂性: 需要更多手动的数据清洗和列名设置步骤,可能不如 pd.read_csv 直接处理文件句柄那么简洁。

5. 总结与最佳实践

在处理包含非结构化文本的CSV文件时,选择合适的方法取决于文件的具体结构、大小和性能要求:

对于文件头部冗余行数不固定,但头部行内容相对稳定的情况(推荐):方法二(逐行读取定位头部并传递文件句柄) 是最推荐的方案。它结合了Python文件操作的灵活性和Pandas的强大读取能力,既高效又健壮。对于文件头部冗余行数相对固定,或可以通过一个关键词准确识别头部行的情况:方法一(基于关键词定位并跳过指定行) 是一个简单有效的选择。对于文件结构极其复杂,或者需要对文件内容进行更细粒度的字符串操作的情况:方法三(全文件读取与后处理) 提供了最大的灵活性,但应注意其潜在的性能开销。

通用注意事项:

错误处理: 在实际应用中,务必添加文件不存在、关键词未找到等异常处理逻辑。模式匹配: 如果头部识别逻辑非常复杂,可以考虑使用正则表达式来匹配头部行。数据类型: 在读取后,通常需要检查并转换DataFrame中列的数据类型,因为 pd.read_csv 可能会将数字列识别为字符串。dropna() 的使用: 根据实际情况选择 how=’any’(删除包含任何NaN的行)或 how=’all’(删除所有值为NaN的行)。

通过这些方法,您可以有效地自动化处理大量包含非结构化文本的CSV文件,从而节省时间和精力,确保数据处理流程的准确性和效率。

以上就是清理并高效读取含非结构化文本的CSV文件的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1371929.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 11:52:52
下一篇 2025年12月14日 11:53:07

相关推荐

  • PyTorch安装故障排除:解决卡顿与“幽灵”安装问题

    本文旨在解决PyTorch安装过程中常见的卡顿、系统冻结及无法卸载等疑难杂症。我们将探讨磁盘空间不足、安装中断等常见原因,并提供一套系统的故障排除方案,包括确保充足存储、尝试不同CUDA版本,以及一个鲜为人知的“Tab+Enter”组合键技巧,帮助用户成功完成PyTorch的安装与配置。 PyTor…

    好文分享 2025年12月14日
    000
  • 深入解析Confluence页面数据提取:API优先,数据库直连为辅

    本文旨在探讨如何从Confluence页面高效提取数据,特别是表格格式内容。我们主要介绍两种策略:推荐使用的Confluence REST API,它适用于大多数场景且易于实现;以及针对特定自托管环境和极致性能需求下考虑的数据库直连方式。文章将详细阐述两种方法的优缺点、适用场景,并提供API方式的P…

    2025年12月14日
    000
  • 深入理解Python中[1:]、%a格式化与字节求和的用法

    本文深入解析一段Python代码,详细阐述了如何使用open(0)读取标准输入、[1:]进行列表切片以跳过首行、:=赋值表达式,以及b’%a’%s将字符串转换为其ASCII字节表示。通过对字节序列求和并进行模运算,本文揭示了该代码的工作原理,旨在帮助读者理解Python中输入…

    2025年12月14日
    000
  • Python怎么调用父类的方法_Python中父类方法的调用技巧

    Python中调用父类方法推荐使用super(),因其遵循MRO顺序,在多重继承中能确保方法正确且仅执行一次;而直接通过父类名调用易导致重复执行、跳过中间类等问题,代码脆弱且难维护。super()不仅适用于__init__,还可用于重写普通方法、实现Mixin组合、资源管理等场景,提升代码的可扩展性…

    2025年12月14日
    000
  • Confluence数据提取策略:API与数据库直连对比解析

    本文深入探讨了从Confluence页面(特别是表格数据)提取信息的两种主要策略:通过Confluence API进行访问和直接连接Confluence后端数据库。文章分析了两种方法的优缺点、适用场景及技术挑战,强调API是更推荐且简便的方案,而数据库直连则适用于特定高性能需求但技术门槛较高的场景,…

    2025年12月14日
    000
  • PyTorch安装故障排除指南:从空间不足到卡顿冻结的全面解决方案

    本教程旨在解决PyTorch安装过程中常见的各类问题,包括磁盘空间不足、安装中断、系统冻结以及安装过程卡顿等。我们将提供从环境准备、版本选择到应对安装卡顿的实战技巧,特别是针对安装冻结的特殊处理方法,确保用户能够顺利完成PyTorch的部署。 1. PyTorch安装常见挑战概述 pytorch作为…

    2025年12月14日
    000
  • 从Confluence页面高效提取数据:API与数据库直连策略解析

    本文旨在探讨从Confluence页面提取数据的两种主要策略:优先推荐使用Confluence API,它适用于大多数场景,尤其是在云端或追求开发简便性的情况下。对于自托管Confluence且有极致性能需求的用户,文章也介绍了直接连接后端数据库的方法,并强调了其固有的复杂性、技术要求和潜在风险,建…

    2025年12月14日
    000
  • FastAPI大文件高效下载实践:告别内存溢出,巧用FileResponse

    本文旨在解决FastAPI在分发大文件时因将整个文件加载到内存而导致的内存溢出问题。通过分析传统StreamingResponse与io.BytesIO(file.read())结合的弊端,我们提出并详细演示了使用FileResponse这一高效、低内存占用的解决方案,确保即使是超大文件也能流畅、稳…

    2025年12月14日
    000
  • python如何实现一个装饰器_python装饰器原理与实现方法详解

    Python装饰器利用函数为一等公民和闭包特性,通过@语法为函数添加功能而不修改其代码。如log_calls装饰器可记录函数调用日志,核心是外部函数返回嵌套的wrapper函数,wrapper保留对原函数的引用并扩展行为。functools.wraps确保被装饰函数的元信息不变。带参数的装饰器需多一…

    2025年12月14日
    000
  • python中global关键字怎么使用_Python global关键字修改全局变量

    global关键字用于在函数内修改全局变量,避免创建局部副本;nonlocal则用于修改嵌套函数中外层函数的变量,二者作用域不同:global指向模块级全局变量,nonlocal指向最近的非全局封闭作用域。过度使用global会降低代码可读性、引发副作用、增加耦合度,并在并发环境下导致竞态条件,应优…

    2025年12月14日
    000
  • python如何实现一个简单的web服务器_python搭建Web服务器的详细教程

    答案:Python可通过http.server模块快速搭建Web服务器,用于文件共享或开发调试;也可用socket模块从零实现HTTP请求处理,理解底层通信机制。 在Python中实现一个简单的Web服务器,核心在于利用其内置的 http.server 模块,或者更底层地,通过 socket 模块来…

    2025年12月14日 好文分享
    000
  • python中reduce()函数怎么用?

    reduce()函数用于将序列归约为单一值,通过二元函数依次累积元素,可选初始值避免空序列报错,适用于求和、乘积、字典合并等场景,但需注意可读性与内置函数的优先选择。 在 Python 中, reduce() 函数主要用于对一个序列(如列表、元组等)中的元素进行累积操作,将序列“归约”成一个单一的值…

    2025年12月14日
    000
  • python中deque双端队列怎么用?

    deque是Python中高效处理双端操作的队列结构,适用于频繁在两端增删元素的场景。它支持append、appendleft、pop、popleft等基本操作,时间复杂度均为O(1),性能优于list。通过maxlen参数可实现固定长度的滑动窗口,超出时自动从对端移除元素。deque不支持线程安全…

    2025年12月14日
    000
  • python中怎么实现单例模式_Python设计模式之单例模式实现

    Python中实现单例模式的常见方法有:1. 重写__new__方法,通过类属性控制实例唯一性,适合简单场景;2. 使用装饰器,将单例逻辑与业务类分离,提升代码可读性和复用性;3. 利用元类(Metaclass),在类创建阶段控制实例化过程,适用于框架级设计。这些方法中,__new__方式最直接,装…

    2025年12月14日
    000
  • Python怎么进行MD5或SHA加密_hashlib模块哈希加密算法应用

    Python中使用hashlib模块进行MD5或SHA加密需先导入模块,选择算法如md5()或sha256()创建哈希对象,调用update()方法传入字节串数据,最后通过hexdigest()获取十六进制哈希值;处理大文件时应分块读取数据并更新哈希对象,避免内存溢出;MD5因碰撞漏洞已不推荐用于安…

    2025年12月14日
    000
  • 使用 Flet 刷新动态更新的图片

    本文将介绍在使用 Flet 框架开发应用时,如何实现动态更新图片的功能。当图片文件在操作系统层面被替换,但文件名保持不变时,传统的 page.update() 方法可能无法正确刷新图片显示。本文将提供一种解决方案,通过重新读取图片文件并将其转换为 base64 编码,从而强制 Flet 重新加载最新…

    2025年12月14日
    000
  • python中如何用beautifulsoup解析HTML_BeautifulSoup解析HTML网页实战

    BeautifulSoup是Python中流行的HTML解析工具,安装需运行pip install beautifulsoup4和lxml;通过构建解析树可轻松提取数据,如获取标签、属性、链接文本等,支持CSS选择器精确查找,结合requests库可用于网页抓取,注意设置请求头、编码及反爬策略,适合…

    2025年12月14日
    000
  • python asyncio如何使用_python asyncio异步编程入门教程

    事件循环是asyncio核心,负责调度协程、管理任务和处理I/O事件。它通过注册任务、监听事件、调度执行、切换协程及完成任务来实现单线程并发。协程是异步函数,任务包装协程并跟踪状态,Future表示未来结果,Task是其子类。异常处理可通过try-except、gather的return_excep…

    2025年12月14日
    000
  • python怎么发送HTTP的GET和POST请求_python发送HTTP请求实战指南

    使用requests库发送HTTP请求是Python中最直接推荐的方式,它简化了GET和POST请求的实现。首先通过pip install requests安装库。发送GET请求时,调用requests.get(url)获取数据,参数可通过params传递;发送POST请求时,使用requests.…

    2025年12月14日
    000
  • 使用 Flet 刷新动态变化的图片

    在 Flet 应用中动态更新图片,特别是当图片文件名不变但内容变化时,直接使用 page.update() 方法可能会失效。这是因为 Flet 可能会缓存图片,导致即使文件内容改变,显示的仍然是旧的图片。解决这个问题需要绕过缓存,强制 Flet 重新加载图片。 以下是一种实现动态刷新图片的方法: 读…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信