数据清洗的第一步,是把数据"请进门"。听起来简单,但CSV的编码暗坑、Excel的多个工作表、中文乱码的顽固问题——这些细节能让新手卡住半天。本文将从pandas的数据读写入手。
文中涉及到的数据文件可以联系我发给你,因为我还不知道怎么在公众号插入文件
CSV(逗号分隔值)是最常见的数据交换格式。几乎所有系统都能导出CSV。pandas用 pd.read_csv() 读取它,这也是你以后使用频率最高的函数。
import pandas as pd
# 最简单的调用——只指定文件路径
df = pd.read_csv('data_python/employee_data.csv')
df.head(3)输出:
emp_id name department gender age education hire_date salary
0 EMP0001 员工_36 市场部 女 46.0 本科 2018-07-11 22968.99
1 EMP0002 员工_62 NaN 男 24.0 大专 2023-03-29 6314.78
2 EMP0003 员工_39 NaN 女 35.0 本科 2022-02-26 3222.29一行代码,数据已经在内存中了。但 read_csv() 的真正威力在于它的参数。
# pd.read_csv() 的常用参数一览
df = pd.read_csv(
'data_python/sales_orders.csv',
encoding='utf-8', # 文件编码
sep=',', # 分隔符
header=0, # 第几行作为列名(0表示第一行)
nrows=100, # 只读取前100行(预览大文件时特别有用)
usecols=None, # 指定要读取哪些列
dtype=None, # 指定列的数据类型
parse_dates=None, # 指定哪些列需要解析为日期
)encoding | 'utf-8''gbk', 'gb2312' | |
sep | ',''\t'(tsv文件) | |
header | 0None(无列名) | |
nrows | ||
usecols | [0, 1, 3]['emp_id', 'name'] | |
dtype | {'age': 'float64'} | |
parse_dates | ['hire_date'] | |
skiprows |
emp = pd.read_csv(
'data_python/employee_data.csv',
encoding='utf-8',
parse_dates=['hire_date'], # 入职日期直接转为datetime
dtype={'emp_id': 'string'} # 员工编号作为字符串(不需要数学运算)
)
# 验证:hire_date现在应该是datetime类型
print(emp.dtypes)
print(f"数据规模: {emp.shape}")关键习惯:读取数据时就把
parse_dates和dtype设好,不要等出错了再回头修正。这在处理大批量数据时尤其重要。
中文乱码是每个Python数据分析师都会遇到的"第一课"。当你满怀期待地 read_csv,结果看到一堆 锟斤拷 或 ???,那种挫败感我们都懂。
文件在保存时使用了一种编码(比如GBK),而你在读取时用了另一种编码(比如UTF-8)。编码不匹配,中文就变成了乱码。
第一步:尝试常见编码
# 中文文件最常见的三种编码,挨个试
for enc in ['utf-8', 'gbk', 'gb2312', 'utf-8-sig']:
try:
df = pd.read_csv('data_python/sales_orders.csv', encoding=enc)
print(f"{enc} ✓ 读取成功")
break
except Exception as e:
print(f"{enc} ✗ 失败: {type(e).__name__}")第二步:用chardet自动检测
如果手动尝试都失败了,让程序来猜:
import chardet
# 读取文件的原始字节,让chardet检测编码
with open('data_python/sales_orders.csv', 'rb') as f:
raw = f.read(10000) # 读取前10000字节就够了
result = chardet.detect(raw)
print(f"检测结果: {result}")
# 输出示例: {'encoding': 'utf-8', 'confidence': 0.99}第三步:用检测到的编码读取
encoding = result['encoding']
df = pd.read_csv('data_python/sales_orders.csv', encoding=encoding)
print(df.head(2))实用经验:Windows上用Excel生成的中文CSV通常是 GBK 编码。用代码生成的CSV通常是 UTF-8。如果你不确定,优先试这两个。
# 用 utf-8-sig 保存,Excel打开不会乱码
df.to_csv('output.csv', encoding='utf-8-sig', index=False)utf-8-sig 在文件头部添加了BOM(字节顺序标记),Windows Excel看到这个标记就知道用UTF-8打开,完美解决中文显示问题。
Excel文件在企业环境中无处不在。pandas读取Excel一样简单。
# 读取第一个工作表
df = pd.read_excel('data.xlsx')
# 读取指定工作表
df = pd.read_excel('data.xlsx', sheet_name='销售数据')
# 读取第2个工作表(索引从0开始)
df = pd.read_excel('data.xlsx', sheet_name=1)df = pd.read_excel(
'data.xlsx',
sheet_name='Sheet1', # 工作表名称或索引
header=0, # 列名所在行
usecols='A:D', # 只读取A到D列(Excel列号方式)
skiprows=2, # 跳过前2行(比如标题行)
nrows=500, # 只读取500行
dtype={'age': int}, # 指定数据类型
)# 一次性读取所有工作表,返回一个字典
all_sheets = pd.read_excel('data.xlsx', sheet_name=None)
# 逐个访问
for name, sheet_df in all_sheets.items():
print(f"工作表 [{name}]: {sheet_df.shape}")提示:
read_excel()依赖openpyxl库来读取.xlsx文件。如果遇到报错,先检查是否安装了它:pip install openpyxl。
pandas支持的数据格式远不止CSV和Excel,以下是几个你可能遇到的格式:
# JSON在Web API返回中非常常见
df = pd.read_json('data.json')
# 也可以直接读取JSON字符串
df = pd.read_json('[{"name":"张三","age":28},{"name":"李四","age":35}]')from sqlalchemy import create_engine
# 创建数据库连接
engine = create_engine('sqlite:///mydata.db')
# 用SQL查询读取数据
df = pd.read_sql('SELECT * FROM employees WHERE salary > 10000', engine)pd.read_csv() | df.to_csv() | |
pd.read_excel() | df.to_excel() | |
pd.read_json() | df.to_json() | |
pd.read_sql() | df.to_sql() | |
pd.read_stata() | df.to_stata() | |
pd.read_spss() | ||
pd.read_clipboard() | df.to_clipboard() |
清洗完的数据需要保存。to_csv() 和 to_excel() 是你的出口。
df.to_csv(
'cleaned_data.csv',
index=False, # 不保存行索引(强烈建议)
encoding='utf-8-sig', # Excel友好编码
sep=',', # 分隔符
float_format='%.2f', # 浮点数保留两位小数
na_rep='', # 缺失值用什么表示
)index=False 一定要加。否则每次保存都会多出一列无意义的数字索引,累计几次文件就会变得面目全非。
# 保存到单个工作表
df.to_excel('cleaned_data.xlsx', sheet_name='清洗结果', index=False)
# 把多个DataFrame写入同一个Excel文件的不同工作表
with pd.ExcelWriter('report.xlsx', engine='openpyxl') as writer:
emp.to_excel(writer, sheet_name='员工数据', index=False)
sales.to_excel(writer, sheet_name='销售数据', index=False)
cust.to_excel(writer, sheet_name='客户数据', index=False)pd.ExcelWriter 让你可以在一个Excel文件中创建多个工作表,非常适合生成多页报告。
当CSV文件达到几百MB甚至几GB时,一次性读入内存可能导致电脑卡死。pandas提供了两种策略。
# 只读前1000行,快速预览结构和内容
df_preview = pd.read_csv('large_file.csv', nrows=1000)
print(df_preview.shape)
print(df_preview.dtypes)# 每次读入5000行,逐块处理
chunks = []
for chunk in pd.read_csv('large_file.csv', chunksize=5000):
# 每一块是一个DataFrame,在这里做清洗
chunk = chunk.dropna() # 删除缺失值
chunk['date'] = pd.to_datetime(chunk['date']) # 转换日期
chunks.append(chunk)
# 合并所有处理后的块
df_full = pd.concat(chunks, ignore_index=True)
print(f"处理完成,总行数: {len(df_full)}")nrows | nrows=N | |
chunksize | chunksize=N | |
usecols | usecols=[...] | |
dtype | dtype={...} |
让我们用一个循环,把本系列的所有练习数据全部读入:
import pandas as pd
from pathlib import Path
data_dir = Path('data_python')
datasets = {}
for file in sorted(data_dir.glob('*.csv')):
# 从文件名提取数据集名称(去掉.csv后缀)
name = file.stem
# 读取,统一用utf-8编码
df = pd.read_csv(file, encoding='utf-8')
# 存入字典
datasets[name] = df
# 打印基本信息
print(f"{name:25s} → {df.shape[0]:>4} 行 × {df.shape[1]} 列")
print(f"\n共加载 {len(datasets)} 套数据集,准备就绪!")输出:
employee_data → 500 行 × 8 列
sales_orders → 610 行 × 6 列
customer_info → 300 行 × 7 列
department_data → 5 行 × 5 列
time_series_sales → 471 行 × 4 列
survey_data → 400 行 × 6 列
共加载 6 套数据集,准备就绪!现在所有数据都在 datasets 字典中,随时可以按名称取出。例如:
emp = datasets['employee_data']
sales = datasets['sales_orders']
print(emp['salary'].describe())
print(sales['product'].value_counts())这就是数据清洗的起点——把所有数据整齐地读入内存,为后续的探索和清洗做好准备。
今天我们学会了数据的"进门"和"出门":
pd.read_csv() | encodingparse_dates, dtype | |
pd.read_excel() | sheet_nameusecols, skiprows | |
pd.read_json() | orient | |
df.to_csv() | index=Falseencoding='utf-8-sig' | |
df.to_excel() | sheet_nameindex=False | |
chunksize |
核心原则就三条:
chardet 或挨个试 utf-8、gbkparse_dates,不要等后面再转换index=False下一篇 《数据初探与基础统计》 将进入真正的数据清洗实战。你会学到如何用 isnull() 定位缺失值、用 value_counts() 检查分类变量、用 groupby() 做分组统计——以及最重要的,如何培养"怀疑数据"的习惯。数据已经就位,准备动手清洗!
#Pandas #read_csv #中文乱码 #数据导入 #编码问题 #chardet
如果这篇文章帮你解决了中文乱码问题,点个"在看"让更多人看到。有问题欢迎留言,我们评论区见。