在日常数据处理工作中,我们几乎每天都要和各种格式的数据文件打交道。作为Python开发者,掌握不同格式文件的读写方法是必备技能。本文将系统梳理Python处理常见数据文件的方法论,从内置模块到第三方库,从基础操作到高阶技巧,带你构建完整的数据文件处理知识体系。
我从事数据分析工作多年,处理过各种"奇葩"数据文件格式,深知不同场景下工具选型的重要性。比如当需要快速查看一个小型CSV文件时,直接使用内置csv模块就足够了;但处理GB级别的大型数据集时,pandas的read_csv配合chunksize参数才是明智之选;而当需要处理复杂的Excel报表时,openpyxl提供的单元格级操作能力就派上用场了。
Python标准库中的csv模块是处理CSV文件的首选工具。CSV(Comma-Separated Values)作为一种轻量级数据交换格式,在数据科学领域应用极为广泛。与直接使用文件对象的read/write方法相比,csv模块能正确处理包含换行符、引号等特殊字符的情况,避免数据解析错误。
读取CSV文件的标准写法:
python复制import csv
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
print(row) # 每行数据以列表形式返回
写入CSV文件的正确姿势:
python复制data = [
['姓名', '年龄', '城市'],
['张三', 28, '北京'],
['李四', 32, '上海']
]
with open('output.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerows(data) # 一次性写入多行
注意:在Windows平台写入CSV文件时,务必指定newline=''参数,否则会出现空行问题。这是Windows换行符处理机制导致的。
实际工作中我们经常需要处理非标准CSV文件,这时就需要用到csv模块的一些高级参数:
python复制# 处理以分号分隔的文件
csv.reader(f, delimiter=';')
# 处理包含标题行的文件
csv.DictReader(f) # 每行数据以字典形式返回,键为标题行
# 处理包含引号的字段
csv.writer(f, quoting=csv.QUOTE_NONNUMERIC) # 非数字字段自动加引号
# 自定义空值处理
csv.writer(f, na_rep='NULL') # 将None值写入为'NULL'
我曾经遇到过一个坑:处理从欧洲同事发来的CSV文件时,发现数字解析总是出错。后来发现他们使用逗号作为小数点(如"1,23"表示1.23),而用分号作为列分隔符。解决方案是:
python复制csv.reader(f, delimiter=';', decimal=',')
NumPy提供了多种数据加载方法,最常用的是loadtxt和更强大的genfromtxt:
python复制import numpy as np
# 基本加载
data = np.loadtxt('data.csv', delimiter=',')
# 处理缺失值
data = np.genfromtxt('data.csv', delimiter=',',
filling_values=0, # 缺失值填充为0
skip_header=1) # 跳过标题行
genfromtxt的优势在于:
对于大型数值数据集,二进制格式能显著提高IO性能:
python复制# 保存为NumPy原生二进制格式
arr = np.random.rand(10000, 10000)
np.save('big_array.npy', arr) # 保存单个数组
np.savez('multi_array.npz', arr1=arr1, arr2=arr2) # 保存多个数组
# 加载时内存映射技术处理超大文件
mmapped = np.load('huge_array.npy', mmap_mode='r')
我曾经处理过一个20GB的气象数据集,使用mmap模式可以像操作内存数组一样操作磁盘文件,而不会耗尽内存。
Pandas的read_csv函数堪称数据科学家的瑞士军刀,支持上百个参数应对各种复杂场景:
python复制import pandas as pd
# 基本读取
df = pd.read_csv('data.csv')
# 处理复杂情况
df = pd.read_csv('messy_data.csv',
encoding='gbk', # 指定编码
skiprows=[0,2,3], # 跳过不规则标题行
parse_dates=['date'], # 日期解析
na_values=['NA', 'NULL'], # 自定义缺失值
dtype={'id': str}, # 指定列类型
thousands=',', # 千分位分隔符
nrows=1000) # 只读取前1000行
处理超大型CSV文件时,这些技巧可以显著提升性能:
python复制# 分块读取
chunk_iter = pd.read_csv('huge.csv', chunksize=100000)
for chunk in chunk_iter:
process(chunk)
# 指定数据类型减少内存占用
dtypes = {'id': 'int32', 'price': 'float32'}
pd.read_csv('large.csv', dtype=dtypes)
# 使用C引擎加速
pd.read_csv('data.csv', engine='c')
Pandas支持几乎所有的数据格式:
python复制# Excel文件
pd.read_excel('data.xlsx', sheet_name='Sheet1')
# JSON数据
pd.read_json('data.json', orient='records')
# SQL数据库
import sqlite3
conn = sqlite3.connect('database.db')
pd.read_sql('SELECT * FROM table', conn)
# 剪贴板数据
pd.read_clipboard() # 直接从复制的表格数据创建DataFrame
Python操作Excel的库各有侧重:
| 库名称 | 读写支持 | 格式支持 | 主要特点 |
|---|---|---|---|
| xlrd | 只读 | xls/xlsx | 经典但停止维护 |
| xlwt | 只写 | xls | 生成旧版Excel文件 |
| openpyxl | 读写 | xlsx | 功能全面,推荐使用 |
| xlwings | 读写 | 全格式 | 与Excel程序交互 |
| pandas | 读写 | xls/xlsx | 简单操作,依赖其他库 |
openpyxl是当前最推荐的Excel操作库:
python复制from openpyxl import Workbook, load_workbook
# 创建新工作簿
wb = Workbook()
ws = wb.active
ws['A1'] = "Hello" # 单元格赋值
ws.append([1, 2, 3]) # 添加一行数据
# 样式设置
from openpyxl.styles import Font, Color
ws['A1'].font = Font(bold=True, color="FF0000")
wb.save('report.xlsx')
# 读取现有文件
wb = load_workbook('data.xlsx')
print(wb.sheetnames) # 查看所有工作表
处理复杂Excel报表时可能需要:
python复制# 合并单元格
ws.merge_cells('A1:D1')
# 公式计算
ws['E1'] = "=SUM(A1:D1)"
# 条件格式
from openpyxl.formatting.rule import ColorScaleRule
rule = ColorScaleRule(start_type='min', start_color='FFFFFF',
end_type='max', end_color='FF0000')
ws.conditional_formatting.add('A1:D10', rule)
# 图表插入
from openpyxl.chart import BarChart
chart = BarChart()
chart.add_data(ws.values)
ws.add_chart(chart, "F1")
Python通过DB-API规范支持各种关系型数据库:
python复制# SQLite (内置支持)
import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM stocks')
print(cursor.fetchall())
# MySQL
import pymysql
conn = pymysql.connect(host='localhost',
user='user',
password='pass',
database='db')
pd.read_sql('SELECT * FROM table', conn)
# PostgreSQL
import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
对于复杂应用,SQLAlchemy等ORM框架更高效:
python复制from sqlalchemy import create_engine
engine = create_engine('sqlite:///example.db')
# 直接执行SQL
engine.execute("INSERT INTO table VALUES (1, 'test')")
# 与Pandas集成
df.to_sql('table', engine, if_exists='replace') # DataFrame写入数据库
pd.read_sql_table('table', engine) # 整表读取
python复制# MongoDB
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.test_database
db.collection.insert_one({'name': 'John'})
# Redis
import redis
r = redis.Redis(host='localhost', port=6379)
r.set('foo', 'bar')
print(r.get('foo'))
处理大型数据集时的内存管理策略:
python复制# 使用合适的数据类型
df = df.astype({'col1': 'int32', 'col2': 'category'})
# 分块处理
for chunk in pd.read_csv('large.csv', chunksize=10000):
process(chunk)
# 使用Dask处理超大数据集
import dask.dataframe as dd
ddf = dd.read_csv('very_large_*.csv')
python复制# 尝试常见编码
for encoding in ['utf-8', 'gbk', 'latin1']:
try:
pd.read_csv('file.csv', encoding=encoding)
break
except UnicodeDecodeError:
continue
python复制# 明确指定日期格式
pd.to_datetime(df['date'], format='%Y-%m-%d %H:%M:%S')
# 处理混合格式日期
pd.to_datetime(df['date'], errors='coerce') # 无法解析的设为NaT
python复制# openpyxl默认不计算公式,需要手动启用
wb = load_workbook('file.xlsx', data_only=True)
多年实战经验告诉我,数据文件处理看似简单,实则暗藏无数细节陷阱。比如我曾经因为忘记指定newline=''导致生成的CSV在Excel中全部显示为一行;也曾经因为编码问题导致中文全部变成乱码。掌握这些工具的正确使用方式,能让你在数据处理工作中事半功倍。