迭代点
这段代码的主要功能是优化前两天发的版本数据清洗【Python】Python3.6处理数据实例:快速进行数据清洗,可用但局部有小bug,静候大佬指导调整方案!
核心功能还是读取指定目录下的CSV文件,并将其转换为XLSX格式的Excel文件。在转换过程中,需要对数据进行一些预处理,例如清除字符串中的空白字符、将特定列包含百分比的字符串转换为数值类型。此外,代码还实现了多进程并发处理和处理进度的监控。
功能概述
- 文件读取与转换:从指定目录读取CSV文件,并将其转换为XLSX格式的Excel文件。
- 数据预处理:对数据进行清洗和格式转换。
- 多进程并发处理:利用Python的
concurrent.futures.ProcessPoolExecutor
并发执行多个文件的处理任务。 - 进度监控:记录处理过程中的时间信息,并统计处理进度。
实现模块
- os: 用于文件路径操作。
- re: 用于正则表达式的匹配。
- datetime: 用于获取当前时间和格式化时间。
- pandas: 用于读写CSV文件以及数据处理。
- xlsxwriter: 用于写入XLSX文件。
- multiprocessing: 用于多进程并发处理,这里主要使用
Manager
来创建共享队列和列表。
优点
- 高效处理大量文件:通过多进程并发处理,能够显著提高处理大量文件的速度。
- 数据预处理:对数据进行了适当的预处理,提高了数据的质量。
- 异常处理:对于处理过程中可能出现的异常进行了捕获,并记录了错误信息。
- 进度监控:实时输出处理进度,方便监控任务执行情况。
缺点
- 内存消耗:由于每个进程都会加载整个CSV文件到内存中进行处理,当文件非常大时可能会导致内存不足。
- 进程间通信开销:使用
Manager
创建的队列和列表在进程间传递数据时会产生一定的性能开销。 - 文件锁问题:如果两个进程试图同时写入同一个文件(例如日志文件),可能会导致文件锁冲突。这个可折磨死我了,有的文件太大了,单文件20MB左右,本来想用
batch_size=10
把单文件拆分成10个来处理,但是各种冲突报错,不晓得是不是这个导致的。 - 资源管理:虽然代码使用了
with
语句来管理资源,但在异常情况下可能还是需要更精细的资源释放机制。 - 可读性和维护性:代码较为复杂,尤其是多进程部分,可能不太好理解,也增加了后期维护的难度。
我想改进的地方
- 内存优化:考虑用
pandas
的分块读取功能来减少内存占用。 - 日志管理:把日志输出到单独的日志文件中,避免进程间的文件锁问题。
- 错误处理:增加更详细的错误处理逻辑,如重试。
- 并行度调整:根据实际硬件配置调整进程池的最大工作进程数,以达到最优性能。
- 代码结构改进:可以通过封装函数、类等方式提高代码的可读性和可维护性。
以上是对这段代码一个总结,希望有大佬看到能指点迷津,这个还能怎么继续优化,同时也希望能对有需要的打工人有所帮助。
以下是完整代码
import os
import re
import pandas as pd
import concurrent.futures
from datetime import datetime
from xlsxwriter.workbook import Workbook
from multiprocessing import Manager, Process, cpu_count
# CSV文件所在的目录
csv_dir = 'inputpath' # inputpath 替换为你需要保存数据清洗后的文件夹
# 输出文件夹
output_dir = os.path.join(csv_dir, 'outputpath') # outputpath替换为你需要保存数据清洗后的文件夹
os.makedirs(output_dir, exist_ok=True) # 确保输出文件夹存在
# 定义一个函数来处理单元格中的文本数据
def convert_text_to_number(cell_value):
# 如果单元格值含有百分号,则去除百分号并转换为数值
if isinstance(cell_value, str) and '%' in cell_value:
# 使用正则表达式移除百分号并转换为浮点数
return float(re.sub(r'%', '', cell_value)) / 100.0
# 如果单元格值是数字或数字型字符串,则转换为浮点数
if isinstance(cell_value, (int, float)) or (
isinstance(cell_value, str) and cell_value.replace('.', '', 1).isdigit()):
return float(cell_value)
# 如果没有找到数字,或者转换失败,则返回原始值
return cell_value
# 对特定列进行数值转换前的预处理
specific_cols = ['Y', 'AF', 'AJ', 'AR', 'AV']
# 处理单个CSV文件
def process_csv_file(csv_file, output_queue, processed_files):