3. 数据加载与初步探索:先摸清数据的底细
拿到一份生产数据,别急着上模型。我个人的习惯是,先花 15 分钟把数据「摸」一遍。说白了,就是搞清楚三件事:数据长什么样、有没有坑、能不能直接用。
这一章,我们就用 pandas 走完这个流程。你跟着我敲一遍,以后拿到任何表格数据,心里都有底。
3.1 用 pandas 读取 CSV 和 Excel
pandas 的 read_csv() 和 read_excel() 是最常用的两个函数。我见过不少新手直接 pd.read_csv('data.csv') 就跑,结果后面全是乱码或类型错误。嗯,这里要注意几个参数。
import pandas as pd
# 读取 CSV —— 我建议显式指定编码
df_csv = pd.read_csv('production_data.csv', encoding='utf-8')
# 如果报编码错误,试试 'gbk' 或 'latin1'
# df_csv = pd.read_csv('production_data.csv', encoding='gbk')
# 读取 Excel —— 可以指定 sheet
df_excel = pd.read_excel('production_data.xlsx', sheet_name='Sheet1')
# 如果文件有中文列名,记得加这一句
# df_csv = pd.read_csv('data.csv', encoding='utf-8-sig')
chunksize=10000 分块读取,才搞定。如果你的数据很大,记得用 chunksize 或 dtype 指定列类型来省内存。
3.2 看一眼数据全貌:shape 与 info
数据加载完,我第一件事就是看 .shape。它告诉你数据有多少行、多少列。比如一个产量预测数据集,可能有 10 万行、20 列。行数太少,模型容易过拟合;列数太多,要小心维度灾难。
print('数据集形状:', df_csv.shape)
# 输出示例: (102400, 18)
然后我会跑 .info()。这个函数会列出每一列的名称、非空数量、数据类型。我特别喜欢用它来快速定位缺失值和类型异常。
df_csv.info()
输出大概长这样:
| 列名 | 非空计数 | 数据类型 |
|---|---|---|
| batch_id | 102400 | int64 |
| temperature | 102400 | float64 |
| pressure | 102400 | float64 |
| humidity | 102400 | float64 |
| raw_material_quality | 102400 | object |
| yield_amount | 102400 | float64 |
| defect_rate | 102400 | float64 |
| operator_shift | 102400 | object |
| machine_id | 102400 | int64 |
| timestamp | 102400 | object |
object 但实际应该是数值(比如 '25.3'),说明需要类型转换。这两点,我在项目中几乎每次都会遇到。
3.3 描述性统计:describe() 的妙用
.describe() 会给出数值列的统计摘要:均值、标准差、最小值、四分位数、最大值。我一般用它来快速判断数据分布是否合理。
df_csv.describe()
输出示例:
| 统计量 | temperature | pressure | humidity | yield_amount | defect_rate |
|---|---|---|---|---|---|
| count | 102400.00 | 102400.00 | 102400.00 | 102400.00 | 102400.00 |
| mean | 75.32 | 1.02 | 45.67 | 892.15 | 0.03 |
| std | 10.15 | 0.15 | 12.34 | 120.50 | 0.01 |
| min | 40.10 | 0.50 | 10.00 | 450.00 | 0.00 |
| 25% | 68.00 | 0.92 | 36.00 | 810.00 | 0.02 |
| 50% | 75.00 | 1.01 | 45.00 | 890.00 | 0.03 |
| 75% | 82.00 | 1.12 | 55.00 | 970.00 | 0.04 |
| max | 120.00 | 1.80 | 80.00 | 1350.00 | 0.15 |
你想想看,如果 temperature 的最大值是 120°C,但工艺要求不能超过 100°C,那这些数据就有异常。我在一个化工项目中就遇到过类似情况,后来发现是传感器故障。所以,describe() 不只是看数字,更是找异常的第一步。
3.4 数据类型检查:别让 object 坑了你
数据类型不对,模型训练会直接报错。我习惯用 .dtypes 快速扫一眼,然后用 pd.to_numeric() 或 pd.to_datetime() 做转换。
# 检查所有列的类型
print(df_csv.dtypes)
# 如果某列是 object 但应该是数值,强制转换
df_csv['temperature'] = pd.to_numeric(df_csv['temperature'], errors='coerce')
# 如果时间戳是字符串,转成 datetime
df_csv['timestamp'] = pd.to_datetime(df_csv['timestamp'])
errors='coerce' 会把无法转换的值变成 NaN。这样你就能快速定位哪些数据有问题。我曾经用这个参数,发现一批数据里混入了中文备注,直接揪出了数据录入环节的 bug。
3.5 知识体系总览
下面这张图,把数据加载与初步探索的核心流程串起来了。你可以把它当作一个 checklist,每次拿到新数据都走一遍。
3.6 实战小贴士:把探索写成函数
我个人习惯把上面这些步骤封装成一个函数。每次拿到新数据,跑一遍就完事。省时间,也避免遗漏。
def quick_explore(df, name='dataset'):
print(f'=== {name} 初步探索 ===')
print(f'形状: {df.shape}')
print(f'\n列信息:')
df.info()
print(f'\n描述性统计:')
print(df.describe())
print(f'\n数据类型:')
print(df.dtypes)
print(f'\n前5行:')
print(df.head())
# 使用
quick_explore(df_csv, '产量数据')
info() 和 describe(),确保改动没引入新问题。你想想看,如果改完数据忘了检查,后面模型跑出来一堆 NaN,那才叫头疼。