
在实际数据处理中,我们经常会遇到csv文件并非纯粹的逗号分隔值数据,而是在文件开头或结尾包含一些非结构化的元数据、报告标题或脚注。对于少量文件,手动清理尚可接受,但当需要处理成千上万个此类文件时,自动化清理和读取就变得至关重要。本文将介绍几种利用python和pandas库来应对这一挑战的有效方法。
为了演示这些方法,我们首先创建一个模拟包含非结构化文本的CSV文件 students.csv:
# 创建一个示例文件
sample_data = """SAMPLE FILE LTD
STUDENT NUMBERS
INFO 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:00
Student,id,add,div,rank
ABC,12,USA,A,1
DEF,13,IND,C,2
XYZ,14,UK,E,3
PQR,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,rank ABC,12,USA,A,1 DEF,13,IND,C,2 XYZ,14,UK,E,3 PQR,15,DE,F,4
这种方法的核心思想是,首先找到包含实际数据头部的行(例如,通过匹配列名),然后计算出在该行之前有多少行需要跳过,最后使用 pd.read_csv 的 skiprows 参数进行读取。
import pandas as pd
def 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 += 1
def 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)这种方法更加灵活和健壮,尤其适用于头部行位置不固定,但其内容结构相对稳定的情况。它通过Python的文件操作逐行读取,直到找到真正的CSV头部,然后将文件句柄的剩余部分直接传递给 pd.read_csv。
import pandas as pd
def 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)这种方法将整个文件内容作为字符串读取,然后进行分割、清洗和转换为DataFrame。它更通用,可以处理更复杂的非标准格式,但对于超大文件可能效率较低,因为它需要将整个文件内容加载到内存中。
import pandas as pd
def 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 df
df_full_read = read_cleaned_csv_by_full_read('students.csv')
print("方法三:全文件读取与后处理读取结果:")
print(df_full_read)
print("-" * 30)在处理包含非结构化文本的CSV文件时,选择合适的方法取决于文件的具体结构、大小和性能要求:
通用注意事项:
通过这些方法,您可以有效地自动化处理大量包含非结构化文本的CSV文件,从而节省时间和精力,确保数据处理流程的准确性和效率。
以上就是清理并高效读取含非结构化文本的CSV文件的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号