第四章:数据读取与预处理——文件格式解析与清洗实战

各位工程师朋友,大家好。今天我们来聊聊MOCVD数据分析中最基础、也最容易被忽视的一环——数据读取与预处理。

说实话,我见过太多人一上来就急着建模、画图,结果数据本身就有问题。嗯,这就像盖房子不打地基,迟早要塌。我自己在早期做MOCVD工艺开发时,就吃过这个亏。有一次花了整整一周分析反射率曲线,最后发现是原始数据里混入了几个异常点,导致整个结论都是错的。从那以后,我养成了一个习惯:拿到数据,先花30%的时间做预处理。

4.1 文件格式解析:CSV/Excel/TXT

MOCVD原位监测的数据来源五花八门。有的设备输出CSV,有的用Excel,还有的老设备直接给TXT。我个人的习惯是,先统一转成CSV格式再处理。为什么?因为CSV轻量、跨平台、Python读取最快。

咱们直接看代码。这是我最常用的读取方式:

import pandas as pd
import numpy as np

# 读取CSV——最常见的情况
df_csv = pd.read_csv('mocvd_data.csv', encoding='utf-8')

# 读取Excel——注意sheet_name参数
df_excel = pd.read_excel('mocvd_data.xlsx', sheet_name='Sheet1')

# 读取TXT——有时候分隔符是空格或制表符
df_txt = pd.read_csv('mocvd_data.txt', sep='\t', header=None)

这里有个小坑。我在项目中遇到过,有些老设备的TXT文件第一行是注释,不是列名。这时候要加个skiprows=1参数跳过它。你想想看,如果不跳过,第一行数据就被当成列名了,后面全乱套。

我的小技巧: 拿到不熟悉的文件,先用 df.head() 看一眼前5行。这能帮你快速确认数据格式对不对。

4.2 缺失值处理——别急着删

缺失值在MOCVD数据里太常见了。比如温度传感器偶尔掉线,或者反射率信号在切换波长时出现空白。很多人一看到NaN就删掉整行,我建议你先想想:这个缺失值是怎么来的?

我一般分三种情况处理:

  • 随机缺失:比如传感器偶尔丢包。可以用前后均值填充。
  • 系统性缺失:比如某个工艺步骤不采集数据。这时候填充反而会引入偏差,我建议保留NaN。
  • 关键参数缺失:比如生长速率数据缺失。嗯,这种情况我倾向于用插值法。

看代码:

# 检查缺失值
print(df.isnull().sum())

# 方法1:删除缺失值过多的列(比如缺失超过50%)
df_clean = df.dropna(thresh=len(df)*0.5, axis=1)

# 方法2:用前后均值填充(适合连续数据)
df['temperature'] = df['temperature'].fillna(method='ffill').fillna(method='bfill')

# 方法3:线性插值(我最推荐的方法)
df['reflectance'] = df['reflectance'].interpolate(method='linear')
注意: 我曾经犯过一个错误——对分类数据用了均值填充。结果模型训练出来完全不对。后来才意识到,分类数据的缺失值应该用众数填充,或者单独标记为一个新类别。

4.3 异常值检测——别让一个点毁了整条曲线

MOCVD数据里的异常值,说白了就是那些明显偏离正常范围的点。比如反射率突然跳到1.5以上(正常范围0-1),或者温度瞬间变化超过50°C。这些点往往是传感器故障或者信号干扰造成的。

我常用的检测方法有三种:

方法 适用场景 我的经验
Z-score法 数据近似正态分布 适合温度、压力这类参数
IQR四分位法 数据分布偏态 适合反射率、生长速率
移动窗口法 时间序列数据 我最常用,能捕捉局部异常

代码实现:

from scipy import stats

# Z-score法——适合正态分布数据
z_scores = np.abs(stats.zscore(df['temperature']))
df_no_outlier = df[(z_scores < 3)]  # 保留Z-score小于3的数据

# IQR法——适合偏态分布
Q1 = df['reflectance'].quantile(0.25)
Q3 = df['reflectance'].quantile(0.75)
IQR = Q3 - Q1
df_no_outlier = df[(df['reflectance'] >= Q1 - 1.5*IQR) & 
                   (df['reflectance'] <= Q3 + 1.5*IQR)]

# 移动窗口法——我最推荐的方法
window_size = 10
rolling_mean = df['reflectance'].rolling(window=window_size).mean()
rolling_std = df['reflectance'].rolling(window=window_size).std()
df_no_outlier = df[np.abs(df['reflectance'] - rolling_mean) <= 3*rolling_std]
核心原则: 异常值不一定要删除。有时候异常值本身就有物理意义——比如它可能标志着一次工艺异常。我建议先标记出来,再决定是删除还是保留。

4.4 数据标准化——让不同量纲的参数能放在一起比较

MOCVD数据里,温度是几百到一千多度,反射率是0到1,生长速率是纳米/分钟。量纲完全不同。如果你直接拿这些数据做分析,温度会主导一切,反射率几乎没影响。这显然不合理。

标准化的目的,说白了就是把所有参数拉到同一个尺度上。我常用的有两种:

  • Z-score标准化:减去均值,除以标准差。结果均值为0,标准差为1。适合数据分布比较对称的情况。
  • Min-Max归一化:缩放到[0,1]区间。适合有明确上下限的参数,比如反射率。

代码:

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# Z-score标准化——我最常用
scaler = StandardScaler()
df_scaled = pd.DataFrame(
    scaler.fit_transform(df[['temperature', 'reflectance', 'growth_rate']]),
    columns=['temperature', 'reflectance', 'growth_rate']
)

# Min-Max归一化——适合有物理边界的参数
scaler = MinMaxScaler()
df_normalized = pd.DataFrame(
    scaler.fit_transform(df[['temperature', 'reflectance', 'growth_rate']]),
    columns=['temperature', 'reflectance', 'growth_rate']
)
我的建议: 如果你后续要做PCA或者聚类分析,用Z-score标准化。如果你要做神经网络,用Min-Max归一化。这个选择会影响模型收敛速度。

知识体系总览

下面这张图是我自己总结的数据预处理流程。每次拿到新数据,我就按这个步骤走一遍,基本不会出大问题。

MOCVD数据预处理流程 文件格式解析 CSV / Excel / TXT 缺失值处理 填充 / 插值 / 删除 异常值检测 Z-score / IQR / 移动窗口 数据标准化 Z-score / Min-Max 干净数据 → 分析建模 关键要点 • 先看数据头,确认格式 • 缺失值不急着删 • 异常值可能有物理意义 • 标准化方法要选对 • 每一步都做可视化检查 • 保留原始数据备份 • 记录每一步的处理参数 • 用版本号管理数据 • 和工艺工程师确认边界 • 最终数据要可复现

好了,以上就是数据读取与预处理的全部内容。说实话,这些步骤看起来简单,但真正做好并不容易。我自己的经验是:多花时间在预处理上,后面分析建模会省很多事。记住一句话——垃圾进,垃圾出。数据质量决定了分析结果的上限。

专注资料整理