4. 用Pandas读取农业食品数据

在农业食品数据分析中,我们拿到的原始数据往往来自三个完全不同的渠道:农业农村部门发布的作物产量统计表、气象站导出的逐日观测记录、以及批发市场或电商平台导出的价格流水。这些数据可能是 CSV,也可能是 Excel,编码、列名、缺失值写法各不相同。Pandas 的 read_csv() 和 read_excel() 就是把这些"异构原料"统一成 DataFrame 的第一道工序。这一节我们围绕"读得进、读得对、看得清"三个目标展开:先掌握读取函数的关键参数,再处理列名、编码与缺失值标记,最后用结构查看方法确认数据是否按预期进入内存。

一、read_csv 与 read_excel 的核心参数

两个函数共享大量参数,理解它们的作用比死记参数表更重要。下面这张图把"文件 → 参数 → DataFrame → 结构检查"的读取链路和关键参数分组呈现出来,便于对照记忆。

产量统计表 产量.csv(GBK) 气象观测记录 weather.xlsx 价格流水 price.csv(UTF-8) Pandas 读取函数 read_csv( ) read_excel( ) 按文件类型选择 参数决定"读得对不对" 列名与表头 header=0 / None,names=[...] usecols 只读需要的列,减少内存 编码 encoding="utf-8" / "gbk" / "gb18030" 中文乱码时优先尝试 gb18030 缺失值标记 na_values=["", "—", "NA", "无"] keep_default_na 控制是否保留默认标记 Excel 专属 sheet_name="Sheet1" 或 0 dtype 指定列类型,避免编号被转数字 DataFrame 行 × 列 + 索引 + 类型 结构检查四件套: df.shape 看行列数 | df.head() 看前几行 | df.info() 看类型与非空计数 | df.describe() 看数值分布

实际读取时,最常见的写法是先把参数写全,再逐步精简。例如读取一份 GBK 编码、首行为列名、用"—"表示缺失的产量表:

import pandas as pd

yield_df = pd.read_csv(
    "产量.csv",
    encoding="gbk",
    na_values=["—", "无", ""],
    usecols=["年份", "地区", "作物", "播种面积", "总产量"]
)
print(yield_df.shape)
print(yield_df.head())

Excel 文件则多一个工作表选择问题。气象数据常把多个站点放在不同 sheet 中,此时 sheet_name 可以传名称、序号,甚至传 None 一次性读成"表名 → DataFrame"的字典,便于后续按站点循环处理。

二、列名、编码与缺失值:三个最容易踩的坑

列名问题分两类。一类是文件本身没有表头,数据从第一行就开始,这时要写 header=None,再用 names 显式给出列名;另一类是表头存在但含空格、换行或单位,如"总产量(吨)",读入后建议统一重命名为简洁的英文或拼音标识,避免后续用中文列名做运算时反复转义。重命名用 df.rename(columns={...}) 即可,注意 inplace 参数或重新赋值的选择要保持一致。

编码问题表现为中文变成乱码或直接抛 UnicodeDecodeError。判断方法很直接:Windows 下由 Excel 另存的 CSV 多为 GBK 系,Linux 或网页导出多为 UTF-8。遇到报错先换 encoding="gb18030",它兼容 GBK 且字符集更全;若仍失败,可用 chardet 探测,或先用文本编辑器另存为 UTF-8 再读。不要用 errors="ignore" 掩盖问题,那会静默丢字符。

缺失值标记是农业数据里最隐蔽的坑。气象表用"999"表示缺测,价格表用"-"表示当日无交易,产量表用空格表示未统计。Pandas 默认只把空字符串、NA、NaN 等识别为缺失,其余会当成正常字符串或数值读进来,导致均值、求和全部失真。正确做法是通过 na_values 补充业务标记;如果某些列本来就有合法取值与缺失标记冲突(例如产量列里 0 是真实值),则用字典形式按列指定:na_values={"单产": ["", "—"], "价格": ["-"]}。同时留意 keep_default_na,默认 True 会保留 Pandas 内置标记集,一般不必关闭。

把"999"这类缺测码直接当数值参与计算,是农业气象数据中最常见的错误来源。读入后务必用 df.isna().sum() 核对每列缺失数量,与原始表格的人工抽查结果对照。

三、查看数据结构与基本信息

数据读进来不等于读对了。建议按固定顺序做四项检查:shape 确认行列数与预期一致;head() 与 tail() 抽查首尾,看列名是否错位、中文是否正常;info() 查看每列 dtype 和非空计数,若"年份"被读成 object 或"产量"被读成 object,说明混入了非数值字符;describe() 看数值列的均值、最值与分位数,异常的最大值往往就是漏标的缺测码。

检查方法关注点典型异常信号
df.shape行数、列数行数远少于源文件,可能被错误分隔符截断
df.head()列名、首行内容列名变成"Unnamed: 0",说明索引列被误读
df.info()dtype、非空计数数值列显示 object,存在非数值字符
df.describe()最值、分位数最大值 999 或 -999,疑似缺测码未处理

以价格数据为例,若 info() 显示"价格"列为 object,可进一步用 pd.to_numeric(df["价格"], errors="coerce") 转换,转换后新增的 NaN 就是无法解析的脏值,再回查原始行定位问题。这一步与读取阶段的 na_values 形成互补:前者处理"已知标记",后者兜底"未知脏值"。

养成"读取即记录"的习惯:在代码注释或分析日志中写明文件名、编码、缺失标记和读入后的 shape。多人协作时,这份记录能避免后来者重复试错。

把三类数据都读成干净的 DataFrame 之后,后续的合并、清洗与统计才有可靠基础。本节的关键不在于记住所有参数,而在于形成"先判断文件特征、再配置参数、最后用结构检查验证"的稳定习惯——读得进只是起点,读得对才是目的。