第4章 Pandas入门:从数据到洞察的第一步

说实话,做材料计算这几年,我最大的感触就是——数据本身不会说话,但Pandas能让它开口。你可能已经用VASP、LAMMPS算了一大堆数据,但面对几十个CSV文件时,是不是有点头大?别急,这一章我们就把Pandas这个利器彻底搞明白。

4.1 Series与DataFrame:Pandas的两大基石

先说说这两个东西到底是什么。我刚开始接触Pandas时,总觉得它们很抽象。后来我给自己打了个比方:Series是一列数据,DataFrame是一张表格。就这么简单。

4.1.1 Series:带标签的一维数组

Series说白了就是「有名字的一列数据」。它比Python列表强在哪?强在你可以给每个数据起个名字(索引)。

import pandas as pd

# 创建一个Series
energies = pd.Series([-4.56, -3.21, -5.89, -2.34], 
                     index=['Si', 'Ge', 'GaAs', 'InP'])
print(energies)

# 输出:
# Si     -4.56
# Ge     -3.21
# GaAs   -5.89
# InP    -2.34
# dtype: float64

你看,每个能量值都对应一个材料名。这在处理材料数据时特别方便。我记得有一次做能带计算,需要快速查找某个材料的带隙值,用Series的索引查找比列表快多了。

我的小技巧: 如果你有一堆计算数据,建议先用Series把关键物理量(如能量、体积、带隙)存起来,方便后续分析。

4.1.2 DataFrame:表格数据的终极形态

DataFrame就是一张电子表格。行是样本,列是属性。做材料计算的人,天天跟这个打交道。

# 创建一个DataFrame
data = {
    '材料': ['Si', 'Ge', 'GaAs', 'InP'],
    '带隙(eV)': [1.12, 0.67, 1.43, 1.35],
    '晶格常数(Å)': [5.43, 5.66, 5.65, 5.87],
    '介电常数': [11.9, 16.0, 12.9, 12.5]
}
df = pd.DataFrame(data)
print(df)

输出结果就像一张整齐的表格。我个人习惯把计算出的所有结构参数都塞进一个DataFrame里,这样后续做筛选、绘图都特别顺手。

4.2 数据读取与写入:CSV和Excel

嗯,这里要注意——材料计算的数据文件格式五花八门,但CSV和Excel是最常见的两种。我见过太多人手动复制粘贴数据了,其实一行代码就能搞定。

4.2.1 读取CSV文件

# 读取CSV文件
df = pd.read_csv('band_structure.csv')

# 常用参数
df = pd.read_csv('data.csv', 
                 sep=',',        # 分隔符,默认逗号
                 header=0,       # 第0行作为列名
                 index_col=0,    # 第0列作为行索引
                 na_values=['NA', 'null'])  # 指定缺失值标记

我曾经处理过一个VASP计算的大批量数据,几百个CSV文件,每个文件里还有空行和注释。用skiprows参数跳过前几行,用comment参数忽略注释行,几分钟就搞定了。

4.2.2 读取Excel文件

# 读取Excel文件
df = pd.read_excel('experimental_data.xlsx', sheet_name='Sheet1')

# 读取多个sheet
dfs = pd.read_excel('data.xlsx', sheet_name=None)  # 返回字典
避坑指南: 我曾经因为Excel文件里有合并单元格,读进来全是NaN。后来发现加个参数header=None,自己手动指定列名,问题就解决了。

4.2.3 写入文件

# 写入CSV
df.to_csv('processed_data.csv', index=False)

# 写入Excel
df.to_excel('result.xlsx', sheet_name='计算结果', index=False)

你想想看,每次算完一批数据,直接to_csv保存,既规范又省事。我一般会在文件名里加上日期,比如results_2024_01_15.csv,方便追溯。

4.3 数据清洗与筛选:把脏数据变干净

做材料计算的人都知道,原始数据很少是完美的。有时候计算不收敛,有时候实验测量有误差,数据里总会有各种「脏东西」。清洗数据,说白了就是把这些脏东西挑出来或者修好。

4.3.1 查看数据概览

# 快速查看数据
df.head()      # 前5行
df.info()      # 列信息、非空值数量、数据类型
df.describe()  # 统计摘要(均值、标准差、分位数等)

我个人习惯拿到数据先跑df.info(),看看有没有列的数据类型不对。比如「带隙」这一列如果是object类型而不是float,那肯定有问题。

4.3.2 筛选数据

# 条件筛选
# 筛选带隙大于1.0 eV的材料
wide_gap = df[df['带隙(eV)'] > 1.0]

# 多条件筛选
# 带隙在1.0-2.0之间,且介电常数大于10
selected = df[(df['带隙(eV)'] >= 1.0) & (df['带隙(eV)'] <= 2.0) & (df['介电常数'] > 10)]

# 按列筛选
df[['材料', '带隙(eV)']]

为什么筛选这么重要?因为很多时候我们只关心特定范围的数据。比如研究光伏材料,你肯定只关心带隙在1.0-1.5 eV之间的材料。用Pandas筛选,一行代码就搞定。

4.3.3 排序与去重

# 按带隙升序排序
df_sorted = df.sort_values('带隙(eV)')

# 去重
df_unique = df.drop_duplicates(subset=['材料'])

我记得有一次处理合金成分的数据,同一个成分重复计算了好几次。用drop_duplicates去重后,数据量直接减半,分析起来清爽多了。

4.4 缺失值处理:别让NaN毁了你的分析

缺失值,就是数据里的「黑洞」。计算不收敛、实验没测到、数据录入遗漏……原因太多了。但你不能不管它,否则后续画图、拟合全都会报错。

4.4.1 检测缺失值

# 检测缺失值
df.isnull().sum()  # 每列缺失值数量

# 缺失值占比
df.isnull().mean() * 100

4.4.2 处理缺失值的三种策略

处理缺失值,说白了就三条路:删、填、插。我根据自己的经验给你总结一下:

策略 方法 适用场景 代码示例
删除 直接扔掉有缺失的行或列 缺失值很少(<5%) df.dropna()
填充 用均值、中位数、众数填充 缺失值较多,但数据分布稳定 df.fillna(df.mean())
插值 用前后值线性插值 时间序列或连续变化的数据 df.interpolate()
# 具体示例
# 1. 删除所有包含缺失值的行
df_clean = df.dropna()

# 2. 用均值填充
df['带隙(eV)'] = df['带隙(eV)'].fillna(df['带隙(eV)'].mean())

# 3. 线性插值(适用于随温度变化的物理量)
df['电阻率'] = df['电阻率'].interpolate(method='linear')
我的经验: 处理材料计算数据时,我一般优先用插值。因为物理量通常是连续变化的,插值比简单填充更合理。但如果你不确定,可以先画个分布图看看数据趋势。

4.5 本章知识体系

下面这张图帮你理清Pandas处理材料数据的完整流程:

Pandas数据处理流程 数据读取 CSV / Excel / 其他 数据结构 Series / DataFrame 数据清洗 筛选 / 去重 / 排序 缺失值处理 删除 / 填充 / 插值 数据输出 CSV / Excel / 可视化 数据分析 统计 / 分组 / 聚合 数据可视化 Matplotlib / Seaborn 核心思想:读取 → 清洗 → 处理缺失 → 分析 → 可视化 每一步都可用Pandas一行代码完成

这张图展示的就是我们处理材料数据的完整链路。从读取原始数据开始,经过清洗、缺失值处理,再到分析和可视化。每一步都离不开Pandas。

给新手的建议: 别想着一次性把所有功能都学会。先掌握read_csvheadinfodropnafillna这几个最常用的,剩下的遇到问题再查。我当年就是这么过来的。

好了,这一章的内容就到这里。Pandas的核心就是让你用最少的代码,做最多的事。下一章我们会把这些技巧用在真实的材料计算数据上,到时候你就知道这些东西有多好用了。


公众号:蓝海资料掘金营,微信deep3321