Python - 数据分析三剑客之Pandas
阅读前可参考NumPy文章
https://blog.csdn.net/MinggeQingchun/article/details/148253682https://blog.csdn.net/MinggeQingchun/article/details/148253682
Pandas是Python中一个强大的开源数据分析库,专门用于处理结构化数据(如表格、时间序列等),其核心数据结构为Series(一维数组)和DataFrame(二维表格)。 它基于NumPy构建,提供高效的数据清洗、操作、聚合及可视化功能,广泛应用于数据科学领域。
Pandas官方文档:pandas documentation — pandas 2.2.3 documentation
1、核心数据结构
Series:一维带标签数组,可存储任意数据类型(数值、字符串等),索引支持自定义或自动生成
DataFrame:二维表格型结构,由多个Series组成,支持行列索引和异构数据类型(每列类型可不同),类似Excel或SQL表
2、核心功能
数据清洗:处理缺失值、去重、类型转换等
数据操作:筛选、切片、合并、分组聚合(如groupby)及透视表功能
时间序列支持:专为金融数据分析设计,提供时间索引和窗口计算
3、技术优势
高效性:基于NumPy的向量化操作,避免循环,优化内存使用
兼容性:支持多种数据格式(CSV、Excel、JSON等)的读写,并集成Matplotlib可视化
SQL-like操作:支持类似SQL的join和复杂查询,简化数据分析流程
4、Pandas 适用场景
-
数据清洗(处理缺失值、异常值、重复数据)
-
数据分析(统计、聚合、可视化前处理)
-
机器学习数据预处理(特征工程)
-
金融、科研、商业数据分析
Pandas 通常与 NumPy(数值计算)、Matplotlib/Seaborn(可视化)、Scikit-learn(机器学习) 结合使用,是 Python 数据科学生态的核心工具之一。
一、Series
Series
是 Pandas 中最基本的一维数据结构(类似带标签的数组),可以存储整数、浮点数、字符串、Python对象等类型的数据
Series:一维带标签数组,可存储任意数据类型(数值、字符串等),索引支持自定义或自动生成,由下面2个部分组成:
- values:一组数据(ndarray类型)
- index:相关的数据索引标签
1、创建 Series
import pandas as pd# 从列表创建
s1 = pd.Series([1, 3, 5, 7, 9]) # 从字典创建(键自动变成索引)
s2 = pd.Series({"A": 10, "B": 20, "C": 30})# 指定索引和数据类型
s3 = pd.Series([1.1, 2.2, 3.3], index=["X", "Y", "Z"], dtype="float64")
输出示例:
s1:
0 1
1 3
2 5
3 7
4 9
dtype: int64s2:
A 10
B 20
C 30
dtype: int64
2、访问数据
按索引标签或位置
# 按标签
s2["A"] # 返回 10# 按位置(从0开始)
s2[1] # 返回 20# 切片(类似列表)
s1[1:4] # 返回第2~4个元素
布尔索引(条件筛选)
s = pd.Series([10, 20, 30, 40], index=["a", "b", "c", "d"])
s[s > 20] # 返回大于20的值
输出:
c 30
d 40
dtype: int64
3、修改数据
# 修改单个值
s2["A"] = 99 # 批量修改
s2.replace(20, 200, inplace=True) # 把20替换成200# 增加新数据
s2["D"] = 40 # 新增索引"D",值为40
4、常用统计计算
s = pd.Series([1, 2, 3, 4, 5])s.sum() # 求和 → 15
s.mean() # 平均值 → 3.0
s.max() # 最大值 → 5
s.min() # 最小值 → 1
s.std() # 标准差 → 1.581
s.value_counts() # 统计每个值的出现次数
5、缺失值处理
s = pd.Series([1, None, 3, None, 5])s.isnull() # 返回布尔Series,标记缺失值
s.dropna() # 删除缺失值
s.fillna(0) # 用0填充缺失值
6、向量化运算(类似NumPy)
s1 = pd.Series([1, 2, 3])
s2 = pd.Series([10, 20, 30])s1 + s2 # 对应位置相加 → [11, 22, 33]
s1 * 2 # 所有元素乘以2 → [2, 4, 6]
s1 ** 2 # 平方 → [1, 4, 9]
7、索引操作
s = pd.Series([10, 20, 30], index=["A", "B", "C"])# 修改索引
s.index = ["X", "Y", "Z"]# 重置索引(变成默认0,1,2...)
s.reset_index(drop=True, inplace=True) # `drop=True` 表示丢弃原索引
8、与 DataFrame 交互
Series 可以看作 DataFrame 的一列:
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
col_a = df["A"] # 提取列"A" → 返回Series
总结
操作 | 示例 |
---|---|
创建 | pd.Series([1, 2, 3]) |
访问数据 | s[0] 或 s["A"] |
条件筛选 | s[s > 2] |
修改数据 | s["A"] = 10 |
统计计算 | s.mean() |
缺失值处理 | s.fillna(0) |
向量化运算 | s1 + s2 |
Series 是 Pandas 的基础,熟练掌握后能更高效地处理 DataFrame!
二、DataFrame
DataFrame
是 Pandas 最核心的二维数据结构(类似 Excel 表格或 SQL 表),由行(index)和列(columns)组成,每列可以是不同数据类型。
行索引:index
列索引:columns
值:values(NumPy的二维数组)
(一)DataFrame基本操作
1、创建 DataFrame
import pandas as pd# 从字典创建(键是列名,值是数据)
data = {"姓名": ["张三", "李四", "王五"],"年龄": [25, 30, 28],"城市": ["北京", "上海", "广州"]}
df = pd.DataFrame(data)# 从列表创建(需指定列名)
data = [["张三", 25, "北京"], ["李四", 30, "上海"], ["王五", 28, "广州"]]
df = pd.DataFrame(data, columns=["姓名", "年龄", "城市"])# 指定索引
df = pd.DataFrame(data, index=["A", "B", "C"])
输出示例:
姓名 年龄 城市
A 张三 25 北京
B 李四 30 上海
C 王五 28 广州
2、查看数据
df.head(2) # 查看前2行
df.tail(1) # 查看最后1行
df.shape # 返回行数和列数 (3, 3)
df.columns # 查看列名
df.index # 查看行索引
df.info() # 查看数据类型和内存信息
df.describe() # 数值列的统计摘要(计数、均值、标准差等)
3、选择数据
选择列
df["姓名"] # 返回 Series
df[["姓名", "城市"]] # 返回多列(DataFrame)
选择行
df.loc["A"] # 按索引标签选择行(返回 Series)
df.iloc[0] # 按位置选择行(第1行)
df.loc[["A", "C"]] # 选择多行(按标签)
df.iloc[0:2] # 切片选择行(第1~2行)
条件筛选
df[df["年龄"] > 25] # 年龄大于25的行
df[(df["城市"] == "北京") | (df["年龄"] < 30)] # 复合条件
4、修改数据
修改列名
df.rename(columns={"姓名": "Name", "城市": "City"}, inplace=True)
修改值
df.loc["A", "年龄"] = 26 # 修改单个值
df["年龄"] = df["年龄"] + 1 # 整列运算
新增列
df["性别"] = ["男", "女", "男"] # 直接赋值
df["是否成年"] = df["年龄"] > 18 # 基于条件
删除列或行
df.drop("城市", axis=1, inplace=True) # 删除列
df.drop("A", axis=0, inplace=True) # 删除行
5、缺失值处理
df.isnull() # 检查缺失值
df.dropna() # 删除包含缺失值的行
df.fillna(0) # 用0填充缺失值
6、排序
df.sort_values("年龄", ascending=False) # 按年龄降序
df.sort_index(ascending=False) # 按索引降序
7、分组与聚合
df.groupby("城市")["年龄"].mean() # 按城市分组计算平均年龄
df.groupby("城市").agg({"年龄": "mean", "姓名": "count"}) # 多聚合
8、合并 DataFrame
# 纵向合并(类似 SQL UNION)
pd.concat([df1, df2], axis=0)# 横向合并(类似 SQL JOIN)
pd.merge(df1, df2, on="共同列", how="inner") # 内连接
9、保存数据
df.to_csv("data.csv", index=False) # 保存为 CSV
df.to_excel("data.xlsx", index=False) # 保存为 Excel
总结
操作 | 示例 |
---|---|
创建 | pd.DataFrame({"列名": [数据]}) |
选择列 | df["列名"] |
选择行 | df.loc["索引"] |
条件筛选 | df[df["年龄"] > 25] |
修改数据 | df.loc["A", "年龄"] = 26 |
新增列 | df["新列"] = 值 |
分组聚合 | df.groupby("城市").mean() |
保存 | df.to_csv("data.csv") |
Series 和 DataFrame 的区别
(二)缺失数据处理
1、缺失值的表示
在 Pandas 中,缺失数据主要由以下两种形式表示:
-
NaN
(Not a Number): 用于浮点数据类型 -
None
: 用于对象数据类型
import pandas as pd
import numpy as npdf = pd.DataFrame({'A': [1, 2, np.nan, 4],'B': [5, np.nan, np.nan, 8],'C': ['a', 'b', None, 'd']
})
2、检测缺失值
2.1 检查单个缺失值
pd.isna(df.loc[2, 'A']) # 检查特定位置是否为缺失值
pd.notna(df.loc[0, 'B']) # 检查特定位置是否不是缺失值
2.2 检查整个DataFrame
df.isna() # 返回布尔DataFrame,显示每个元素是否为缺失值
df.isnull() # isna()的别名,功能相同df.notna() # 返回布尔DataFrame,显示每个元素是否不是缺失值
df.notnull() # notna()的别名
2.3 统计每列的缺失值数量
df.isna().sum() # 每列缺失值计数
df.isna().mean() # 每列缺失值比例
3、删除缺失值
3.1 删除包含缺失值的行
df.dropna() # 删除任何包含缺失值的行
df.dropna(how='all') # 只删除全为缺失值的行
df.dropna(thresh=2) # 保留至少有2个非缺失值的行
3.2 删除包含缺失值的列
df.dropna(axis=1) # 删除任何包含缺失值的列
df.dropna(axis=1, how='all') # 只删除全为缺失值的列
4、填充缺失值
4.1 用固定值填充
df.fillna(0) # 用0填充所有缺失值
df.fillna({'A': 0, 'B': 1, 'C': 'unknown'}) # 不同列用不同值填充
4.2 前向填充和后向填充
df.fillna(method='ffill') # 用前一个非缺失值填充
df.fillna(method='bfill') # 用后一个非缺失值填充
df.fillna(method='ffill', limit=1) # 限制填充的连续缺失值数量
4.3 用统计值填充
df.fillna(df.mean()) # 用各列均值填充数值列
df.fillna(df.median()) # 用中位数填充
df.fillna(df.mode().iloc[0]) # 用众数填充
4.4 插值填充
df.interpolate() # 线性插值
df.interpolate(method='time') # 时间序列插值
df.interpolate(method='polynomial', order=2) # 多项式插值
5、处理缺失值的注意事项
-
数据分析前:应该先了解缺失值的比例和模式
-
删除缺失值:当缺失比例很小时适用,大量缺失时会导致信息损失
-
填充缺失值:要选择合理的方法,避免引入偏差
-
时间序列数据:通常使用插值或前向/后向填充
-
机器学习模型:有些模型可以直接处理缺失值,有些需要先处理
(三)Pandas 层次化索引(MultiIndex)
1、创建层次化索引
1、创建具有 MultiIndex 的 Series
import pandas as pd
import numpy as np# 从元组列表创建
arrays = [['北京', '北京', '上海', '上海'],['东城', '西城', '浦东', '静安']]
index = pd.MultiIndex.from_arrays(arrays, names=('城市', '区域'))
s = pd.Series([1200, 1500, 1800, 1600], index=index)# 从元组直接创建
tuples = [('北京', '东城'), ('北京', '西城'), ('上海', '浦东'), ('上海', '静安')]
index = pd.MultiIndex.from_tuples(tuples, names=['城市', '区域'])
2、创建具有 MultiIndex 的 DataFrame
# 方法1:通过set_index
data = {'城市': ['北京', '北京', '上海', '上海'],'区域': ['东城', '西城', '浦东', '静安'],'房价': [1200, 1500, 1800, 1600],'租金': [60, 75, 90, 80]
}
df = pd.DataFrame(data).set_index(['城市', '区域'])# 方法2:直接创建MultiIndex
index = pd.MultiIndex.from_product([['北京', '上海'], ['东城', '西城', '浦东', '静安']],names=['城市', '区域'])
df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['房价', '租金'])
2、索引操作
1、选择数据
# 选择一级索引
df.loc['北京'] # 选择北京所有区域数据# 选择多级索引
df.loc[('北京', '东城')] # 选择北京东城数据
df.loc[[('北京', '东城'), ('上海', '浦东')]] # 选择多个组合# 使用xs方法跨级选择
df.xs('东城', level='区域') # 选择所有城市的东城区
2、部分索引
# 使用slice(None)选择部分索引
df.loc[('北京', slice(None)), :] # 北京所有区域
df.loc[(slice(None), '东城'), :] # 所有城市的东城区
三、聚合(Aggregation),级联(Concatenation)函数
在Pandas中,使用聚合(Aggregation)和级联(Chaining)函数操作是处理和分析数据帧(DataFrame)的常见方法。这些操作可以帮助你从数据中提取有用的信息、执行计算并生成新的数据集。
(一)聚合操作(Aggregation)
聚合操作通常用于将数据分组后对每个组进行计算。这可以通过groupby()
方法实现,然后使用agg()
或aggregate()
方法进行聚合计算。
常用的聚合函数包括:
-
sum()
– 求和 -
mean()
– 均值 -
max()
/min()
– 最大值 / 最小值 -
count()
– 计数 -
std()
– 标准差 -
agg()
– 自定义聚合(可同时计算多个统计量)
(1)基本聚合操作
import pandas as pd# 示例 DataFrame
df = pd.DataFrame({'Category': ['A', 'B', 'A', 'B', 'A'],'Value': [10, 20, 30, 40, 50]
})# 按 'Category' 分组并计算均值
grouped = df.groupby('Category').mean()
print(grouped)输出:
Category Value
A 30
B 30
(2)agg()
多聚合计算
# 同时计算多个统计量
result = df.groupby('Category').agg({'Value': ['sum', 'mean', 'max']
})
print(result)输出:
Category sum mean max
A 90 30 50
B 60 30 40
(3)apply()
自定义聚合
# 自定义聚合函数
def custom_agg(x):return x.max() - x.min()result = df.groupby('Category')['Value'].apply(custom_agg)
print(result)输出:
Category
A 40
B 20
Name: Value, dtype: int64
(二)级联函数操作(Chaining)
级联是指将多个 DataFrame 或 Series 沿某个轴(行或列)拼接在一起。主要使用:
-
pd.concat()
– 通用拼接 -
append()
– 追加行(已弃用,推荐用concat
)
(1)pd.concat()
基本使用
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})# 默认按行(axis=0)拼接
result = pd.concat([df1, df2])
print(result)输出:A B
0 1 3
1 2 4
0 5 7
1 6 8
(2)按列拼接(axis=1
)
result = pd.concat([df1, df2], axis=1)
print(result)输出:A B A B
0 1 3 5 7
1 2 4 6 8
(3)ignore_index=True
重置索引
result = pd.concat([df1, df2], ignore_index=True)
print(result)输出:A B
0 1 3
1 2 4
2 5 7
3 6 8
(4)append()
(不推荐,建议用 concat
)
# 追加行(已弃用,推荐用 concat)
result = df1.append(df2, ignore_index=True)
print(result)
(三)聚合 vs. 级联对比
操作 | 主要函数 | 用途 |
---|---|---|
聚合 | groupby() , agg() , sum() , mean() | 数据分组计算统计量 |
级联 | pd.concat() , append() | 合并多个 DataFrame |
总结
操作 | 适用场景 | 关键函数 |
---|---|---|
聚合 | 分组计算统计量 | groupby() , agg() , sum() , mean() |
级联 | 合并多个 DataFrame | pd.concat() , append() (不推荐) |
四、Pandas画图
在 Pandas 中,可以直接使用 DataFrame.plot()
和 Series.plot()
进行数据可视化,底层基于 Matplotlib,但语法更简洁。
1、基本绘图方法
Pandas 支持多种图表类型,通过 kind
参数指定:
-
line
– 折线图(默认) -
bar
/barh
– 柱状图 / 横向柱状图 -
hist
– 直方图 -
box
– 箱线图 -
pie
– 饼图 -
scatter
– 散点图 -
area
– 面积图
如:DataFrame
import pandas as pd
import numpy as npdf = pd.DataFrame({'A': np.random.rand(10),'B': np.random.rand(10),'C': np.random.rand(10)
}, index=pd.date_range('2023-01-01', periods=10))
2、常见图表
(1) 折线图(kind='line'
)
df.plot(kind='line', title='Line Plot', figsize=(8, 4))
(2) 柱状图(kind='bar'
)
df.head(5).plot(kind='bar', title='Bar Plot', figsize=(8, 4))
(3) 横向柱状图(kind='barh'
)
df.head(3).plot(kind='barh', title='Horizontal Bar Plot')
(4) 直方图(kind='hist'
)
df['A'].plot(kind='hist', bins=5, title='Histogram')
(5) 箱线图(kind='box'
)
df.plot(kind='box', title='Box Plot')
(6) 饼图(kind='pie'
)
df['A'].head(5).plot(kind='pie', autopct='%.1f%%', title='Pie Chart')
(7) 散点图(kind='scatter'
)
df.plot(kind='scatter', x='A', y='B', title='Scatter Plot')
3、自定义图表样式
(1) 调整大小、颜色、标题
df.plot(kind='line',figsize=(10, 5),title='Customized Plot',color=['red', 'green', 'blue'],linewidth=2,alpha=0.7 # 透明度
)
(2) 添加网格、图例、坐标轴标签
ax = df.plot(kind='bar')
ax.grid(True, linestyle='--') # 网格线
ax.set_xlabel('Date') # X轴标签
ax.set_ylabel('Value') # Y轴标签
ax.legend(loc='upper right') # 图例位置
(3) 子图(多个图表并列)
df.plot(kind='line',subplots=True, # 每个列一个子图layout=(2, 2), # 2行2列figsize=(10, 8)
)
4、直接使用 Matplotlib 增强功能
Pandas 绘图返回的是 Matplotlib 的 Axes
对象,可以进一步自定义:
import matplotlib.pyplot as pltax = df.plot(kind='bar')
ax.set_title('Enhanced Plot')
plt.xticks(rotation=45) # 旋转X轴标签
plt.tight_layout() # 自动调整布局
plt.show()
5、保存图表
ax = df.plot(kind='line')
ax.figure.savefig('plot.png', dpi=300, bbox_inches='tight') # 保存为PNG
总结
功能 | 方法 | 示例 |
---|---|---|
折线图 | df.plot(kind='line') | 趋势分析 |
柱状图 | df.plot(kind='bar') | 分类对比 |
直方图 | df['col'].plot(kind='hist') | 分布查看 |
箱线图 | df.plot(kind='box') | 离群值检测 |
饼图 | df['col'].plot(kind='pie') | 占比分析 |
散点图 | df.plot(kind='scatter', x='A', y='B') | 相关性分析 |
保存图表 | ax.figure.savefig('file.png') | 导出图片 |
Pandas 绘图适合快速探索数据,如需更复杂可视化,可结合 Matplotlib 或 Seaborn!