Pandas入门:Series、DataFrame、文件读取与缺失值处理
做数据分析绕不开 Pandas,这玩意儿说白了就是 Python 里的 Excel 增强版。我刚接触时觉得它不就一个表格库么?后来在项目中处理百万行日志,才知道没有 Pandas 我连数据都打不开。
这一章我们集中攻克四个核心:
- 两种基本结构 —— Series 和 DataFrame
- 从 CSV / Excel 把数据拽进来
- 处理最头疼的缺失值
1. Series 与 DataFrame:两种武器
Series 是一维的,就像 Excel 里的一列(带行号)。DataFrame 是二维的,像一张完整的表。
直接看代码:
import pandas as pd
# 创建 Series
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s)
# a 10
# b 20
# c 30
# d 40
# dtype: int64
Series 的索引可以自定义,不一定是连续整数。我自己在项目中经常用它来存时间序列的一列数据,比如某个传感器的每小时读数。
DataFrame 更常用:
data = {
'城市': ['北京', '上海', '广州', '深圳'],
'温度': [12, 15, 20, 22],
'湿度': [60, 70, 80, 75]
}
df = pd.DataFrame(data)
print(df)
# 城市 温度 湿度
# 0 北京 12 60
# 1 上海 15 70
# 2 广州 20 80
# 3 深圳 22 75
嗯,这里要注意:DataFrame 的列名来自字典的 key,行索引默认从 0 开始。
我整理了一张对比表,方便你快速区分:
| 特性 | Series | DataFrame |
|---|---|---|
| 维度 | 一维 | 二维 |
| 数据结构 | 带标签的数组 | 带标签的表格(多列 Series) |
| 索引方式 | loc 按标签,iloc 按位置 | loc 按行列标签,iloc 按行列位置 |
| 常见创建 | pd.Series(list, index=) | pd.DataFrame(dict) 或读取文件 |
| 典型用途 | 单列数据 + 统计分析 | 多列关联数据 + 清洗建模 |
有个实用技巧:DataFrame 里每一列其实都是一个 Series。你取 df['温度'] 得到的就是 Series,可以继续用 Series 的方法。
2. 读取 CSV / Excel:数据入口
现实中的数据很少是靠手动敲字典创建的,更多是从文件读入。Pandas 的 read_csv 和 read_excel 就是大门。
先看 CSV:
# 最简单的读取
df = pd.read_csv('data.csv')
print(df.head()) # 默认前5行
# 如果文件没有列名(header=None)
df = pd.read_csv('data.csv', header=None)
# 指定分隔符为制表符
df = pd.read_csv('data.tsv', sep='\t')
# 只读取前100行,适合大文件测试
df = pd.read_csv('big.csv', nrows=100)
我记得刚入行时,遇到一个 CSV 文件里面有几万行乱码,就是因为编码问题。后来我养成习惯:
# 遇到中文文件,指定 encoding='utf-8' 或 'gbk'
df = pd.read_csv('数据.csv', encoding='gbk')
读取 Excel 文件要复杂一丢丢,需要安装 openpyxl 或 xlrd:
# 默认读取第一个 sheet
df = pd.read_excel('报表.xlsx')
# 指定 sheet 名
df = pd.read_excel('报表.xlsx', sheet_name='销售数据')
# 跳过前2行,从第3行开始读(表头在第3行)
df = pd.read_excel('报表.xlsx', header=2)
读取后第一件事是什么?我的流程是这样:
- df.info() —— 看列名、非空数量、数据类型
- df.describe() —— 数值列的统计摘要
- df.isnull().sum() —— 查缺失值情况
你想想看,这三个命令下来,数据长什么样基本心里有数了。
3. 缺失值处理:数据清洗必修课
现实数据几乎没有干干净净的。缺一个值、传个 NaN、甚至留个空字符串,都很常见。Pandas 把缺失值统一表示为 NaN(Not a Number)。
怎么发现缺失值?
# 布尔型缺失掩码
df.isna() # 或 df.isnull()
# 每列缺失数量
df.isnull().sum()
# 有缺失的行
df[df.isnull().any(axis=1)]
处理缺失值通常有两种思路:删掉 或 填充。
3.1 删除缺失行/列
# 删除包含任何缺失值的行
df_clean = df.dropna()
# 只在某列缺失时才删(比如 '价格' 列)
df_clean = df.dropna(subset=['价格'])
# 删除全部是缺失值的行
df_clean = df.dropna(how='all')
# 删除列:缺失比例超过 50% 的列
df_clean = df.dropna(thresh=len(df)*0.5, axis=1)
3.2 填充缺失值
# 用固定值填充
df['温度'].fillna(0, inplace=True)
# 用列平均值填充
df['温度'].fillna(df['温度'].mean(), inplace=True)
# 用前一个有效值填充(适用于时间序列)
df['温度'].fillna(method='ffill', inplace=True)
# 用后一个有效值填充
df['温度'].fillna(method='bfill', inplace=True)
为什么用平均值?对于正态分布的数值数据,平均值是合理的猜测。但如果数据有离群点,用中位数更稳健:
df['收入'].fillna(df['收入'].median(), inplace=True)
类别数据则用众数填充:
df['城市'].fillna(df['城市'].mode()[0], inplace=True)
讲真,有一次我忘了 inplace=True,跑完代码发现 DataFrame 没变,闹了个小乌龙。现在写 fillna 我都习惯先赋值或加 inplace。
1. 金额列:用同产品的平均金额填充
2. 客户名列:缺失比例低就删行,高则统一填 "未知客户"
3. 日期列(如果有缺失):直接删行,因为日期不可推断
小结
这一章我们走了三个台阶:先认识 Series 和 DataFrame,再学会从 CSV/Excel 读取数据,最后处理缺失值。这三步是任何数据分析流程的前置动作,练熟了后面画图建模才不卡壳。
我自己初期在缺失值处理上栽过跟头,比如用 fillna 后没检查是否真的填充成功。推荐你们每次填充后都跑一次 df.isnull().sum() 确认一下。嗯,今天就到这,动手敲吧。