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')
我曾经踩过的坑:有一次读取一个 500MB 的 CSV,直接内存爆了。后来加了 chunksize=10000 分块读取,才搞定。如果你的数据很大,记得用 chunksize 或 dtype 指定列类型来省内存。

3.2 看一眼数据全貌:shape 与 info

数据加载完,我第一件事就是看 .shape。它告诉你数据有多少行、多少列。比如一个产量预测数据集,可能有 10 万行、20 列。行数太少,模型容易过拟合;列数太多,要小心维度灾难。

print('数据集形状:', df_csv.shape)
# 输出示例: (102400, 18)

然后我会跑 .info()。这个函数会列出每一列的名称、非空数量、数据类型。我特别喜欢用它来快速定位缺失值和类型异常。

df_csv.info()

输出大概长这样:

列名非空计数数据类型
batch_id102400int64
temperature102400float64
pressure102400float64
humidity102400float64
raw_material_quality102400object
yield_amount102400float64
defect_rate102400float64
operator_shift102400object
machine_id102400int64
timestamp102400object
关键点:如果某列的非空计数小于总行数,说明有缺失值。如果某列的类型是 object 但实际应该是数值(比如 '25.3'),说明需要类型转换。这两点,我在项目中几乎每次都会遇到。

3.3 描述性统计:describe() 的妙用

.describe() 会给出数值列的统计摘要:均值、标准差、最小值、四分位数、最大值。我一般用它来快速判断数据分布是否合理。

df_csv.describe()

输出示例:

统计量temperaturepressurehumidityyield_amountdefect_rate
count102400.00102400.00102400.00102400.00102400.00
mean75.321.0245.67892.150.03
std10.150.1512.34120.500.01
min40.100.5010.00450.000.00
25%68.000.9236.00810.000.02
50%75.001.0145.00890.000.03
75%82.001.1255.00970.000.04
max120.001.8080.001350.000.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,每次拿到新数据都走一遍。

数据加载与初步探索流程 数据加载与初步探索流程 1. 数据加载 2. shape & info 3. 描述性统计 4. 数据类型检查 5. 输出结果与决策 常见数据源 • CSV 文件 • Excel 文件 • 数据库查询结果 检查要点 • 缺失值 • 异常值 • 类型错误

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,那才叫头疼。