Python九阳神功之柒:数据分析三剑客·执剑问道

前言
上一篇我们打通了数据存储与缓存 的任督二脉,本篇正式进入数据分析与可视化的核心领域。NumPy 提供高效的数值计算引擎,Pandas 承载灵活的数据清洗与变换,Matplotlib 赋予数据直观的表达能力------三者环环相扣,构成 Python 数据分析的完整闭环。
一、三剑客概览
| 库 | 定位 | 核心数据结构 |
|---|---|---|
| NumPy | 数值计算底座 | ndarray(多维数组) |
| Pandas | 数据处理与分析 | Series(一维)、DataFrame(二维) |
| Matplotlib | 数据可视化 | Figure、Axes |
层次关系:
- NumPy 是基础层:提供高效数组对象,是 Pandas 和 Matplotlib 的底层依赖
- Pandas 是处理层:基于 NumPy 构建,专注于数据清洗、整理和分析
- Matplotlib 是可视化层:依赖 NumPy,能直接处理 Pandas 数据对象
python
# 标准工作流
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# NumPy:生成数据
data = np.random.randn(100, 3)
# Pandas:整理分析
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
# Matplotlib:可视化
df.plot(kind='hist', alpha=0.5)
plt.show()
二、NumPy --- 数值计算之基
2.1 安装与导入
bash
pip install numpy
python
import numpy as np
2.2 ndarray:核心数据结构
创建方式
python
# 从列表创建
arr1 = np.array([1, 2, 3, 4, 5]) # 一维
arr2 = np.array([[1, 2, 3], [4, 5, 6]]) # 二维
# 特殊数组
zeros = np.zeros((3, 4)) # 全0
ones = np.ones((2, 3)) # 全1
eye = np.eye(3) # 单位矩阵
# 序列数组
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace_arr = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1]
# 随机数组
rand_arr = np.random.rand(3, 3) # 均匀分布 [0,1)
normal_arr = np.random.randn(3, 3) # 标准正态分布
randint_arr = np.random.randint(0, 10, (3, 3)) # 随机整数
核心属性
python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.ndim) # 2 维度数
print(arr.shape) # (2, 3) 形状
print(arr.size) # 6 元素总数
print(arr.dtype) # int64 元素类型
2.3 索引与切片
python
arr = np.array([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]
])
# 取行
arr[0] # 第一行
arr[-1] # 最后一行
arr[:2] # 前两行
# 取列(注意逗号)
arr[:, 1] # 第二列
arr[:, -2:] # 后两列
# 取元素
arr[1, 2] # 第2行第3列 → 8
# 切片:行起始:结束:步长, 列起始:结束:步长
arr[:2, :2] # 前两行前两列
arr[::2, ::2] # 隔行隔列取
# 布尔索引
arr[arr > 10] # 筛选大于10的元素 → 一维数组
2.4 形状操作
python
arr = np.array([[1, 2, 3], [4, 5, 6]])
arr.T # 转置(行变列、列变行)
arr.reshape(3, 2) # 重塑形状(元素总数不变)
arr.flatten() # 展平为一维
np.resize(arr, (2, 4)) # 调整大小(可增减元素)
2.5 数学运算
算术运算(逐元素)
python
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
a + b # [6, 8, 10, 12]
a - b # [-4, -4, -4, -4]
a * b # [5, 12, 21, 32]
a / b # [0.2, 0.333, 0.428, 0.5]
a ** 2 # [1, 4, 9, 16]
矩阵乘法(点积)
python
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 两种写法等价
A @ B
np.dot(A, B)
# [[19, 22], [43, 50]]
统计运算
| 函数 | 说明 | 按维度 |
|---|---|---|
np.sum() |
求和 | axis=0列方向,axis=1行方向 |
np.mean() |
均值 | 同上 |
np.std() |
标准差 | 同上 |
np.var() |
方差 | 同上 |
np.max() / np.min() |
最大/最小值 | 同上 |
np.argmax() / np.argmin() |
最大/最小值索引 | 同上 |
python
arr = np.array([[1, 2, 3], [4, 5, 6]])
np.sum(arr) # 21 全部求和
np.sum(arr, axis=0) # [5, 7, 9] 按列求和
np.sum(arr, axis=1) # [6, 15] 按行求和
np.mean(arr, axis=0) # [2.5, 3.5, 4.5]
2.6 广播机制(重要)
广播规则 :不同形状的数组做逐元素运算时,从最后一维开始向前依次对比,满足以下二者之一即可匹配:
- 两个维度大小相等
- 其中一个维度等于 1
python
# 形状 (3, 4) 与 (4,) → 可广播
arr = np.arange(12).reshape(3, 4) # (3, 4)
vec = np.array([1, 2, 3, 4]) # (4,)
arr + vec # 每行加 vec
# 形状 (3, 4) 与 (3, 1) → 可广播
vec2 = np.array([[1], [2], [3]]) # (3, 1)
arr + vec2 # 每列加 vec2
# 形状 (3, 4) 与 (4, 3) → 不可广播(最后一维 4 vs 3)
三、Pandas --- 数据处理之器
3.1 安装与导入
bash
pip install pandas
python
import pandas as pd
3.2 Series:一维带标签数组
python
# 从列表创建(索引自动为 0, 1, 2...)
s1 = pd.Series([10, 20, 30, 40])
# 0 10
# 1 20
# 2 30
# 3 40
# 从字典创建(索引为字典 key)
s2 = pd.Series({'name': '老高', 'age': 36, 'city': '北京'})
# 核心属性
s1.values # 底层 numpy 数组
s1.index # 索引对象
s1.shape # (4,)
s1.dtype # 数据类型
3.3 DataFrame:二维表格
创建方式
python
# 方式1:字典(每个 key 为一列)
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 35],
'工资': [5000, 7000, 6000]
}
df = pd.DataFrame(data)
# 方式2:列表(每行为一条记录)
data = [
['张三', 25, 5000],
['李四', 30, 7000],
['王五', 35, 6000]
]
df = pd.DataFrame(data, columns=['姓名', '年龄', '工资'])
# 指定索引
df = pd.DataFrame(data, columns=['姓名', '年龄', '工资'], index=['a', 'b', 'c'])
核心属性
python
df.shape # (行数, 列数)
df.index # 行索引
df.columns # 列索引
df.dtypes # 每列数据类型
df.info() # 信息概览
3.4 数据查看与选择
python
df.head(3) # 前3行
df.tail(2) # 后2行
df.describe() # 数值列统计(均值、最值、标准差等)
# 选择列(注意双括号)
df['姓名'] # 单列 → Series
df[['姓名', '年龄']] # 多列 → DataFrame
# 按标签选择(loc,包左包右)
df.loc['a'] # 单行
df.loc[['a', 'c']] # 多行
df.loc['a':'c'] # 切片
# 按位置选择(iloc,包左不包右)
df.iloc[0] # 第一行
df.iloc[[0, 2]] # 第一、三行
df.iloc[0:2] # 前两行
3.5 数据筛选与过滤
python
# 单条件
df[df['工资'] > 6000]
# 多条件(必须用 & 代替 and,且每个条件加括号)
df[(df['工资'] > 5000) & (df['年龄'] < 35)]
# query 写法(更简洁)
df.query('工资 > 5000 and 年龄 < 35')
3.6 排序
python
# 单字段
df.sort_values('工资') # 升序(默认)
df.sort_values('工资', ascending=False) # 降序
# 多字段
df.sort_values(['工资', '年龄'], ascending=[False, True])
3.7 数据清洗
读取 CSV
python
df = pd.read_csv(
'data.csv',
sep=',', # 分隔符
encoding='utf-8', # 编码
header=0, # 第0行作为列名
usecols=['name', 'age'], # 只读指定列
na_values=['NA', '-'] # 将指定值识别为 NaN
)
缺失值处理
python
# 统计缺失值
df.isnull().sum() # 每列缺失数量
df.notnull().sum() # 每列非缺失数量
# 删除
df.dropna() # 删除含缺失值的行
df.dropna(how='all') # 删除全为缺失值的行
# 填充
df.fillna(0) # 填充0
df.fillna(df.mean()) # 填充该列均值
df.fillna(df['col'].median()) # 填充中位数
# 填充特定列
df['col'] = df['col'].fillna(df['col'].mean())
3.8 分组聚合(GroupBy)
python
# 单字段分组,单聚合
df.groupby('地区')['销售额'].sum()
# 多聚合
df.groupby('地区')['销售额'].agg(['sum', 'mean', 'count', 'max', 'min'])
# 多字段分组
df.groupby(['地区', '产品'])['销售额'].agg(['sum', 'mean'])
3.9 数据透视表(Pivot Table)
python
# Excel 透视表风格
pd.pivot_table(
data=df,
index='地区', # 行维度
columns='产品', # 列维度
values='销售额', # 统计值
aggfunc='sum', # 聚合方式
fill_value=0, # 缺失值填充
margins=True # 合计行列
)
四、Matplotlib --- 数据可视化之镜
4.1 安装与导入
bash
pip install matplotlib
python
import matplotlib.pyplot as plt
import matplotlib
# 设置后端(新版本需要)
matplotlib.use('TkAgg')
# 中文显示设置
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows
# plt.rcParams['font.sans-serif'] = ['PingFang SC'] # Mac
plt.rcParams['axes.unicode_minus'] = False
4.2 图表类型速查
| 图表 | 函数 | 适用场景 |
|---|---|---|
| 折线图 | plt.plot() |
趋势变化 |
| 柱状图 | plt.bar() |
类别对比 |
| 散点图 | plt.scatter() |
相关性分析 |
| 饼图 | plt.pie() |
占比分布 |
| 直方图 | plt.hist() |
数据分布 |
4.3 基础绘图
python
# 准备数据
x = [1, 2, 3, 4, 5]
y = [100, 200, 60, 80, 190]
# 折线图
plt.plot(x, y, color='blue', marker='o', linestyle='-', linewidth=2, label='体重')
# 柱状图
plt.bar(x, y, color='skyblue')
# 散点图
plt.scatter(x, y, color='red', s=50)
# 饼图
plt.pie([15, 34, 6, 9], labels=['大专', '本科', '硕士', '博士'], autopct='%.0f%%')
# 通用设置
plt.xlabel('月份')
plt.ylabel('体重/kg')
plt.title('体重变化图')
plt.grid(True) # 网格
plt.legend() # 图例
plt.savefig('chart.png', dpi=300) # 保存(在 show 之前)
plt.show()
4.4 多子图
python
x = [1, 2, 3, 4, 5]
y1 = [10, 16, 13, 20, 18]
y2 = [8, 12, 15, 11, 17]
# 2行2列,第1个子图
plt.subplot(2, 2, 1)
plt.plot(x, y1)
plt.title('折线图')
# 第2个子图
plt.subplot(2, 2, 2)
plt.bar(x, y2)
plt.title('柱状图')
plt.tight_layout() # 自动调整间距
plt.show()
五、综合实战:中美日 GDP 趋势分析
python
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 读取数据
df = pd.read_csv('1960-2019全球GDP数据.csv', encoding='gbk')
# 2. 数据清洗
df.dropna(inplace=True)
# 3. 提取三国数据
df_cn = df[df['country'] == '中国'].copy()
df_us = df[df['country'] == '美国'].copy()
df_jp = df[df['country'] == '日本'].copy()
# 4. 设置年份为索引
df_cn.set_index('year', inplace=True)
df_us.set_index('year', inplace=True)
df_jp.set_index('year', inplace=True)
# 5. 重命名列
df_cn.rename(columns={'GDP': '中国'}, inplace=True)
df_us.rename(columns={'GDP': '美国'}, inplace=True)
df_jp.rename(columns={'GDP': '日本'}, inplace=True)
# 6. 可视化
plt.figure(figsize=(12, 6))
plt.plot(df_cn.index, df_cn['中国'], label='中国', color='red', linewidth=2)
plt.plot(df_us.index, df_us['美国'], label='美国', color='green', linewidth=2)
plt.plot(df_jp.index, df_jp['日本'], label='日本', color='blue', linewidth=2)
plt.title('1960-2019年中美日GDP趋势对比', fontsize=16)
plt.xlabel('年份')
plt.ylabel('GDP(万亿美元)')
plt.legend()
plt.grid(alpha=0.3)
plt.savefig('中美日GDP对比.png', dpi=300)
plt.show()
总结
| 库 | 核心能力 | 关键方法 |
|---|---|---|
| NumPy | 多维数组运算、广播、统计 | array(), reshape(), sum(), mean(), @ |
| Pandas | 数据清洗、分组聚合、透视 | read_csv(), groupby(), pivot_table(), fillna() |
| Matplotlib | 图表绘制、多子图 | plot(), bar(), scatter(), pie(), subplot() |
一条主线贯穿全文:从「NumPy 生成与计算」到「Pandas 清洗与聚合」,再到「Matplotlib 可视化呈现」------ 这是数据分析从原始数据到洞察结论的完整链路。